From 3ece76e25b7935da63eada064eadd23cac468adf Mon Sep 17 00:00:00 2001 From: atheate Date: Mon, 1 Jun 2026 08:44:04 +0200 Subject: [PATCH] Fix #90 #97 #115 #141 #175 #177 --- .../ActorMembershipExtensionsTestFixture.cs | 66 ++++++++-- ...ertConstraintUsageExtensionsTestFixture.cs | 47 +++++-- .../CaseDefinitionExtensionsTestFixture.cs | 4 +- .../Extend/CaseUsageExtensionsTestFixture.cs | 4 +- .../ConstraintUsageExtensionsTestFixture.cs | 105 ++++++++++++++-- ...dConcernMembershipExtensionsTestFixture.cs | 116 +++++++++++++++-- ...uirementDefinitionExtensionsTestFixture.cs | 10 +- .../RequirementUsageExtensionsTestFixture.cs | 10 +- ...ficationMembershipExtensionsTestFixture.cs | 118 ++++++++++++++++-- ...fyRequirementUsageExtensionsTestFixture.cs | 105 ++++++++++++++-- ...tionCaseDefinitionExtensionsTestFixture.cs | 6 +- ...ificationCaseUsageExtensionsTestFixture.cs | 6 +- ...iewpointDefinitionExtensionsTestFixture.cs | 7 +- .../ViewpointUsageExtensionsTestFixture.cs | 7 +- .../Extend/ActorMembershipExtensions.cs | 9 +- .../Extend/AssertConstraintUsageExtensions.cs | 15 ++- .../Extend/ConstraintUsageExtensions.cs | 34 ++++- .../FramedConcernMembershipExtensions.cs | 26 +++- ...irementVerificationMembershipExtensions.cs | 26 +++- .../SatisfyRequirementUsageExtensions.cs | 43 ++++++- 20 files changed, 650 insertions(+), 114 deletions(-) diff --git a/SysML2.NET.Tests/Extend/ActorMembershipExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ActorMembershipExtensionsTestFixture.cs index 2ad5978dd..b5f0959e0 100644 --- a/SysML2.NET.Tests/Extend/ActorMembershipExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/ActorMembershipExtensionsTestFixture.cs @@ -1,38 +1,84 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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.Elements; + using SysML2.NET.Core.POCO.Root.Namespaces; + using SysML2.NET.Core.POCO.Systems.Parts; using SysML2.NET.Core.POCO.Systems.Requirements; + using SysML2.NET.Exceptions; + using SysML2.NET.Extensions; [TestFixture] public class ActorMembershipExtensionsTestFixture { [Test] - public void ComputeOwnedActorParameter_ThrowsNotSupportedException() + public void VerifyComputeOwnedActorParameter() { - Assert.That(() => ((IActorMembership)null).ComputeOwnedActorParameter(), Throws.TypeOf()); + Assert.That(() => ((IActorMembership)null).ComputeOwnedActorParameter(), Throws.TypeOf()); + + // Empty OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var emptyMembership = new ActorMembership(); + + Assert.That(() => emptyMembership.ComputeOwnedActorParameter(), Throws.TypeOf()); + + // Single non-IPartUsage in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var nonPartMembership = new ActorMembership(); + var nonPartElement = new Namespace(); + ((IContainedRelationship)nonPartMembership).OwnedRelatedElement.Add(nonPartElement); + + Assert.That(() => nonPartMembership.ComputeOwnedActorParameter(), Throws.TypeOf()); + + // Single IPartUsage wired via the public API → returned. + // ActorMembership is a FeatureMembership and requires an IType source per AssignOwnership; + // RequirementDefinition is the natural Requirements-namespace IType for an actor parameter. + var owningDefinition = new RequirementDefinition(); + var actorMembership = new ActorMembership(); + var partUsage = new PartUsage(); + owningDefinition.AssignOwnership(actorMembership, partUsage); + + Assert.That(actorMembership.ComputeOwnedActorParameter(), Is.SameAs(partUsage)); + + // Two IPartUsage in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var twoPartMembership = new ActorMembership(); + var firstPart = new PartUsage(); + var secondPart = new PartUsage(); + ((IContainedRelationship)twoPartMembership).OwnedRelatedElement.Add(firstPart); + ((IContainedRelationship)twoPartMembership).OwnedRelatedElement.Add(secondPart); + + Assert.That(() => twoPartMembership.ComputeOwnedActorParameter(), Throws.TypeOf()); + + // Mixed: non-IPartUsage (Namespace) alongside a single IPartUsage — the type filter picks + // out the PartUsage regardless of its position. + var mixedMembership = new ActorMembership(); + var siblingNamespace = new Namespace(); + var mixedPart = new PartUsage(); + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(siblingNamespace); + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(mixedPart); + + Assert.That(mixedMembership.ComputeOwnedActorParameter(), Is.SameAs(mixedPart)); } } } diff --git a/SysML2.NET.Tests/Extend/AssertConstraintUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/AssertConstraintUsageExtensionsTestFixture.cs index 3c4410d56..fe7ee0764 100644 --- a/SysML2.NET.Tests/Extend/AssertConstraintUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/AssertConstraintUsageExtensionsTestFixture.cs @@ -1,38 +1,65 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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.Systems.Constraints ; + using SysML2.NET.Core.POCO.Core.Features; + using SysML2.NET.Core.POCO.Systems.Constraints; + using SysML2.NET.Core.POCO.Systems.Parts; + using SysML2.NET.Extensions; [TestFixture] public class AssertConstraintUsageExtensionsTestFixture { [Test] - public void ComputeAssertedConstraint_ThrowsNotSupportedException() + public void VerifyComputeAssertedConstraint() { - Assert.That(() => ((IAssertConstraintUsage)null).ComputeAssertedConstraint(), Throws.TypeOf()); + Assert.That(() => ((IAssertConstraintUsage)null).ComputeAssertedConstraint(), Throws.TypeOf()); + + // No ownedReferenceSubsetting → ReferencedFeatureTarget() returns null → + // self-fallback branch: returns the subject itself (which IS-A IConstraintUsage). + var selfFallbackUsage = new AssertConstraintUsage(); + + Assert.That(selfFallbackUsage.ComputeAssertedConstraint(), Is.SameAs(selfFallbackUsage)); + + // ownedReferenceSubsetting points to a ConstraintUsage → that ConstraintUsage is returned + // (since the referenced feature's featureTarget is itself when it has no chainingFeatures). + var withConstraintRefUsage = new AssertConstraintUsage(); + var targetConstraint = new ConstraintUsage(); + var referenceSubsetting = new ReferenceSubsetting { ReferencedFeature = targetConstraint }; + withConstraintRefUsage.AssignOwnership(referenceSubsetting); + + Assert.That(withConstraintRefUsage.ComputeAssertedConstraint(), Is.SameAs(targetConstraint)); + + // ownedReferenceSubsetting points to a non-ConstraintUsage feature → the "as IConstraintUsage" + // cast yields null (the OCL "else null" branch). + var withNonConstraintRefUsage = new AssertConstraintUsage(); + var nonConstraintTarget = new PartUsage(); + var nonConstraintRefSubsetting = new ReferenceSubsetting { ReferencedFeature = nonConstraintTarget }; + withNonConstraintRefUsage.AssignOwnership(nonConstraintRefSubsetting); + + Assert.That(withNonConstraintRefUsage.ComputeAssertedConstraint(), Is.Null); } } } diff --git a/SysML2.NET.Tests/Extend/CaseDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/CaseDefinitionExtensionsTestFixture.cs index 5745038d8..27f73238c 100644 --- a/SysML2.NET.Tests/Extend/CaseDefinitionExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/CaseDefinitionExtensionsTestFixture.cs @@ -50,12 +50,12 @@ public void VerifyComputeActorParameter() Assert.That(caseDefinition.ComputeActorParameter(), Is.Empty); - // For Later: populated case depends on IActorMembership.ComputeOwnedActorParameter, which is still a stub. + // Populated: an ActorMembership carrying a PartUsage → that PartUsage appears in the result. var actorMembership = new ActorMembership(); var actorPartUsage = new PartUsage(); caseDefinition.AssignOwnership(actorMembership, actorPartUsage); - Assert.That(() => caseDefinition.ComputeActorParameter(), Throws.TypeOf()); + Assert.That(caseDefinition.ComputeActorParameter(), Is.EqualTo([actorPartUsage])); } [Test] diff --git a/SysML2.NET.Tests/Extend/CaseUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/CaseUsageExtensionsTestFixture.cs index 7cf27a63e..4b2e31a13 100644 --- a/SysML2.NET.Tests/Extend/CaseUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/CaseUsageExtensionsTestFixture.cs @@ -51,12 +51,12 @@ public void VerifyComputeActorParameter() Assert.That(caseUsage.ComputeActorParameter(), Is.Empty); - // For Later: populated case depends on IActorMembership.ComputeOwnedActorParameter, which is still a stub. + // Populated: an ActorMembership carrying a PartUsage → that PartUsage appears in the result. var actorMembership = new ActorMembership(); var actorPartUsage = new PartUsage(); caseUsage.AssignOwnership(actorMembership, actorPartUsage); - Assert.That(() => caseUsage.ComputeActorParameter(), Throws.TypeOf()); + Assert.That(caseUsage.ComputeActorParameter(), Is.EqualTo([actorPartUsage])); } [Test] diff --git a/SysML2.NET.Tests/Extend/ConstraintUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ConstraintUsageExtensionsTestFixture.cs index 1495397c7..602d41f0a 100644 --- a/SysML2.NET.Tests/Extend/ConstraintUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/ConstraintUsageExtensionsTestFixture.cs @@ -1,38 +1,123 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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.Kernel.Functions; using SysML2.NET.Core.POCO.Systems.Constraints; + using SysML2.NET.Core.POCO.Systems.Parts; + using SysML2.NET.Core.POCO.Systems.Requirements; + using SysML2.NET.Extensions; [TestFixture] public class ConstraintUsageExtensionsTestFixture { [Test] - public void ComputeConstraintDefinition_ThrowsNotSupportedException() + public void VerifyComputeConstraintDefinition() + { + Assert.That(() => ((IConstraintUsage)null).ComputeConstraintDefinition(), Throws.TypeOf()); + + // Empty OwnedRelationship → no FeatureTyping → null. + var emptyUsage = new ConstraintUsage(); + + Assert.That(emptyUsage.ComputeConstraintDefinition(), Is.Null); + + // FeatureTyping whose Type is a non-Predicate → returns null (no IPredicate match). + var nonPredicateUsage = new ConstraintUsage(); + var partDefinition = new PartDefinition(); + var nonPredicateTyping = new FeatureTyping { Type = partDefinition }; + nonPredicateUsage.AssignOwnership(nonPredicateTyping); + + Assert.That(nonPredicateUsage.ComputeConstraintDefinition(), Is.Null); + + // FeatureTyping whose Type is a Predicate → returns it. + var predicateUsage = new ConstraintUsage(); + var predicate = new Predicate(); + var predicateTyping = new FeatureTyping { Type = predicate }; + predicateUsage.AssignOwnership(predicateTyping); + + Assert.That(predicateUsage.ComputeConstraintDefinition(), Is.SameAs(predicate)); + + // FeatureTyping whose Type is a ConstraintDefinition (which IS-A Predicate) → returns it. + var constraintDefUsage = new ConstraintUsage(); + var constraintDefinition = new ConstraintDefinition(); + var constraintDefTyping = new FeatureTyping { Type = constraintDefinition }; + constraintDefUsage.AssignOwnership(constraintDefTyping); + + Assert.That(constraintDefUsage.ComputeConstraintDefinition(), Is.SameAs(constraintDefinition)); + } + + [Test] + public void VerifyComputeRedefinedNamingFeatureOperation() { - Assert.That(() => ((IConstraintUsage)null).ComputeConstraintDefinition(), Throws.TypeOf()); + Assert.That(() => ((IConstraintUsage)null).ComputeRedefinedNamingFeatureOperation(), Throws.TypeOf()); + + // No owningFeatureMembership → else branch delegates to UsageExtensions.ComputeRedefinedNamingFeatureOperation. + // With no OwnedRelationship (no Redefinition) and not a VariantMembership → null. + var elseFallbackUsage = new ConstraintUsage(); + + Assert.That(elseFallbackUsage.ComputeRedefinedNamingFeatureOperation(), Is.Null); + + // owningFeatureMembership IS a RequirementConstraintMembership AND ownedReferenceSubsetting present → + // returns ownedReferenceSubsetting.ReferencedFeature.featureTarget (which is itself for a feature + // with no chainingFeatures). + var owningRequirementUsage = new RequirementUsage(); + var requirementConstraintMembership = new RequirementConstraintMembership(); + var usageInBranch1 = new ConstraintUsage(); + owningRequirementUsage.AssignOwnership(requirementConstraintMembership, usageInBranch1); + + var refTarget = new Feature(); + var referenceSubsetting = new ReferenceSubsetting { ReferencedFeature = refTarget }; + usageInBranch1.AssignOwnership(referenceSubsetting); + + Assert.That(usageInBranch1.ComputeRedefinedNamingFeatureOperation(), Is.SameAs(refTarget)); + + // owningFeatureMembership is RequirementConstraintMembership but NO ownedReferenceSubsetting → + // condition fails → else branch → returns null (no Redefinition). + var owningRequirementUsage2 = new RequirementUsage(); + var rcmNoRef = new RequirementConstraintMembership(); + var usageNoRef = new ConstraintUsage(); + owningRequirementUsage2.AssignOwnership(rcmNoRef, usageNoRef); + + Assert.That(usageNoRef.ComputeRedefinedNamingFeatureOperation(), Is.Null); + } + + [Test] + public void VerifyComputeRedefinedModelLevelEvaluableOperation() + { + Assert.That(() => ((IConstraintUsage)null).ComputeRedefinedModelLevelEvaluableOperation([]), Throws.TypeOf()); + + // OCL body is literally `false` — independent of subject state and of the visited list. + var usage = new ConstraintUsage(); + + using (Assert.EnterMultipleScope()) + { + Assert.That(usage.ComputeRedefinedModelLevelEvaluableOperation([]), Is.False); + Assert.That(usage.ComputeRedefinedModelLevelEvaluableOperation(null), Is.False); + Assert.That(usage.ComputeRedefinedModelLevelEvaluableOperation([new Feature()]), Is.False); + } } } } diff --git a/SysML2.NET.Tests/Extend/FramedConcernMembershipExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/FramedConcernMembershipExtensionsTestFixture.cs index 8adb5ec7d..015f451e1 100644 --- a/SysML2.NET.Tests/Extend/FramedConcernMembershipExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/FramedConcernMembershipExtensionsTestFixture.cs @@ -1,43 +1,135 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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; + using SysML2.NET.Core.POCO.Systems.Parts; using SysML2.NET.Core.POCO.Systems.Requirements; + using SysML2.NET.Exceptions; + using SysML2.NET.Extensions; [TestFixture] public class FramedConcernMembershipExtensionsTestFixture { [Test] - public void ComputeOwnedConcern_ThrowsNotSupportedException() + public void VerifyComputeOwnedConcern() { - Assert.That(() => ((IFramedConcernMembership)null).ComputeOwnedConcern(), Throws.TypeOf()); + Assert.That(() => ((IFramedConcernMembership)null).ComputeOwnedConcern(), Throws.TypeOf()); + + // Empty OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var emptyMembership = new FramedConcernMembership(); + + Assert.That(() => emptyMembership.ComputeOwnedConcern(), Throws.TypeOf()); + + // Single non-IConcernUsage in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var nonConcernMembership = new FramedConcernMembership(); + var nonConcernElement = new Namespace(); + ((IContainedRelationship)nonConcernMembership).OwnedRelatedElement.Add(nonConcernElement); + + Assert.That(() => nonConcernMembership.ComputeOwnedConcern(), Throws.TypeOf()); + + // Single IConcernUsage wired via the public API → returned. + // FramedConcernMembership is a FeatureMembership and requires an IType source per + // AssignOwnership; RequirementDefinition is the natural Requirements-namespace IType + // for a framed concern. + var owningNamespace = new RequirementDefinition(); + var framedMembership = new FramedConcernMembership(); + var concernUsage = new ConcernUsage(); + owningNamespace.AssignOwnership(framedMembership, concernUsage); + + Assert.That(framedMembership.ComputeOwnedConcern(), Is.SameAs(concernUsage)); + + // Two IConcernUsage in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var twoConcernMembership = new FramedConcernMembership(); + var firstConcern = new ConcernUsage(); + var secondConcern = new ConcernUsage(); + ((IContainedRelationship)twoConcernMembership).OwnedRelatedElement.Add(firstConcern); + ((IContainedRelationship)twoConcernMembership).OwnedRelatedElement.Add(secondConcern); + + Assert.That(() => twoConcernMembership.ComputeOwnedConcern(), Throws.TypeOf()); + + // Mixed: non-IConcernUsage (Namespace) alongside a single IConcernUsage — the type filter + // picks out the ConcernUsage regardless of its position. + var mixedMembership = new FramedConcernMembership(); + var siblingNamespace = new Namespace(); + var mixedConcern = new ConcernUsage(); + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(siblingNamespace); + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(mixedConcern); + + Assert.That(mixedMembership.ComputeOwnedConcern(), Is.SameAs(mixedConcern)); } + [Test] - public void ComputeReferencedConcern_ThrowsNotSupportedException() + public void VerifyComputeReferencedConcern() { - Assert.That(() => ((IFramedConcernMembership)null).ComputeReferencedConcern(), Throws.TypeOf()); + Assert.That(() => ((IFramedConcernMembership)null).ComputeReferencedConcern(), Throws.TypeOf()); + + // Empty ownedConcern → propagates IncompleteModelException from ownedConcern's [1..1] guard. + var emptyMembership = new FramedConcernMembership(); + + Assert.That(() => emptyMembership.ComputeReferencedConcern(), Throws.TypeOf()); + + // Populated, no ownedReferenceSubsetting on the ownedConcern → referencedFeatureTarget is null + // → returns ownedConcern itself. + // FramedConcernMembership is a FeatureMembership and requires an IType source per + // AssignOwnership; RequirementDefinition is the natural Requirements-namespace IType + // for a framed concern. + var owningNamespace = new RequirementDefinition(); + var membership = new FramedConcernMembership(); + var ownedConcern = new ConcernUsage(); + owningNamespace.AssignOwnership(membership, ownedConcern); + + Assert.That(membership.ComputeReferencedConcern(), Is.SameAs(ownedConcern)); + + // Populated, with ownedReferenceSubsetting whose ReferencedFeature is itself a ConcernUsage + // → returns that ConcernUsage. + var owningNamespace2 = new RequirementDefinition(); + var membership2 = new FramedConcernMembership(); + var ownedConcern2 = new ConcernUsage(); + owningNamespace2.AssignOwnership(membership2, ownedConcern2); + + var referencedConcern = new ConcernUsage(); + var refSubsetting = new ReferenceSubsetting { ReferencedFeature = referencedConcern }; + ownedConcern2.AssignOwnership(refSubsetting); + + Assert.That(membership2.ComputeReferencedConcern(), Is.SameAs(referencedConcern)); + + // Populated, with ownedReferenceSubsetting whose ReferencedFeature is a non-ConcernUsage Feature + // → returns null (the OCL "else null" branch). + var owningNamespace3 = new RequirementDefinition(); + var membership3 = new FramedConcernMembership(); + var ownedConcern3 = new ConcernUsage(); + owningNamespace3.AssignOwnership(membership3, ownedConcern3); + + var nonConcernTarget = new PartUsage(); + var refSubsetting3 = new ReferenceSubsetting { ReferencedFeature = nonConcernTarget }; + ownedConcern3.AssignOwnership(refSubsetting3); + + Assert.That(membership3.ComputeReferencedConcern(), Is.Null); } } } diff --git a/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs index 216eeefda..87548c26c 100644 --- a/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/RequirementDefinitionExtensionsTestFixture.cs @@ -56,13 +56,12 @@ public void VerifyComputeActorParameter() Assert.That(requirementDefinition.ComputeActorParameter(), Is.Empty); - // Populated case: ActorMembership is present; selecting ownedActorParameter triggers an - // upstream stub (ActorMembershipExtensions.ComputeOwnedActorParameter is not yet implemented). + // Populated: an ActorMembership carrying a PartUsage → that PartUsage appears in the result. var actorMembership = new ActorMembership(); var actorPartUsage = new PartUsage(); requirementDefinition.AssignOwnership(actorMembership, actorPartUsage); - Assert.That(() => requirementDefinition.ComputeActorParameter(), Throws.TypeOf()); + Assert.That(requirementDefinition.ComputeActorParameter(), Is.EqualTo([actorPartUsage])); } [Test] @@ -113,13 +112,12 @@ public void VerifyComputeFramedConcern() // 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). + // Populated: a FramedConcernMembership carrying a ConcernUsage → that ConcernUsage appears in the result. var framedMembership = new FramedConcernMembership(); var concernUsage = new ConcernUsage(); requirementDefinition.AssignOwnership(framedMembership, concernUsage); - Assert.That(() => requirementDefinition.ComputeFramedConcern(), Throws.TypeOf()); + Assert.That(requirementDefinition.ComputeFramedConcern(), Is.EqualTo([concernUsage])); } [Test] diff --git a/SysML2.NET.Tests/Extend/RequirementUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/RequirementUsageExtensionsTestFixture.cs index 6ecc53d4f..60f858235 100644 --- a/SysML2.NET.Tests/Extend/RequirementUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/RequirementUsageExtensionsTestFixture.cs @@ -57,13 +57,12 @@ public void VerifyComputeActorParameter() Assert.That(requirementUsage.ComputeActorParameter(), Is.Empty); - // Populated case: ActorMembership is present; selecting ownedActorParameter triggers an - // upstream stub (ActorMembershipExtensions.ComputeOwnedActorParameter is not yet implemented). + // Populated: an ActorMembership carrying a PartUsage → that PartUsage appears in the result. var actorMembership = new ActorMembership(); var actorPartUsage = new PartUsage(); requirementUsage.AssignOwnership(actorMembership, actorPartUsage); - Assert.That(() => requirementUsage.ComputeActorParameter(), Throws.TypeOf()); + Assert.That(requirementUsage.ComputeActorParameter(), Is.EqualTo([actorPartUsage])); } [Test] @@ -114,13 +113,12 @@ public void VerifyComputeFramedConcern() // 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). + // Populated: a FramedConcernMembership carrying a ConcernUsage → that ConcernUsage appears in the result. var framedMembership = new FramedConcernMembership(); var concernUsage = new ConcernUsage(); requirementUsage.AssignOwnership(framedMembership, concernUsage); - Assert.That(() => requirementUsage.ComputeFramedConcern(), Throws.TypeOf()); + Assert.That(requirementUsage.ComputeFramedConcern(), Is.EqualTo([concernUsage])); } [Test] diff --git a/SysML2.NET.Tests/Extend/RequirementVerificationMembershipExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/RequirementVerificationMembershipExtensionsTestFixture.cs index b691b212b..19d5138e9 100644 --- a/SysML2.NET.Tests/Extend/RequirementVerificationMembershipExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/RequirementVerificationMembershipExtensionsTestFixture.cs @@ -1,44 +1,136 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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; + using SysML2.NET.Core.POCO.Systems.Parts; + using SysML2.NET.Core.POCO.Systems.Requirements; using SysML2.NET.Core.POCO.Systems.VerificationCases; + using SysML2.NET.Exceptions; + using SysML2.NET.Extensions; [TestFixture] public class RequirementVerificationMembershipExtensionsTestFixture { [Test] - public void ComputeOwnedRequirement_ThrowsNotSupportedException() + public void VerifyComputeOwnedRequirement() { - Assert.That(() => ((IRequirementVerificationMembership)null).ComputeOwnedRequirement(), Throws.TypeOf()); + Assert.That(() => ((IRequirementVerificationMembership)null).ComputeOwnedRequirement(), Throws.TypeOf()); + + // Empty OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var emptyMembership = new RequirementVerificationMembership(); + + Assert.That(() => emptyMembership.ComputeOwnedRequirement(), Throws.TypeOf()); + + // Single non-IRequirementUsage in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var nonRequirementMembership = new RequirementVerificationMembership(); + var nonRequirementElement = new Namespace(); + ((IContainedRelationship)nonRequirementMembership).OwnedRelatedElement.Add(nonRequirementElement); + + Assert.That(() => nonRequirementMembership.ComputeOwnedRequirement(), Throws.TypeOf()); + + // Single IRequirementUsage wired via the public API → returned. + // RequirementVerificationMembership is a FeatureMembership (via RequirementConstraintMembership) + // and requires an IType source per AssignOwnership; VerificationCaseDefinition is the natural + // IType context for verifying a requirement. + var owningNamespace = new VerificationCaseDefinition(); + var membership = new RequirementVerificationMembership(); + var requirementUsage = new RequirementUsage(); + owningNamespace.AssignOwnership(membership, requirementUsage); + + Assert.That(membership.ComputeOwnedRequirement(), Is.SameAs(requirementUsage)); + + // Two IRequirementUsage in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var twoRequirementMembership = new RequirementVerificationMembership(); + var firstReq = new RequirementUsage(); + var secondReq = new RequirementUsage(); + ((IContainedRelationship)twoRequirementMembership).OwnedRelatedElement.Add(firstReq); + ((IContainedRelationship)twoRequirementMembership).OwnedRelatedElement.Add(secondReq); + + Assert.That(() => twoRequirementMembership.ComputeOwnedRequirement(), Throws.TypeOf()); + + // Mixed: non-IRequirementUsage (Namespace) alongside a single IRequirementUsage — + // the type filter picks out the RequirementUsage regardless of its position. + var mixedMembership = new RequirementVerificationMembership(); + var siblingNamespace = new Namespace(); + var mixedReq = new RequirementUsage(); + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(siblingNamespace); + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(mixedReq); + + Assert.That(mixedMembership.ComputeOwnedRequirement(), Is.SameAs(mixedReq)); } - + [Test] - public void ComputeVerifiedRequirement_ThrowsNotSupportedException() + public void VerifyComputeVerifiedRequirement() { - Assert.That(() => ((IRequirementVerificationMembership)null).ComputeVerifiedRequirement(), Throws.TypeOf()); + Assert.That(() => ((IRequirementVerificationMembership)null).ComputeVerifiedRequirement(), Throws.TypeOf()); + + // Empty ownedRequirement → propagates IncompleteModelException from ownedRequirement's [1..1] guard. + var emptyMembership = new RequirementVerificationMembership(); + + Assert.That(() => emptyMembership.ComputeVerifiedRequirement(), Throws.TypeOf()); + + // Populated, no ownedReferenceSubsetting on the ownedRequirement → referencedFeatureTarget is null + // → returns ownedRequirement itself. + // RequirementVerificationMembership is a FeatureMembership (via RequirementConstraintMembership) + // and requires an IType source per AssignOwnership; VerificationCaseDefinition is the natural + // IType context for verifying a requirement. + var owningNamespace = new VerificationCaseDefinition(); + var membership = new RequirementVerificationMembership(); + var ownedRequirement = new RequirementUsage(); + owningNamespace.AssignOwnership(membership, ownedRequirement); + + Assert.That(membership.ComputeVerifiedRequirement(), Is.SameAs(ownedRequirement)); + + // Populated, with ownedReferenceSubsetting whose ReferencedFeature is itself a RequirementUsage + // → returns that RequirementUsage. + var owningNamespace2 = new VerificationCaseDefinition(); + var membership2 = new RequirementVerificationMembership(); + var ownedRequirement2 = new RequirementUsage(); + owningNamespace2.AssignOwnership(membership2, ownedRequirement2); + + var referencedRequirement = new RequirementUsage(); + var refSubsetting = new ReferenceSubsetting { ReferencedFeature = referencedRequirement }; + ownedRequirement2.AssignOwnership(refSubsetting); + + Assert.That(membership2.ComputeVerifiedRequirement(), Is.SameAs(referencedRequirement)); + + // Populated, with ownedReferenceSubsetting whose ReferencedFeature is a non-RequirementUsage Feature + // → returns null (the OCL "else null" branch). + var owningNamespace3 = new VerificationCaseDefinition(); + var membership3 = new RequirementVerificationMembership(); + var ownedRequirement3 = new RequirementUsage(); + owningNamespace3.AssignOwnership(membership3, ownedRequirement3); + + var nonRequirementTarget = new PartUsage(); + var refSubsetting3 = new ReferenceSubsetting { ReferencedFeature = nonRequirementTarget }; + ownedRequirement3.AssignOwnership(refSubsetting3); + + Assert.That(membership3.ComputeVerifiedRequirement(), Is.Null); } } } diff --git a/SysML2.NET.Tests/Extend/SatisfyRequirementUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/SatisfyRequirementUsageExtensionsTestFixture.cs index 506fc4b3e..a234761c4 100644 --- a/SysML2.NET.Tests/Extend/SatisfyRequirementUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/SatisfyRequirementUsageExtensionsTestFixture.cs @@ -1,43 +1,126 @@ // ------------------------------------------------------------------------------------------------- // -// +// // 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.Core.Types; + using SysML2.NET.Core.POCO.Kernel.Connectors; + using SysML2.NET.Core.POCO.Systems.Constraints; + using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage; using SysML2.NET.Core.POCO.Systems.Requirements; + using SysML2.NET.Extensions; [TestFixture] public class SatisfyRequirementUsageExtensionsTestFixture { [Test] - public void ComputeSatisfiedRequirement_ThrowsNotSupportedException() + public void VerifyComputeSatisfiedRequirement() { - Assert.That(() => ((ISatisfyRequirementUsage)null).ComputeSatisfiedRequirement(), Throws.TypeOf()); + Assert.That(() => ((ISatisfyRequirementUsage)null).ComputeSatisfiedRequirement(), Throws.TypeOf()); + + // No ownedReferenceSubsetting → AssertConstraintUsage.assertedConstraint returns subject itself, + // which IS-A IRequirementUsage (ISatisfyRequirementUsage : IRequirementUsage) → returns subject. + var selfFallbackUsage = new SatisfyRequirementUsage(); + + Assert.That(selfFallbackUsage.ComputeSatisfiedRequirement(), Is.SameAs(selfFallbackUsage)); + + // ownedReferenceSubsetting points to a RequirementUsage → returns it. + var withReqRefUsage = new SatisfyRequirementUsage(); + var targetRequirement = new RequirementUsage(); + var refSubsetting = new ReferenceSubsetting { ReferencedFeature = targetRequirement }; + withReqRefUsage.AssignOwnership(refSubsetting); + + Assert.That(withReqRefUsage.ComputeSatisfiedRequirement(), Is.SameAs(targetRequirement)); + + // ownedReferenceSubsetting points to a ConstraintUsage that is NOT a RequirementUsage → + // assertedConstraint returns the ConstraintUsage, but the "as IRequirementUsage" cast yields null. + var withWrongTypeUsage = new SatisfyRequirementUsage(); + var nonRequirementTarget = new ConstraintUsage(); + var wrongRefSubsetting = new ReferenceSubsetting { ReferencedFeature = nonRequirementTarget }; + withWrongTypeUsage.AssignOwnership(wrongRefSubsetting); + + Assert.That(withWrongTypeUsage.ComputeSatisfiedRequirement(), Is.Null); } + [Test] - public void ComputeSatisfyingFeature_ThrowsNotSupportedException() + public void VerifyComputeSatisfyingFeature() { - Assert.That(() => ((ISatisfyRequirementUsage)null).ComputeSatisfyingFeature(), Throws.TypeOf()); + Assert.That(() => ((ISatisfyRequirementUsage)null).ComputeSatisfyingFeature(), Throws.TypeOf()); + + // Empty case: no ownedMember at all → no BindingConnectors → returns null. + var emptyUsage = new SatisfyRequirementUsage(); + + Assert.That(emptyUsage.ComputeSatisfyingFeature(), Is.Null); + + // Populated case: a BindingConnector with two ends, one referencing subjectParameter and one + // referencing a "satisfying" Feature → ComputeSatisfyingFeature returns the satisfying Feature. + // Constructing the chain end-to-end: + // srfUsage.subjectParameter ← SubjectMembership.ownedSubjectParameter + // bindingConnector.relatedElement + // ← connectorEnd.ownedReferenceSubsetting.SubsettedFeature + // ← featureMembership.ownedMemberFeature.Where(IsEnd).OwnedRelationship.OfType().FirstOrDefault().ReferencedFeature + var populatedUsage = new SatisfyRequirementUsage(); + + var subjectMembership = new SubjectMembership(); + var subjectParameter = new Usage(); + populatedUsage.AssignOwnership(subjectMembership, subjectParameter); + + var satisfyingFeature = new Feature(); + + var endForSubject = new Feature { IsEnd = true }; + endForSubject.AssignOwnership(new ReferenceSubsetting { ReferencedFeature = subjectParameter }); + + var endForSatisfying = new Feature { IsEnd = true }; + endForSatisfying.AssignOwnership(new ReferenceSubsetting { ReferencedFeature = satisfyingFeature }); + + var bindingConnector = new BindingConnector(); + bindingConnector.AssignOwnership(new FeatureMembership(), endForSubject); + bindingConnector.AssignOwnership(new FeatureMembership(), endForSatisfying); + + populatedUsage.AssignOwnership(new FeatureMembership(), bindingConnector); + + Assert.That(populatedUsage.ComputeSatisfyingFeature(), Is.SameAs(satisfyingFeature)); + + // Degenerate case: a BindingConnector with only ONE end (referencing subjectParameter) → + // bindings[0].relatedElement contains only subjectParameter → FirstOrDefault with the + // !ReferenceEquals(r, subjectParameter) predicate finds no match → returns null. + var degenUsage = new SatisfyRequirementUsage(); + + var degenSubjectMembership = new SubjectMembership(); + var degenSubjectParameter = new Usage(); + degenUsage.AssignOwnership(degenSubjectMembership, degenSubjectParameter); + + var degenEnd = new Feature { IsEnd = true }; + degenEnd.AssignOwnership(new ReferenceSubsetting { ReferencedFeature = degenSubjectParameter }); + + var degenBindingConnector = new BindingConnector(); + degenBindingConnector.AssignOwnership(new FeatureMembership(), degenEnd); + + degenUsage.AssignOwnership(new FeatureMembership(), degenBindingConnector); + + Assert.That(degenUsage.ComputeSatisfyingFeature(), Is.Null); } } } diff --git a/SysML2.NET.Tests/Extend/VerificationCaseDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/VerificationCaseDefinitionExtensionsTestFixture.cs index aaf5996a6..7173e668a 100644 --- a/SysML2.NET.Tests/Extend/VerificationCaseDefinitionExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/VerificationCaseDefinitionExtensionsTestFixture.cs @@ -50,12 +50,14 @@ public void VerifyComputeVerifiedRequirement() Assert.That(verificationCaseDefinition.ComputeVerifiedRequirement(), Is.Empty); - // For Later: populated case depends on IRequirementVerificationMembership.ComputeVerifiedRequirement, which is still a stub. + // Populated: a RequirementVerificationMembership inside objectiveRequirement.featureMembership, + // carrying a verifiedRequirement RequirementUsage with no ownedReferenceSubsetting → + // ComputeVerifiedRequirement falls back to ownedRequirement (the verifiedRequirement itself). var requirementVerificationMembership = new RequirementVerificationMembership(); var verifiedRequirement = new RequirementUsage(); requirementUsage.AssignOwnership(requirementVerificationMembership, verifiedRequirement); - Assert.That(() => verificationCaseDefinition.ComputeVerifiedRequirement(), Throws.TypeOf()); + Assert.That(verificationCaseDefinition.ComputeVerifiedRequirement(), Is.EqualTo([verifiedRequirement])); } } } diff --git a/SysML2.NET.Tests/Extend/VerificationCaseUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/VerificationCaseUsageExtensionsTestFixture.cs index a7ac9b288..6f14d0b2c 100644 --- a/SysML2.NET.Tests/Extend/VerificationCaseUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/VerificationCaseUsageExtensionsTestFixture.cs @@ -76,12 +76,14 @@ public void VerifyComputeVerifiedRequirement() Assert.That(verificationCaseUsage.ComputeVerifiedRequirement(), Is.Empty); - // For Later: populated case depends on IRequirementVerificationMembership.ComputeVerifiedRequirement, which is still a stub. + // Populated: a RequirementVerificationMembership inside objectiveRequirement.featureMembership, + // carrying a verifiedRequirement RequirementUsage with no ownedReferenceSubsetting → + // ComputeVerifiedRequirement falls back to ownedRequirement (the verifiedRequirement itself). var requirementVerificationMembership = new RequirementVerificationMembership(); var verifiedRequirement = new RequirementUsage(); requirementUsage.AssignOwnership(requirementVerificationMembership, verifiedRequirement); - Assert.That(() => verificationCaseUsage.ComputeVerifiedRequirement(), Throws.TypeOf()); + Assert.That(verificationCaseUsage.ComputeVerifiedRequirement(), Is.EqualTo([verifiedRequirement])); } } } diff --git a/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs index 1903b9710..2ea596ea3 100644 --- a/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs @@ -42,13 +42,14 @@ public void VerifyComputeViewpointStakeholder() // Empty: no framedConcern (no FramedConcernMembership in featureMembership) → empty result. Assert.That(viewpointDefinition.ComputeViewpointStakeholder(), Is.Empty); - // Populated case: FramedConcernMembership is present; accessing framedConcern calls - // FramedConcernMembershipExtensions.ComputeOwnedConcern which is an out-of-scope stub. + // Populated: a FramedConcernMembership carrying a bare ConcernUsage (no StakeholderMembership + // inside its featureMembership) → the OCL chain framedConcern.featureMembership + // .selectByKind(StakeholderMembership).ownedStakeholderParameter projects to empty. var framedMembership = new FramedConcernMembership(); var concernUsage = new ConcernUsage(); viewpointDefinition.AssignOwnership(framedMembership, concernUsage); - Assert.That(() => viewpointDefinition.ComputeViewpointStakeholder(), Throws.TypeOf()); + Assert.That(viewpointDefinition.ComputeViewpointStakeholder(), Is.Empty); } } } diff --git a/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs index 0250100cd..86db1ef0d 100644 --- a/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs @@ -76,13 +76,14 @@ public void VerifyComputeViewpointStakeholder() // Empty: no framedConcern (no FramedConcernMembership in featureMembership) → empty result. Assert.That(viewpointUsage.ComputeViewpointStakeholder(), Is.Empty); - // Populated case: FramedConcernMembership is present; accessing framedConcern calls - // FramedConcernMembershipExtensions.ComputeOwnedConcern which is an out-of-scope stub. + // Populated: a FramedConcernMembership carrying a bare ConcernUsage (no StakeholderMembership + // inside its featureMembership) → the OCL chain framedConcern.featureMembership + // .selectByKind(StakeholderMembership).ownedStakeholderParameter projects to empty. var framedMembership = new FramedConcernMembership(); var concernUsage = new ConcernUsage(); viewpointUsage.AssignOwnership(framedMembership, concernUsage); - Assert.That(() => viewpointUsage.ComputeViewpointStakeholder(), Throws.TypeOf()); + Assert.That(viewpointUsage.ComputeViewpointStakeholder(), Is.Empty); } } } diff --git a/SysML2.NET/Extend/ActorMembershipExtensions.cs b/SysML2.NET/Extend/ActorMembershipExtensions.cs index bb8c08185..272a42b28 100644 --- a/SysML2.NET/Extend/ActorMembershipExtensions.cs +++ b/SysML2.NET/Extend/ActorMembershipExtensions.cs @@ -32,6 +32,7 @@ namespace SysML2.NET.Core.POCO.Systems.Requirements using SysML2.NET.Core.POCO.Root.Elements; using SysML2.NET.Core.POCO.Root.Namespaces; using SysML2.NET.Core.POCO.Systems.Parts; + using SysML2.NET.Extensions; /// /// The class provides extensions methods for @@ -48,10 +49,14 @@ internal static class ActorMembershipExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IPartUsage ComputeOwnedActorParameter(this IActorMembership actorMembershipSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (actorMembershipSubject == null) + { + throw new ArgumentNullException(nameof(actorMembershipSubject)); + } + + return actorMembershipSubject.OwnedRelatedElement.RequireSingleOfType(nameof(actorMembershipSubject)); } } diff --git a/SysML2.NET/Extend/AssertConstraintUsageExtensions.cs b/SysML2.NET/Extend/AssertConstraintUsageExtensions.cs index 773135ad8..19933aa5c 100644 --- a/SysML2.NET/Extend/AssertConstraintUsageExtensions.cs +++ b/SysML2.NET/Extend/AssertConstraintUsageExtensions.cs @@ -83,10 +83,21 @@ internal static class AssertConstraintUsageExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IConstraintUsage ComputeAssertedConstraint(this IAssertConstraintUsage assertConstraintUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (assertConstraintUsageSubject == null) + { + throw new ArgumentNullException(nameof(assertConstraintUsageSubject)); + } + + var referencedFeature = assertConstraintUsageSubject.ReferencedFeatureTarget(); + + if (referencedFeature == null) + { + return assertConstraintUsageSubject; + } + + return referencedFeature as IConstraintUsage; } } diff --git a/SysML2.NET/Extend/ConstraintUsageExtensions.cs b/SysML2.NET/Extend/ConstraintUsageExtensions.cs index 3971d3e9e..25e1d6be9 100644 --- a/SysML2.NET/Extend/ConstraintUsageExtensions.cs +++ b/SysML2.NET/Extend/ConstraintUsageExtensions.cs @@ -22,6 +22,7 @@ namespace SysML2.NET.Core.POCO.Systems.Constraints { using System; using System.Collections.Generic; + using System.Linq; using SysML2.NET.Core.Core.Types; using SysML2.NET.Core.Root.Namespaces; @@ -72,10 +73,15 @@ internal static class ConstraintUsageExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IPredicate ComputeConstraintDefinition(this IConstraintUsage constraintUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + return constraintUsageSubject == null + ? throw new ArgumentNullException(nameof(constraintUsageSubject)) + : constraintUsageSubject.OwnedRelationship + .OfType() + .Select(featureTyping => featureTyping.Type) + .OfType() + .FirstOrDefault(); } /// @@ -101,10 +107,22 @@ internal static IPredicate ComputeConstraintDefinition(this IConstraintUsage con /// /// The expected /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IFeature ComputeRedefinedNamingFeatureOperation(this IConstraintUsage constraintUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (constraintUsageSubject == null) + { + throw new ArgumentNullException(nameof(constraintUsageSubject)); + } + + if (constraintUsageSubject.owningFeatureMembership is IRequirementConstraintMembership + && constraintUsageSubject.ownedReferenceSubsetting != null) + { + return constraintUsageSubject.ownedReferenceSubsetting.ReferencedFeature?.featureTarget; + } + + // OCL: self.oclAsType(OccurrenceUsage).namingFeature() — explicit upcast bypass. + // OccurrenceUsage does not override Usage::namingFeature, so dispatch resolves to Usage's body. + return UsageExtensions.ComputeRedefinedNamingFeatureOperation(constraintUsageSubject); } /// @@ -125,10 +143,14 @@ internal static IFeature ComputeRedefinedNamingFeatureOperation(this IConstraint /// /// The expected /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static bool ComputeRedefinedModelLevelEvaluableOperation(this IConstraintUsage constraintUsageSubject, List visited) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (constraintUsageSubject == null) + { + throw new ArgumentNullException(nameof(constraintUsageSubject)); + } + + return false; } } } diff --git a/SysML2.NET/Extend/FramedConcernMembershipExtensions.cs b/SysML2.NET/Extend/FramedConcernMembershipExtensions.cs index 28dd5fa59..038bbf870 100644 --- a/SysML2.NET/Extend/FramedConcernMembershipExtensions.cs +++ b/SysML2.NET/Extend/FramedConcernMembershipExtensions.cs @@ -31,6 +31,7 @@ namespace SysML2.NET.Core.POCO.Systems.Requirements using SysML2.NET.Core.POCO.Root.Elements; using SysML2.NET.Core.POCO.Root.Namespaces; using SysML2.NET.Core.POCO.Systems.Constraints; + using SysML2.NET.Extensions; /// /// The class provides extensions methods for @@ -47,10 +48,14 @@ internal static class FramedConcernMembershipExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IConcernUsage ComputeOwnedConcern(this IFramedConcernMembership framedConcernMembershipSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (framedConcernMembershipSubject == null) + { + throw new ArgumentNullException(nameof(framedConcernMembershipSubject)); + } + + return framedConcernMembershipSubject.OwnedRelatedElement.RequireSingleOfType(nameof(framedConcernMembershipSubject)); } /// @@ -62,10 +67,23 @@ internal static IConcernUsage ComputeOwnedConcern(this IFramedConcernMembership /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IConcernUsage ComputeReferencedConcern(this IFramedConcernMembership framedConcernMembershipSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (framedConcernMembershipSubject == null) + { + throw new ArgumentNullException(nameof(framedConcernMembershipSubject)); + } + + var ownedConcern = framedConcernMembershipSubject.ownedConcern; + + var referencedFeature = ownedConcern?.ReferencedFeatureTarget(); + + if (referencedFeature == null) + { + return ownedConcern; + } + + return referencedFeature as IConcernUsage; } } diff --git a/SysML2.NET/Extend/RequirementVerificationMembershipExtensions.cs b/SysML2.NET/Extend/RequirementVerificationMembershipExtensions.cs index f527749e7..b52d7eefb 100644 --- a/SysML2.NET/Extend/RequirementVerificationMembershipExtensions.cs +++ b/SysML2.NET/Extend/RequirementVerificationMembershipExtensions.cs @@ -32,6 +32,7 @@ namespace SysML2.NET.Core.POCO.Systems.VerificationCases using SysML2.NET.Core.POCO.Root.Namespaces; using SysML2.NET.Core.POCO.Systems.Constraints; using SysML2.NET.Core.POCO.Systems.Requirements; + using SysML2.NET.Extensions; /// /// The class provides extensions methods for @@ -48,10 +49,14 @@ internal static class RequirementVerificationMembershipExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IRequirementUsage ComputeOwnedRequirement(this IRequirementVerificationMembership requirementVerificationMembershipSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (requirementVerificationMembershipSubject == null) + { + throw new ArgumentNullException(nameof(requirementVerificationMembershipSubject)); + } + + return requirementVerificationMembershipSubject.OwnedRelatedElement.RequireSingleOfType(nameof(requirementVerificationMembershipSubject)); } /// @@ -63,10 +68,23 @@ internal static IRequirementUsage ComputeOwnedRequirement(this IRequirementVerif /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IRequirementUsage ComputeVerifiedRequirement(this IRequirementVerificationMembership requirementVerificationMembershipSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (requirementVerificationMembershipSubject == null) + { + throw new ArgumentNullException(nameof(requirementVerificationMembershipSubject)); + } + + var ownedRequirement = requirementVerificationMembershipSubject.ownedRequirement; + + var referencedFeature = ownedRequirement?.ReferencedFeatureTarget(); + + if (referencedFeature == null) + { + return ownedRequirement; + } + + return referencedFeature as IRequirementUsage; } } diff --git a/SysML2.NET/Extend/SatisfyRequirementUsageExtensions.cs b/SysML2.NET/Extend/SatisfyRequirementUsageExtensions.cs index 2eedbba1e..7e0d60669 100644 --- a/SysML2.NET/Extend/SatisfyRequirementUsageExtensions.cs +++ b/SysML2.NET/Extend/SatisfyRequirementUsageExtensions.cs @@ -22,6 +22,7 @@ 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; @@ -31,6 +32,7 @@ namespace SysML2.NET.Core.POCO.Systems.Requirements using SysML2.NET.Core.POCO.Core.Types; using SysML2.NET.Core.POCO.Kernel.Behaviors; using SysML2.NET.Core.POCO.Kernel.Classes; + using SysML2.NET.Core.POCO.Kernel.Connectors; using SysML2.NET.Core.POCO.Kernel.Functions; using SysML2.NET.Core.POCO.Root.Annotations; using SysML2.NET.Core.POCO.Root.Elements; @@ -72,10 +74,24 @@ internal static class SatisfyRequirementUsageExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IRequirementUsage ComputeSatisfiedRequirement(this ISatisfyRequirementUsage satisfyRequirementUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (satisfyRequirementUsageSubject == null) + { + throw new ArgumentNullException(nameof(satisfyRequirementUsageSubject)); + } + + // The static-extension call (rather than the POCO-instance assertedConstraint dispatch) is + // correct AND safe for three independent reasons: + // (1) Spec equivalence: "the assertedConstraint of the SatisfyRequirementUsage considered as + // an AssertConstraintUsage" — the phrase "considered as" is the prose-equivalent of + // oclAsType(AssertConstraintUsage), triggering the CLAUDE.md static-extension exception. + // (2) Leaf metaclass: SatisfyRequirementUsage has no subclasses (verified in AutoGenPoco), + // so there is no redefinition for virtual dispatch to honour — bypass is observation-safe. + // (3) Recursion avoidance: subject.assertedConstraint dispatches via the explicit interface + // implementation IAssertConstraintUsage.assertedConstraint => satisfiedRequirement, which + // would re-enter this method and infinite-loop. + return AssertConstraintUsageExtensions.ComputeAssertedConstraint(satisfyRequirementUsageSubject) as IRequirementUsage; } /// @@ -101,10 +117,29 @@ internal static IRequirementUsage ComputeSatisfiedRequirement(this ISatisfyRequi /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IFeature ComputeSatisfyingFeature(this ISatisfyRequirementUsage satisfyRequirementUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (satisfyRequirementUsageSubject == null) + { + throw new ArgumentNullException(nameof(satisfyRequirementUsageSubject)); + } + + var subjectParameter = satisfyRequirementUsageSubject.subjectParameter; + + var bindings = satisfyRequirementUsageSubject.ownedMember + .OfType() + .Where(bindingConnector => bindingConnector.relatedElement.Contains(subjectParameter)) + .ToList(); + + if (bindings.Count == 0) + { + return null; + } + + // OCL: bindings->first().relatedElement->any(r | r <> subjectParameter) — i.e. return the first + // related element other than subjectParameter (or null when none exists, matching the OCL "exits" + // typo — semantically "no other element exists" → null). + return bindings[0].relatedElement.FirstOrDefault(relatedElement => !ReferenceEquals(relatedElement, subjectParameter)) as IFeature; } }