Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The repository ships two NuGet packages that version independently: **ReqIFSharp
- A document without whitespace between its elements (minified XML) lost data without an error: every other header field (such as `CREATION-TIME` and `REQ-IF-TOOL-ID`) and every other enumeration value of an attribute value was skipped, and the spec relations of a relation group were not read or caused an `XmlException` ([#94](https://github.com/STARIONGROUP/ReqIFSharp/issues/94)).
- `AttributeValueXHTML.TheOriginalValue` was not read from `THE-ORIGINAL-VALUE`, so it was always `null` after reading, and a document that was read and written again lost the original values of its simplified XHTML attribute values ([#95](https://github.com/STARIONGROUP/ReqIFSharp/issues/95)).
- Attribute values did not log anything, also when an `ILoggerFactory` was passed to the deserializer: the `AttributeValue` constructors did not keep the logger factory. An enumeration attribute value no longer reports its own element and its `DEFINITION` and `VALUES` elements as not supported ([#97](https://github.com/STARIONGROUP/ReqIFSharp/issues/97)).
- `new AttributeValueXHTML(loggerFactory)` left `ExternalObjects` `null`, so `QueryExternalObjects` and `QueryBase64PayloadsAsync` of ReqIFSharp.Extensions threw for a spec element that held such a value. `new AttributeValueXHTML()` left its logger `null`, so reading into it threw ([#98](https://github.com/STARIONGROUP/ReqIFSharp/issues/98)).

## [10.1.2] - 2026-10-18

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ namespace ReqIFSharp.Extensions.Tests.ReqIFExtensions
using System.Threading;
using System.Threading.Tasks;

using Microsoft.Extensions.Logging.Abstractions;

using NUnit.Framework;

using ReqIFSharp;
Expand Down Expand Up @@ -70,6 +72,19 @@ public void Verify_that_QueryExternalObjects_returns_expected_results()
Assert.That(externalObjects.Count, Is.EqualTo(1));
}

[Test]
public async Task Verify_that_the_external_objects_of_xhtml_values_created_with_a_public_constructor_can_be_queried()
{
// GH-98: the ILoggerFactory constructor left ExternalObjects null
var specObject = new SpecObject();
specObject.Values.Add(new AttributeValueXHTML { TheValue = "<xhtml:p>text</xhtml:p>" });
specObject.Values.Add(new AttributeValueXHTML(NullLoggerFactory.Instance) { TheValue = "<xhtml:p>text</xhtml:p>" });
specObject.Values.Add(new AttributeValueXHTML(null) { TheValue = "<xhtml:p>text</xhtml:p>" });

Assert.That(specObject.QueryExternalObjects(), Is.Empty);
Assert.That(await specObject.QueryBase64PayloadsAsync(this.reqIFLoaderService), Is.Empty);
}

[Test]
public async Task Verify_that_QueryBase64Payloads_returns_expected_results()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ namespace ReqIFSharp.Tests
using System.IO;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;

using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -128,6 +129,64 @@ public void Verify_That_WriteXmlAsync_Without_Definition_Set_Throws_Serializatio
Throws.Exception.TypeOf<SerializationException>());
}

[Test]
public void Verify_that_every_public_constructor_creates_an_empty_list_of_external_objects()
{
// GH-98: the ILoggerFactory constructor left ExternalObjects null
Assert.Multiple(() =>
{
Assert.That(new AttributeValueXHTML().ExternalObjects, Is.Not.Null.And.Empty);
Assert.That(new AttributeValueXHTML(this.loggerFactory).ExternalObjects, Is.Not.Null.And.Empty);
Assert.That(new AttributeValueXHTML(null).ExternalObjects, Is.Not.Null.And.Empty);
});
}

[Test]
public async Task Verify_that_a_value_created_with_the_parameterless_constructor_can_be_read()
{
// GH-98: the parameterless constructor left the logger null, so reading threw an ArgumentNullException
const string xml = "<ATTRIBUTE-VALUE-XHTML xmlns=\"http://www.omg.org/spec/ReqIF/20110401/reqif.xsd\" IS-SIMPLIFIED=\"true\">" +
"<THE-VALUE><xhtml:p xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">text</xhtml:p></THE-VALUE>" +
"</ATTRIBUTE-VALUE-XHTML>";

foreach (var async in new[] { false, true })
{
using var xmlReader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { Async = async });
xmlReader.MoveToContent();

var attributeValueXhtml = new AttributeValueXHTML();

if (async)
{
await attributeValueXhtml.ReadXmlAsync(xmlReader, CancellationToken.None);
}
else
{
attributeValueXhtml.ReadXml(xmlReader);
}

Assert.That(attributeValueXhtml.TheValue, Does.Contain("text"), $"async: {async}");
Assert.That(attributeValueXhtml.IsSimplified, Is.True);
}
}

[Test]
public void Verify_that_ReadXmlAsync_of_a_value_created_with_the_parameterless_constructor_can_be_cancelled()
{
const string xml = "<ATTRIBUTE-VALUE-XHTML xmlns=\"http://www.omg.org/spec/ReqIF/20110401/reqif.xsd\">" +
"<THE-VALUE><xhtml:p xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">text</xhtml:p></THE-VALUE>" +
"</ATTRIBUTE-VALUE-XHTML>";

var cts = new CancellationTokenSource();
cts.Cancel();

using var xmlReader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { Async = true });
xmlReader.MoveToContent();

Assert.That(async () => await new AttributeValueXHTML().ReadXmlAsync(xmlReader, cts.Token),
Throws.Exception.InstanceOf<OperationCanceledException>());
}

[Test]
public void Verify_that_ReadXmlAsync_throws_exception_when_cancelled()
{
Expand Down
10 changes: 3 additions & 7 deletions ReqIFSharp/AttributeValue/AttributeValueXHTML.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
/// The purpose of the <see cref="AttributeValueXHTML"/> class is to define an attribute value with XHTML contents.
/// </summary>
[ReqIfClass(name: "ATTRIBUTE-VALUE-XHTML", isAbstract: false)]
public class AttributeValueXHTML : AttributeValue

Check warning on line 41 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Rename class 'AttributeValueXHTML' to match pascal case naming rules, consider using 'AttributeValueXhtml'.

Check warning on line 41 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Rename class 'AttributeValueXHTML' to match pascal case naming rules, consider using 'AttributeValueXhtml'.
{
/// <summary>
/// The <see cref="ILogger"/> used to log
Expand All @@ -50,11 +50,11 @@
/// </summary>
public AttributeValueXHTML()
{
this.ExternalObjects = new List<ExternalObject>();
this.logger = NullLogger<AttributeValueXHTML>.Instance;
}

/// <summary>
/// Initializes a new instance of the <see cref="AttributeValueString"/> class.
/// Initializes a new instance of the <see cref="AttributeValueXHTML"/> class.
/// </summary>
/// <param name="loggerFactory">
/// The (injected) <see cref="ILoggerFactory"/> used to set up logging
Expand All @@ -77,8 +77,6 @@
: base(specElAt, loggerFactory)
{
this.logger = this.loggerFactory == null ? NullLogger<AttributeValueXHTML>.Instance : this.loggerFactory.CreateLogger<AttributeValueXHTML>();

this.ExternalObjects = new List<ExternalObject>();
}

/// <summary>
Expand All @@ -96,8 +94,6 @@
{
this.logger = this.loggerFactory == null ? NullLogger<AttributeValueXHTML>.Instance : this.loggerFactory.CreateLogger<AttributeValueXHTML>();

this.ExternalObjects = new List<ExternalObject>();

this.OwningDefinition = attributeDefinition;
}

Expand Down Expand Up @@ -126,7 +122,7 @@
{
if (value == null)
{
throw new ArgumentNullException($"{nameof(value)} cannot be null.");

Check warning on line 125 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

The parameter name 'value cannot be null.' is not declared in the argument list.
}

this.TheValue = value.ToString();
Expand All @@ -136,7 +132,7 @@
/// <summary>
/// Gets the <see cref="List{ExternalObject}"/> that may be present as xhtml:object in the XHTML content
/// </summary>
public List<ExternalObject> ExternalObjects { get; private set; }
public List<ExternalObject> ExternalObjects { get; private set; } = new List<ExternalObject>();

/// <summary>
/// Gets or sets the Reference to the attribute definition that relates the value to its data type.
Expand Down Expand Up @@ -263,7 +259,7 @@

switch (subtree.LocalName)
{
case "DEFINITION":

Check warning on line 262 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Define a constant instead of using this literal 'DEFINITION' 4 times.

Check warning on line 262 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Define a constant instead of using this literal 'DEFINITION' 4 times.
using (var definitionSubtree = subtree.ReadSubtree())
{
this.ReadDefinition(definitionSubtree);
Expand All @@ -271,7 +267,7 @@

subtree.Read();
break;
case "THE-VALUE":

Check warning on line 270 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Define a constant instead of using this literal 'THE-VALUE' 4 times.

Check warning on line 270 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Define a constant instead of using this literal 'THE-VALUE' 4 times.
this.TheValue = subtree.ReadInnerXml().Trim();

if (this.TheValue.Contains("xhtml:object") && this.TheValue.Contains("data"))
Expand All @@ -281,7 +277,7 @@
}

break;
case "THE-ORIGINAL-VALUE":

Check warning on line 280 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Define a constant instead of using this literal 'THE-ORIGINAL-VALUE' 4 times.

Check warning on line 280 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Define a constant instead of using this literal 'THE-ORIGINAL-VALUE' 4 times.
this.TheOriginalValue = subtree.ReadInnerXml().Trim();
break;
default:
Expand Down Expand Up @@ -373,7 +369,7 @@
{
reader.MoveToContent();

if (reader.ReadToReqIFDescendant("ATTRIBUTE-DEFINITION-XHTML-REF", this.logger))

Check warning on line 372 in ReqIFSharp/AttributeValue/AttributeValueXHTML.cs

View workflow job for this annotation

GitHub Actions / Build

Define a constant instead of using this literal 'ATTRIBUTE-DEFINITION-XHTML-REF' 4 times.
{
this.SetDefinition(reader.ReadElementContentAsStringToEndElement());
}
Expand Down
Loading