diff --git a/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs
index bb6e6cd9..2af5cd12 100644
--- a/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs
@@ -1,73 +1,236 @@
// -------------------------------------------------------------------------------------------------
//
-//
+//
// 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.Types;
+ using SysML2.NET.Core.POCO.Kernel.Behaviors;
+ using SysML2.NET.Core.POCO.Root.Annotations;
+ using SysML2.NET.Core.POCO.Systems.Constraints;
+ using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage;
+ using SysML2.NET.Core.POCO.Systems.Parts;
using SysML2.NET.Core.POCO.Systems.Requirements;
+ using SysML2.NET.Core.Systems.Requirements;
+ using SysML2.NET.Extensions;
[TestFixture]
public class RequirementDefinitionExtensionsTestFixture
{
[Test]
- public void ComputeActorParameter_ThrowsNotSupportedException()
+ public void VerifyComputeActorParameter()
{
- Assert.That(() => ((IRequirementDefinition)null).ComputeActorParameter(), Throws.TypeOf());
+ Assert.That(() => ((IRequirementDefinition)null).ComputeActorParameter(), Throws.TypeOf());
+
+ var requirementDefinition = new RequirementDefinition();
+
+ Assert.That(requirementDefinition.ComputeActorParameter(), Is.Empty);
+
+ // Discrimination: add a ParameterMembership (not ActorMembership) — must be excluded from result.
+ var parameterMembership = new ParameterMembership();
+ var parameterUsage = new Usage();
+ requirementDefinition.AssignOwnership(parameterMembership, parameterUsage);
+
+ Assert.That(requirementDefinition.ComputeActorParameter(), Is.Empty);
+
+ // Populated case: ActorMembership is present; selecting ownedActorParameter triggers an
+ // upstream stub (ActorMembershipExtensions.ComputeOwnedActorParameter is not yet implemented).
+ var actorMembership = new ActorMembership();
+ var actorPartUsage = new PartUsage();
+ requirementDefinition.AssignOwnership(actorMembership, actorPartUsage);
+
+ Assert.That(() => requirementDefinition.ComputeActorParameter(), Throws.TypeOf());
}
-
+
[Test]
- public void ComputeAssumedConstraint_ThrowsNotSupportedException()
+ public void VerifyComputeAssumedConstraint()
{
- Assert.That(() => ((IRequirementDefinition)null).ComputeAssumedConstraint(), Throws.TypeOf());
+ Assert.That(() => ((IRequirementDefinition)null).ComputeAssumedConstraint(), Throws.TypeOf());
+
+ var requirementDefinition = new RequirementDefinition();
+
+ Assert.That(requirementDefinition.ComputeAssumedConstraint(), Is.Empty);
+
+ // Type discrimination: add a FeatureMembership (not IRequirementConstraintMembership) — excluded.
+ var featureMembership = new FeatureMembership();
+ var featureUsage = new Usage();
+ requirementDefinition.AssignOwnership(featureMembership, featureUsage);
+
+ Assert.That(requirementDefinition.ComputeAssumedConstraint(), Is.Empty);
+
+ // Kind discrimination: add a RequirementConstraintMembership with Kind = Requirement — excluded.
+ var requiredMembership = new RequirementConstraintMembership { Kind = RequirementConstraintKind.Requirement };
+ var requiredConstraintUsage = new ConstraintUsage();
+ requirementDefinition.AssignOwnership(requiredMembership, requiredConstraintUsage);
+
+ Assert.That(requirementDefinition.ComputeAssumedConstraint(), Is.Empty);
+
+ // Populated case: RequirementConstraintMembership with Kind = Assumption; selecting
+ // ownedConstraint triggers an upstream stub (RequirementConstraintMembershipExtensions
+ // .ComputeOwnedConstraint is not yet implemented).
+ var assumedMembership = new RequirementConstraintMembership { Kind = RequirementConstraintKind.Assumption };
+ var assumedConstraintUsage = new ConstraintUsage();
+ requirementDefinition.AssignOwnership(assumedMembership, assumedConstraintUsage);
+
+ Assert.That(() => requirementDefinition.ComputeAssumedConstraint(), Throws.TypeOf());
}
-
+
[Test]
- public void ComputeFramedConcern_ThrowsNotSupportedException()
+ public void VerifyComputeFramedConcern()
{
- Assert.That(() => ((IRequirementDefinition)null).ComputeFramedConcern(), Throws.TypeOf());
+ Assert.That(() => ((IRequirementDefinition)null).ComputeFramedConcern(), Throws.TypeOf());
+
+ var requirementDefinition = new RequirementDefinition();
+
+ Assert.That(requirementDefinition.ComputeFramedConcern(), Is.Empty);
+
+ // Discrimination cannot be tested at this layer: any IFeatureMembership subtype (including
+ // RequirementConstraintMembership) causes subject.featureMembership to traverse
+ // RemoveRedefinedFeatures → IFeatureMembership.ownedMemberFeature, which dispatches to the
+ // stubbed RequirementConstraintMembershipExtensions.ComputeOwnedConstraint and throws
+ // NotSupportedException — identical to the populated stub-blocker case below.
+ // The discrimination block is omitted until upstream stubs are implemented.
+
+ // Populated case: FramedConcernMembership is present; selecting ownedConcern triggers an
+ // upstream stub (FramedConcernMembershipExtensions.ComputeOwnedConcern is not yet implemented).
+ var framedMembership = new FramedConcernMembership();
+ var concernUsage = new ConcernUsage();
+ requirementDefinition.AssignOwnership(framedMembership, concernUsage);
+
+ Assert.That(() => requirementDefinition.ComputeFramedConcern(), Throws.TypeOf());
}
+
[Test]
- public void ComputeRequiredConstraint_ThrowsNotSupportedException()
+ public void VerifyComputeRequiredConstraint()
{
- Assert.That(() => ((IRequirementDefinition)null).ComputeRequiredConstraint(), Throws.TypeOf());
+ Assert.That(() => ((IRequirementDefinition)null).ComputeRequiredConstraint(), Throws.TypeOf());
+
+ var requirementDefinition = new RequirementDefinition();
+
+ Assert.That(requirementDefinition.ComputeRequiredConstraint(), Is.Empty);
+
+ // Type discrimination: add a FeatureMembership (not IRequirementConstraintMembership) — excluded.
+ var featureMembership = new FeatureMembership();
+ var featureUsage = new Usage();
+ requirementDefinition.AssignOwnership(featureMembership, featureUsage);
+
+ Assert.That(requirementDefinition.ComputeRequiredConstraint(), Is.Empty);
+
+ // Kind discrimination: add a RequirementConstraintMembership with Kind = Assumption — excluded.
+ var assumedMembership = new RequirementConstraintMembership { Kind = RequirementConstraintKind.Assumption };
+ var assumedConstraintUsage = new ConstraintUsage();
+ requirementDefinition.AssignOwnership(assumedMembership, assumedConstraintUsage);
+
+ Assert.That(requirementDefinition.ComputeRequiredConstraint(), Is.Empty);
+
+ // Populated case: RequirementConstraintMembership with Kind = Requirement; selecting
+ // ownedConstraint triggers an upstream stub (RequirementConstraintMembershipExtensions
+ // .ComputeOwnedConstraint is not yet implemented).
+ var requiredMembership = new RequirementConstraintMembership { Kind = RequirementConstraintKind.Requirement };
+ var requiredConstraintUsage = new ConstraintUsage();
+ requirementDefinition.AssignOwnership(requiredMembership, requiredConstraintUsage);
+
+ Assert.That(() => requirementDefinition.ComputeRequiredConstraint(), Throws.TypeOf());
}
-
+
[Test]
- public void ComputeStakeholderParameter_ThrowsNotSupportedException()
+ public void VerifyComputeStakeholderParameter()
{
- Assert.That(() => ((IRequirementDefinition)null).ComputeStakeholderParameter(), Throws.TypeOf());
+ Assert.That(() => ((IRequirementDefinition)null).ComputeStakeholderParameter(), Throws.TypeOf());
+
+ var requirementDefinition = new RequirementDefinition();
+
+ Assert.That(requirementDefinition.ComputeStakeholderParameter(), Is.Empty);
+
+ // Discrimination cannot be tested at this layer: any IFeatureMembership subtype (including
+ // ActorMembership) causes subject.featureMembership to traverse RemoveRedefinedFeatures →
+ // IFeatureMembership.ownedMemberFeature, which dispatches to the stubbed
+ // ActorMembershipExtensions.ComputeOwnedActorParameter and throws NotSupportedException —
+ // identical to the populated stub-blocker case below.
+ // The discrimination block is omitted until upstream stubs are implemented.
+
+ // Populated case: StakeholderMembership is present; selecting ownedStakeholderParameter
+ // triggers an upstream stub (StakeholderMembershipExtensions.ComputeOwnedStakeholderParameter
+ // is not yet implemented).
+ var stakeholderMembership = new StakeholderMembership();
+ var stakeholderPartUsage = new PartUsage();
+ requirementDefinition.AssignOwnership(stakeholderMembership, stakeholderPartUsage);
+
+ Assert.That(() => requirementDefinition.ComputeStakeholderParameter(), Throws.TypeOf());
}
-
+
[Test]
- public void ComputeSubjectParameter_ThrowsNotSupportedException()
+ public void VerifyComputeSubjectParameter()
{
- Assert.That(() => ((IRequirementDefinition)null).ComputeSubjectParameter(), Throws.TypeOf());
+ Assert.That(() => ((IRequirementDefinition)null).ComputeSubjectParameter(), Throws.TypeOf());
+
+ var requirementDefinition = new RequirementDefinition();
+
+ // Empty case: no SubjectMembership in featureMembership → null.
+ Assert.That(requirementDefinition.ComputeSubjectParameter(), Is.Null);
+
+ // Discrimination: add a ParameterMembership (not SubjectMembership) → still null.
+ var parameterMembership = new ParameterMembership();
+ var parameterUsage = new Usage();
+ requirementDefinition.AssignOwnership(parameterMembership, parameterUsage);
+
+ Assert.That(requirementDefinition.ComputeSubjectParameter(), Is.Null);
+
+ // Populated case: SubjectMembership is present; selecting ownedSubjectParameter triggers an
+ // upstream stub (SubjectMembershipExtensions.ComputeOwnedSubjectParameter is not yet implemented).
+ var subjectMembership = new SubjectMembership();
+ var subjectUsage = new Usage();
+ requirementDefinition.AssignOwnership(subjectMembership, subjectUsage);
+
+ Assert.That(() => requirementDefinition.ComputeSubjectParameter(), Throws.TypeOf());
}
-
+
+ private static readonly string[] ExpectedSingleComputedText = ["The requirement text."];
+ private static readonly string[] ExpectedMultipleComputedText = ["The requirement text.", "Additional context."];
+
[Test]
- public void ComputeText_ThrowsNotSupportedException()
+ public void VerifyComputeText()
{
- Assert.That(() => ((IRequirementDefinition)null).ComputeText(), Throws.TypeOf());
+ Assert.That(() => ((IRequirementDefinition)null).ComputeText(), Throws.TypeOf());
+
+ var requirementDefinition = new RequirementDefinition();
+
+ // Empty case: no Documentation elements → empty list.
+ Assert.That(requirementDefinition.ComputeText(), Is.Empty);
+
+ // One Documentation with a body.
+ var firstDocumentation = new Documentation { Body = "The requirement text." };
+ var firstAnnotation = new Annotation();
+ requirementDefinition.AssignOwnership(firstAnnotation, firstDocumentation);
+
+ Assert.That(requirementDefinition.ComputeText(), Is.EqualTo(ExpectedSingleComputedText));
+
+ // Two Documentation elements — both bodies appear in order.
+ var secondDocumentation = new Documentation { Body = "Additional context." };
+ var secondAnnotation = new Annotation();
+ requirementDefinition.AssignOwnership(secondAnnotation, secondDocumentation);
+
+ Assert.That(requirementDefinition.ComputeText(), Is.EqualTo(ExpectedMultipleComputedText));
}
}
}
diff --git a/SysML2.NET/Extend/RequirementDefinitionExtensions.cs b/SysML2.NET/Extend/RequirementDefinitionExtensions.cs
index 5f6bfda1..49dcd615 100644
--- a/SysML2.NET/Extend/RequirementDefinitionExtensions.cs
+++ b/SysML2.NET/Extend/RequirementDefinitionExtensions.cs
@@ -22,38 +22,13 @@ namespace SysML2.NET.Core.POCO.Systems.Requirements
{
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.POCO.Core.Classifiers;
- using SysML2.NET.Core.POCO.Core.Features;
- using SysML2.NET.Core.POCO.Core.Types;
- using SysML2.NET.Core.POCO.Kernel.Behaviors;
- using SysML2.NET.Core.POCO.Kernel.Functions;
+ using SysML2.NET.Core.Systems.Requirements;
using SysML2.NET.Core.POCO.Root.Annotations;
- using SysML2.NET.Core.POCO.Root.Elements;
- using SysML2.NET.Core.POCO.Root.Namespaces;
- using SysML2.NET.Core.POCO.Systems.Actions;
- using SysML2.NET.Core.POCO.Systems.Allocations;
- using SysML2.NET.Core.POCO.Systems.AnalysisCases;
- using SysML2.NET.Core.POCO.Systems.Attributes;
- using SysML2.NET.Core.POCO.Systems.Calculations;
- using SysML2.NET.Core.POCO.Systems.Cases;
- using SysML2.NET.Core.POCO.Systems.Connections;
using SysML2.NET.Core.POCO.Systems.Constraints;
using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage;
- using SysML2.NET.Core.POCO.Systems.Enumerations;
- using SysML2.NET.Core.POCO.Systems.Flows;
- using SysML2.NET.Core.POCO.Systems.Interfaces;
- using SysML2.NET.Core.POCO.Systems.Items;
- using SysML2.NET.Core.POCO.Systems.Metadata;
- using SysML2.NET.Core.POCO.Systems.Occurrences;
using SysML2.NET.Core.POCO.Systems.Parts;
- using SysML2.NET.Core.POCO.Systems.Ports;
- using SysML2.NET.Core.POCO.Systems.States;
- using SysML2.NET.Core.POCO.Systems.UseCases;
- using SysML2.NET.Core.POCO.Systems.VerificationCases;
- using SysML2.NET.Core.POCO.Systems.Views;
///
/// The class provides extensions methods for
@@ -78,10 +53,11 @@ internal static class RequirementDefinitionExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeActorParameter(this IRequirementDefinition requirementDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return requirementDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(requirementDefinitionSubject))
+ : [..requirementDefinitionSubject.featureMembership.OfType().Select(actorMembership => actorMembership.ownedActorParameter)];
}
///
@@ -102,10 +78,16 @@ internal static List ComputeActorParameter(this IRequirementDefiniti
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeAssumedConstraint(this IRequirementDefinition requirementDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return requirementDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(requirementDefinitionSubject))
+ : [
+ ..requirementDefinitionSubject.ownedFeatureMembership
+ .OfType()
+ .Where(requirementConstraintMembership => requirementConstraintMembership.Kind == RequirementConstraintKind.Assumption)
+ .Select(requirementConstraintMembership => requirementConstraintMembership.ownedConstraint)
+ ];
}
///
@@ -125,10 +107,11 @@ internal static List ComputeAssumedConstraint(this IRequiremen
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeFramedConcern(this IRequirementDefinition requirementDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return requirementDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(requirementDefinitionSubject))
+ : [..requirementDefinitionSubject.featureMembership.OfType().Select(framedConcernMembership => framedConcernMembership.ownedConcern)];
}
///
@@ -149,10 +132,16 @@ internal static List ComputeFramedConcern(this IRequirementDefini
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeRequiredConstraint(this IRequirementDefinition requirementDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return requirementDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(requirementDefinitionSubject))
+ : [
+ ..requirementDefinitionSubject.ownedFeatureMembership
+ .OfType()
+ .Where(requirementConstraintMembership => requirementConstraintMembership.Kind == RequirementConstraintKind.Requirement)
+ .Select(requirementConstraintMembership => requirementConstraintMembership.ownedConstraint)
+ ];
}
///
@@ -172,10 +161,12 @@ internal static List ComputeRequiredConstraint(this IRequireme
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeStakeholderParameter(this IRequirementDefinition requirementDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ // The OCL uses "StakholderMembership" which is a typo in the XMI source; the correct C# type is IStakeholderMembership.
+ return requirementDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(requirementDefinitionSubject))
+ : [..requirementDefinitionSubject.featureMembership.OfType().Select(stakeholderMembership => stakeholderMembership.ownedStakeholderParameter)];
}
///
@@ -198,10 +189,18 @@ internal static List ComputeStakeholderParameter(this IRequirementDe
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IUsage ComputeSubjectParameter(this IRequirementDefinition requirementDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ if (requirementDefinitionSubject == null)
+ {
+ throw new ArgumentNullException(nameof(requirementDefinitionSubject));
+ }
+
+ var subjects = requirementDefinitionSubject.featureMembership.OfType().ToList();
+
+ return subjects.Count == 0
+ ? null
+ : subjects[0].ownedSubjectParameter;
}
///
@@ -219,11 +218,11 @@ internal static IUsage ComputeSubjectParameter(this IRequirementDefinition requi
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeText(this IRequirementDefinition requirementDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return requirementDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(requirementDefinitionSubject))
+ : [..requirementDefinitionSubject.documentation.Select(documentation => documentation.Body)];
}
-
}
}