diff --git a/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs
index 34b4840b..1fa1434c 100644
--- a/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ConjugatedPortTypingExtensionsTestFixture.cs
@@ -1,38 +1,56 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
-//
+//
// Copyright 2022-2026 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 SysML2.NET.Tests.Extend
{
using System;
-
+
using NUnit.Framework;
-
+
+ using SysML2.NET.Core.POCO.Root.Namespaces;
using SysML2.NET.Core.POCO.Systems.Ports;
+ using SysML2.NET.Extensions;
[TestFixture]
public class ConjugatedPortTypingExtensionsTestFixture
{
[Test]
- public void ComputePortDefinition_ThrowsNotSupportedException()
+ public void VerifyComputePortDefinition()
{
- Assert.That(() => ((IConjugatedPortTyping)null).ComputePortDefinition(), Throws.TypeOf());
+ Assert.That(() => ((IConjugatedPortTyping)null).ComputePortDefinition(), Throws.TypeOf());
+
+ // No ConjugatedPortDefinition -> the null-safe navigation short-circuits to null.
+ var emptyConjugatedPortTyping = new ConjugatedPortTyping();
+
+ Assert.That(emptyConjugatedPortTyping.ComputePortDefinition(), Is.Null);
+
+ // Positive case: the ConjugatedPortDefinition's originalPortDefinition derives from its
+ // owningMembership -> membershipOwningNamespace, which must be a PortDefinition. Wire that
+ // ownership chain so originalPortDefinition (and thus portDefinition) resolves to the original.
+ var originalPortDefinition = new PortDefinition();
+ var conjugatedPortDefinition = new ConjugatedPortDefinition();
+ originalPortDefinition.AssignOwnership(new OwningMembership(), conjugatedPortDefinition);
+
+ var conjugatedPortTyping = new ConjugatedPortTyping { ConjugatedPortDefinition = conjugatedPortDefinition };
+
+ Assert.That(conjugatedPortTyping.ComputePortDefinition(), Is.SameAs(originalPortDefinition));
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ControlNodeExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ControlNodeExtensionsTestFixture.cs
new file mode 100644
index 00000000..b4cf7acc
--- /dev/null
+++ b/SysML2.NET.Tests/Extend/ControlNodeExtensionsTestFixture.cs
@@ -0,0 +1,82 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2026 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 SysML2.NET.Tests.Extend
+{
+ using System;
+
+ using Moq;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.Core.POCO.Core.Types;
+ using SysML2.NET.Core.POCO.Kernel.Multiplicities;
+ using SysML2.NET.Core.POCO.Systems.Actions;
+
+ [TestFixture]
+ public class ControlNodeExtensionsTestFixture
+ {
+ [Test]
+ public void VerifyComputeMultiplicityHasBoundsOperation()
+ {
+ // ControlNode is abstract; ForkNode is a concrete IControlNode used as the subject.
+ var controlNode = new ForkNode();
+
+ Assert.That(() => ((IControlNode)null).ComputeMultiplicityHasBoundsOperation(null, 1, "1"), Throws.TypeOf());
+
+ // mult == null -> false (the OCL "mult <> null" guard, not a throw).
+ Assert.That(controlNode.ComputeMultiplicityHasBoundsOperation(null, 1, "1"), Is.False);
+
+ // mult IS a MultiplicityRange -> the direct branch delegates to HasBounds(lower, upper).
+ var range = new Mock();
+ range.Setup(x => x.HasBounds(1, "5")).Returns(true);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(controlNode.ComputeMultiplicityHasBoundsOperation(range.Object, 1, "5"), Is.True);
+
+ // Bounds that were not set up return Moq's default (false).
+ Assert.That(controlNode.ComputeMultiplicityHasBoundsOperation(range.Object, 0, "5"), Is.False);
+ }
+
+ // mult is a plain Multiplicity (NOT a MultiplicityRange) -> the supertype branch searches
+ // AllSupertypes() for a MultiplicityRange whose HasBounds(lower, upper) is true.
+ var rangeSupertype = new Mock();
+ rangeSupertype.Setup(x => x.HasBounds(1, "5")).Returns(true);
+
+ var multiplicityWithRangeSupertype = new Mock();
+ multiplicityWithRangeSupertype.Setup(x => x.AllSupertypes()).Returns([rangeSupertype.Object]);
+
+ var multiplicityWithoutRangeSupertype = new Mock();
+ multiplicityWithoutRangeSupertype.Setup(x => x.AllSupertypes()).Returns([]);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(controlNode.ComputeMultiplicityHasBoundsOperation(multiplicityWithRangeSupertype.Object, 1, "5"), Is.True);
+
+ // A matching MultiplicityRange supertype exists, but the requested bounds do not match.
+ Assert.That(controlNode.ComputeMultiplicityHasBoundsOperation(multiplicityWithRangeSupertype.Object, 0, "5"), Is.False);
+
+ // No MultiplicityRange among the supertypes -> false.
+ Assert.That(controlNode.ComputeMultiplicityHasBoundsOperation(multiplicityWithoutRangeSupertype.Object, 1, "5"), Is.False);
+ }
+ }
+ }
+}
diff --git a/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs
index 553e9ddb..b9f65d4c 100644
--- a/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/FeatureTypingExtensionsTestFixture.cs
@@ -1,38 +1,57 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
-//
+//
// Copyright 2022-2026 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 SysML2.NET.Tests.Extend
{
using System;
-
+
using NUnit.Framework;
-
+
using SysML2.NET.Core.POCO.Core.Features;
+ using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Core.POCO.Root.Namespaces;
[TestFixture]
public class FeatureTypingExtensionsTestFixture
{
[Test]
- public void ComputeOwningFeature_ThrowsNotSupportedException()
+ public void VerifyComputeOwningFeature()
{
- Assert.That(() => ((IFeatureTyping)null).ComputeOwningFeature(), Throws.TypeOf());
+ Assert.That(() => ((IFeatureTyping)null).ComputeOwningFeature(), Throws.TypeOf());
+
+ var featureTyping = new FeatureTyping();
+
+ Assert.That(featureTyping.ComputeOwningFeature(), Is.Null);
+
+ var feature = new Feature();
+
+ ((IContainedRelationship)featureTyping).OwningRelatedElement = feature;
+
+ Assert.That(featureTyping.ComputeOwningFeature(), Is.SameAs(feature));
+
+ var namespaceOwner = new Namespace();
+ var nonFeatureFeatureTyping = new FeatureTyping();
+
+ ((IContainedRelationship)nonFeatureFeatureTyping).OwningRelatedElement = namespaceOwner;
+
+ Assert.That(nonFeatureFeatureTyping.ComputeOwningFeature(), Is.Null);
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ReturnParameterMembershipExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ReturnParameterMembershipExtensionsTestFixture.cs
new file mode 100644
index 00000000..142328ab
--- /dev/null
+++ b/SysML2.NET.Tests/Extend/ReturnParameterMembershipExtensionsTestFixture.cs
@@ -0,0 +1,43 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2026 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 SysML2.NET.Tests.Extend
+{
+ using System;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.Core.Core.Types;
+ using SysML2.NET.Core.POCO.Kernel.Functions;
+
+ [TestFixture]
+ public class ReturnParameterMembershipExtensionsTestFixture
+ {
+ [Test]
+ public void VerifyComputeRedefinedParameterDirectionOperation()
+ {
+ Assert.That(() => ((IReturnParameterMembership)null).ComputeRedefinedParameterDirectionOperation(), Throws.TypeOf());
+
+ var returnParameterMembership = new ReturnParameterMembership();
+
+ Assert.That(returnParameterMembership.ComputeRedefinedParameterDirectionOperation(), Is.EqualTo(FeatureDirectionKind.Out));
+ }
+ }
+}
diff --git a/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs b/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs
index 807119a3..af5aff1b 100644
--- a/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs
+++ b/SysML2.NET/Extend/ConjugatedPortTypingExtensions.cs
@@ -50,10 +50,11 @@ internal static class ConjugatedPortTypingExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IPortDefinition ComputePortDefinition(this IConjugatedPortTyping conjugatedPortTypingSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return conjugatedPortTypingSubject == null
+ ? throw new ArgumentNullException(nameof(conjugatedPortTypingSubject))
+ : conjugatedPortTypingSubject.ConjugatedPortDefinition?.originalPortDefinition;
}
}
diff --git a/SysML2.NET/Extend/ControlNodeExtensions.cs b/SysML2.NET/Extend/ControlNodeExtensions.cs
index 910f14f3..82604e14 100644
--- a/SysML2.NET/Extend/ControlNodeExtensions.cs
+++ b/SysML2.NET/Extend/ControlNodeExtensions.cs
@@ -22,10 +22,12 @@ namespace SysML2.NET.Core.POCO.Systems.Actions
{
using System;
using System.Collections.Generic;
+ using System.Linq;
using SysML2.NET.Core.Core.Types;
using SysML2.NET.Core.Root.Namespaces;
using SysML2.NET.Core.Systems.Occurrences;
+ using SysML2.NET.Core.POCO.Kernel.Multiplicities;
using SysML2.NET.Core.POCO.Core.Classifiers;
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Core.Types;
@@ -95,10 +97,17 @@ internal static class ControlNodeExtensions
///
/// The expected
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static bool ComputeMultiplicityHasBoundsOperation(this IControlNode controlNodeSubject, IMultiplicity mult, int lower, string upper)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ if (controlNodeSubject == null)
+ {
+ throw new ArgumentNullException(nameof(controlNodeSubject));
+ }
+
+ return mult != null
+ && (mult is IMultiplicityRange multiplicityRange
+ ? multiplicityRange.HasBounds(lower, upper)
+ : mult.AllSupertypes().OfType().Any(rangeSupertype => rangeSupertype.HasBounds(lower, upper)));
}
}
}
diff --git a/SysML2.NET/Extend/FeatureTypingExtensions.cs b/SysML2.NET/Extend/FeatureTypingExtensions.cs
index 0b0762c1..47af06c1 100644
--- a/SysML2.NET/Extend/FeatureTypingExtensions.cs
+++ b/SysML2.NET/Extend/FeatureTypingExtensions.cs
@@ -43,10 +43,11 @@ internal static class FeatureTypingExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IFeature ComputeOwningFeature(this IFeatureTyping featureTypingSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return featureTypingSubject == null
+ ? throw new ArgumentNullException(nameof(featureTypingSubject))
+ : featureTypingSubject.OwningRelatedElement as IFeature;
}
}
diff --git a/SysML2.NET/Extend/ReturnParameterMembershipExtensions.cs b/SysML2.NET/Extend/ReturnParameterMembershipExtensions.cs
index 44d92a18..3f283a64 100644
--- a/SysML2.NET/Extend/ReturnParameterMembershipExtensions.cs
+++ b/SysML2.NET/Extend/ReturnParameterMembershipExtensions.cs
@@ -54,10 +54,11 @@ internal static class ReturnParameterMembershipExtensions
///
/// The expected
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static FeatureDirectionKind ComputeRedefinedParameterDirectionOperation(this IReturnParameterMembership returnParameterMembershipSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return returnParameterMembershipSubject == null
+ ? throw new ArgumentNullException(nameof(returnParameterMembershipSubject))
+ : FeatureDirectionKind.Out;
}
}
}