diff --git a/ReqIFSharp.Tests/AdditionalCoverage/AdditionalCoverageTestFixture.cs b/ReqIFSharp.Tests/AdditionalCoverage/AdditionalCoverageTestFixture.cs new file mode 100644 index 0000000..218a61a --- /dev/null +++ b/ReqIFSharp.Tests/AdditionalCoverage/AdditionalCoverageTestFixture.cs @@ -0,0 +1,269 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright 2017-2025 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ------------------------------------------------------------------------------------------------- + +namespace ReqIFSharp.Tests.AdditionalCoverage +{ + using System; + using System.IO; + using System.Linq; + using System.Text; + using System.Threading; + using System.Threading.Tasks; + using System.Xml; + + using NUnit.Framework; + + using ReqIFSharp; + + /// + /// Additional tests that exercise asynchronous and fallback behaviour in several core classes. + /// + [TestFixture] + public class AdditionalCoverageTestFixture + { + [Test] + public void RelationGroup_ReadXml_CreatesFallbacksForMissingReferences() + { + var content = new ReqIFContent(); + var relationGroupType = new RelationGroupType(content, null) { Identifier = "rgt" }; + + var existingSpecification = new Specification(content, null) + { + Identifier = "existing-spec" + }; + + var existingRelation = new SpecRelation(content, null) + { + Identifier = "existing-rel" + }; + + var relationGroup = new RelationGroup(content, null) + { + Identifier = "rg", + LastChange = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Utc) + }; + + var xml = $@" + + {relationGroupType.Identifier} + + + missing-spec + + + {existingSpecification.Identifier} + + + {existingRelation.Identifier} + missing-rel + +"; + + using var reader = XmlReader.Create(new StringReader(xml)); + reader.MoveToContent(); + + relationGroup.ReadXml(reader); + + Assert.Multiple(() => + { + Assert.That(relationGroup.IsEditable, Is.True, "IS-EDITABLE attribute should enable editing"); + Assert.That(relationGroup.Type, Is.SameAs(relationGroupType)); + Assert.That(relationGroup.SourceSpecification, Is.Not.Null, "Fallback specification should be created"); + Assert.That(relationGroup.SourceSpecification.Identifier, Is.EqualTo("missing-spec")); + Assert.That(relationGroup.TargetSpecification, Is.SameAs(existingSpecification)); + Assert.That(relationGroup.SpecRelations.Count, Is.EqualTo(2)); + Assert.That(relationGroup.SpecRelations.SingleOrDefault(x => ReferenceEquals(x, existingRelation)), Is.Not.Null); + Assert.That(relationGroup.SpecRelations.Any(x => x.Identifier == "missing-rel" && x.Description != null), Is.True); + }); + } + + [Test] + public async Task RelationGroup_ReadXmlAsync_CreatesFallbacksForMissingReferences() + { + var content = new ReqIFContent(); + _ = new RelationGroupType(content, null) { Identifier = "rgt" }; + _ = new Specification(content, null) { Identifier = "existing-spec" }; + _ = new SpecRelation(content, null) { Identifier = "existing-rel" }; + + var relationGroup = new RelationGroup(content, null) { Identifier = "rg" }; + + var xml = "rgt" + + "missing-spec" + + "existing-spec" + + "existing-rel" + + "missing-rel"; + + using var reader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { Async = true }); + await reader.MoveToContentAsync(); + + await relationGroup.ReadXmlAsync(reader, CancellationToken.None); + + Assert.That(relationGroup.SpecRelations.Count, Is.EqualTo(2)); + } + + [Test] + public async Task SpecHierarchy_ReadXmlAsync_InitialisesContainerAndChildren() + { + var content = new ReqIFContent(); + var rootSpecification = new Specification(content, null) { Identifier = "root" }; + var existingObject = new SpecObject(content, null) { Identifier = "existing-object" }; + + var hierarchy = new SpecHierarchy(rootSpecification, content, null) + { + Identifier = "hierarchy" + }; + + var xml = $@" + + missing-object + + + + + {existingObject.Identifier} + + + +"; + + using var reader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { Async = true }); + await reader.MoveToContentAsync(); + + await hierarchy.ReadXmlAsync(reader, CancellationToken.None); + + Assert.Multiple(() => + { + Assert.That(hierarchy.IsTableInternal, Is.True); + Assert.That(hierarchy.Object, Is.Null, "Missing objects should yield null reference"); + Assert.That(hierarchy.Children, Has.Count.EqualTo(1)); + Assert.That(hierarchy.Children[0].Object, Is.SameAs(existingObject)); + Assert.That(hierarchy.Children[0].Container, Is.SameAs(hierarchy)); + }); + } + + [Test] + public void ReqIF_WriteXml_AddsXhtmlNamespaceWhenDatatypePresent() + { + var reqIf = CreateReqIfDocument(); + + var builder = new StringBuilder(); + using (var writer = XmlWriter.Create(builder, new XmlWriterSettings { OmitXmlDeclaration = true })) + { + writer.WriteStartElement("REQ-IF"); + reqIf.WriteXml(writer); + writer.WriteEndElement(); + } + + var xml = builder.ToString(); + + StringAssert.Contains("xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"", xml); + StringAssert.Contains("REQ-IF-HEADER", xml); + StringAssert.Contains("TOOL-EXTENSIONS", xml); + } + + [Test] + public async Task ReqIF_ReadXmlAsync_RestoresHeaderAndToolExtensions() + { + var reqIf = CreateReqIfDocument(); + + var builder = new StringBuilder(); + using (var writer = XmlWriter.Create(builder, new XmlWriterSettings { OmitXmlDeclaration = true })) + { + writer.WriteStartElement("REQ-IF"); + reqIf.WriteXml(writer); + writer.WriteEndElement(); + } + + using var reader = XmlReader.Create(new StringReader(builder.ToString()), new XmlReaderSettings { Async = true }); + await reader.MoveToContentAsync(); + + var roundTrip = new ReqIF(); + await roundTrip.ReadXmlAsync(reader, CancellationToken.None); + + Assert.Multiple(() => + { + Assert.That(roundTrip.Lang, Is.EqualTo(reqIf.Lang)); + Assert.That(roundTrip.TheHeader.Title, Is.EqualTo(reqIf.TheHeader.Title)); + Assert.That(roundTrip.ToolExtension, Has.Count.EqualTo(1)); + Assert.That(roundTrip.CoreContent.DataTypes.Count, Is.EqualTo(2)); + }); + } + + [Test] + public void AttributeValueXhtml_ExtractsPlainTextAndDetectsExternalObjects() + { + var attributeValue = new AttributeValueXHTML(); + attributeValue.TheValue = "
plain text
"; + + var plain = attributeValue.ExtractUnformattedTextFromValue(); + + Assert.That(plain, Is.EqualTo("plain text")); + + var objects = attributeValue.ExternalObjects; + Assert.That(objects, Has.Count.EqualTo(1)); + Assert.That(objects[0].Uri, Is.EqualTo("file name.bin")); + } + + private static ReqIF CreateReqIfDocument() + { + var reqIf = new ReqIF + { + Lang = "en", + TheHeader = new ReqIFHeader + { + Identifier = "header", + Comment = "comment", + CreationTime = new DateTime(2024, 01, 01, 12, 00, 00, DateTimeKind.Utc), + RepositoryId = "repo", + ReqIFToolId = "tool", + ReqIFVersion = "1.0", + SourceToolId = "source", + Title = "title" + }, + CoreContent = new ReqIFContent() + }; + + var enumeration = new DatatypeDefinitionEnumeration(reqIf.CoreContent, null) + { + Identifier = "enum" + }; + + var enumValue = new EnumValue(enumeration, null) + { + Identifier = "enum-value" + }; + + _ = new EmbeddedValue(enumValue, null) + { + Key = 5, + OtherContent = "red" + }; + + var xhtmlDatatype = new DatatypeDefinitionXHTML(reqIf.CoreContent, null) + { + Identifier = "xhtml" + }; + + reqIf.ToolExtension.Add(new ReqIFToolExtension { InnerXml = "" }); + + return reqIf; + } + } +} diff --git a/ReqIFSharp.Tests/AdditionalCoverage/AttributeValueAdditionalCoverageTestFixture.cs b/ReqIFSharp.Tests/AdditionalCoverage/AttributeValueAdditionalCoverageTestFixture.cs new file mode 100644 index 0000000..55f89d4 --- /dev/null +++ b/ReqIFSharp.Tests/AdditionalCoverage/AttributeValueAdditionalCoverageTestFixture.cs @@ -0,0 +1,154 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright 2017-2025 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ------------------------------------------------------------------------------------------------- + +namespace ReqIFSharp.Tests.AdditionalCoverage +{ + using System.IO; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using System.Xml; + + using NUnit.Framework; + + using ReqIFSharp; + + /// + /// Additional attribute value tests that focus on asynchronous deserialisation branches. + /// + [TestFixture] + public class AttributeValueAdditionalCoverageTestFixture + { + [Test] + public async Task AttributeValueEnumeration_ReadXmlAsync_ResolvesDefinitions() + { + var content = new ReqIFContent(); + var specType = new SpecObjectType(content, null) { Identifier = "spec-type" }; + + var enumDatatype = new DatatypeDefinitionEnumeration(content, null) { Identifier = "enum-type" }; + var enumValue = new EnumValue(enumDatatype, null) { Identifier = "enum-value" }; + _ = new EmbeddedValue(enumValue, null) { Key = 1, OtherContent = "green" }; + + var attributeDefinition = new AttributeDefinitionEnumeration(specType, null) + { + Identifier = "enum-def", + Type = enumDatatype + }; + + var specObject = new SpecObject(content, null) + { + Identifier = "spec-object", + SpecType = specType + }; + + var attributeValue = new AttributeValueEnumeration(specObject, null); + + var xml = "" + + "enum-def" + + "enum-value" + + ""; + + using var reader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { Async = true }); + await reader.MoveToContentAsync(); + + await attributeValue.ReadXmlAsync(reader, CancellationToken.None); + + Assert.Multiple(() => + { + Assert.That(attributeValue.Definition, Is.SameAs(attributeDefinition)); + Assert.That(attributeValue.Values.Single(), Is.SameAs(enumValue)); + }); + } + + [Test] + public async Task AttributeValueInteger_ReadXmlAsync_ResolvesDefinitionAndValue() + { + var content = new ReqIFContent(); + var specType = new SpecObjectType(content, null) { Identifier = "spec-type" }; + + var integerDatatype = new DatatypeDefinitionInteger(content, null) { Identifier = "int-type" }; + var attributeDefinition = new AttributeDefinitionInteger(specType, null) + { + Identifier = "int-def", + Type = integerDatatype + }; + + var specObject = new SpecObject(content, null) + { + Identifier = "spec-object", + SpecType = specType + }; + + var attributeValue = new AttributeValueInteger(specObject, null); + + var xml = "" + + "int-def" + + ""; + + using var reader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { Async = true }); + await reader.MoveToContentAsync(); + + await attributeValue.ReadXmlAsync(reader, CancellationToken.None); + + Assert.Multiple(() => + { + Assert.That(attributeValue.Definition, Is.SameAs(attributeDefinition)); + Assert.That(attributeValue.TheValue, Is.EqualTo(42)); + }); + } + + [Test] + public async Task AttributeValueReal_ReadXmlAsync_ResolvesDefinition() + { + var content = new ReqIFContent(); + var specType = new SpecObjectType(content, null) { Identifier = "spec-type" }; + + var realDatatype = new DatatypeDefinitionReal(content, null) { Identifier = "real-type" }; + var attributeDefinition = new AttributeDefinitionReal(specType, null) + { + Identifier = "real-def", + Type = realDatatype + }; + + var specObject = new SpecObject(content, null) + { + Identifier = "spec-object", + SpecType = specType + }; + + var attributeValue = new AttributeValueReal(specObject, null); + + var xml = "" + + "real-def" + + ""; + + using var reader = XmlReader.Create(new StringReader(xml), new XmlReaderSettings { Async = true }); + await reader.MoveToContentAsync(); + + await attributeValue.ReadXmlAsync(reader, CancellationToken.None); + + Assert.Multiple(() => + { + Assert.That(attributeValue.Definition, Is.SameAs(attributeDefinition)); + Assert.That(attributeValue.TheValue, Is.EqualTo(4.2d)); + }); + } + } +}