From 024345b988b5ee2bff7ed4d3967bafb2cfea1a34 Mon Sep 17 00:00:00 2001 From: atheate Date: Tue, 26 May 2026 15:50:08 +0200 Subject: [PATCH 1/2] Fix #123 --- ...dFeatureMembershipExtensionsTestFixture.cs | 70 ++++++++++++++++--- .../Extend/EndFeatureMembershipExtensions.cs | 9 ++- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/SysML2.NET.Tests/Extend/EndFeatureMembershipExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/EndFeatureMembershipExtensionsTestFixture.cs index 8a121303..90be40c4 100644 --- a/SysML2.NET.Tests/Extend/EndFeatureMembershipExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/EndFeatureMembershipExtensionsTestFixture.cs @@ -1,38 +1,88 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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.Exceptions; + using SysML2.NET.Extensions; + + using Type = SysML2.NET.Core.POCO.Core.Types.Type; [TestFixture] public class EndFeatureMembershipExtensionsTestFixture { [Test] - public void ComputeOwnedMemberFeature_ThrowsNotSupportedException() + public void VerifyComputeOwnedMemberFeature() { - Assert.That(() => ((IEndFeatureMembership)null).ComputeOwnedMemberFeature(), Throws.TypeOf()); + Assert.That(() => ((IEndFeatureMembership)null).ComputeOwnedMemberFeature(), Throws.TypeOf()); + + // Empty OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var endFeatureMembership = new EndFeatureMembership(); + + Assert.That(() => endFeatureMembership.ComputeOwnedMemberFeature(), Throws.TypeOf()); + + // Single IFeature wired via the public API → returned. + var owningType = new Type(); + var feature = new Feature(); + + owningType.AssignOwnership(endFeatureMembership, feature); + + Assert.That(endFeatureMembership.ComputeOwnedMemberFeature(), Is.SameAs(feature)); + + // Two IFeatures in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException. + var twoFeatureMembership = new EndFeatureMembership(); + var firstFeature = new Feature(); + var secondFeature = new Feature(); + + ((IContainedRelationship)twoFeatureMembership).OwnedRelatedElement.Add(firstFeature); + ((IContainedRelationship)twoFeatureMembership).OwnedRelatedElement.Add(secondFeature); + + Assert.That(() => twoFeatureMembership.ComputeOwnedMemberFeature(), Throws.TypeOf()); + + // Mixed-type owned related elements: exactly one IFeature alongside a non-IFeature (Namespace). + // The RequireSingleOfType projection MUST pick out the IFeature regardless of its position + // (this is the core robustness guarantee — never positionally index the unfiltered collection). + var mixedMembership = new EndFeatureMembership(); + var siblingNonFeature = new Namespace(); + var mixedFeature = new Feature(); + + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(siblingNonFeature); + ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(mixedFeature); + + Assert.That(mixedMembership.ComputeOwnedMemberFeature(), Is.SameAs(mixedFeature)); + + // OwnedRelatedElement populated with non-IFeature element(s) only → no IFeature match: + // [1..1] violation, throws IncompleteModelException. + var nonFeatureMembership = new EndFeatureMembership(); + var nonFeatureElement = new Namespace(); + + ((IContainedRelationship)nonFeatureMembership).OwnedRelatedElement.Add(nonFeatureElement); + + Assert.That(() => nonFeatureMembership.ComputeOwnedMemberFeature(), Throws.TypeOf()); } } } diff --git a/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs b/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs index 538a5844..5c121bc6 100644 --- a/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs +++ b/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs @@ -28,6 +28,7 @@ namespace SysML2.NET.Core.POCO.Core.Features using SysML2.NET.Core.POCO.Root.Annotations; using SysML2.NET.Core.POCO.Root.Elements; using SysML2.NET.Core.POCO.Root.Namespaces; + using SysML2.NET.Extensions; /// /// The class provides extensions methods for @@ -44,10 +45,14 @@ internal static class EndFeatureMembershipExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IFeature ComputeOwnedMemberFeature(this IEndFeatureMembership endFeatureMembershipSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (endFeatureMembershipSubject == null) + { + throw new ArgumentNullException(nameof(endFeatureMembershipSubject)); + } + + return endFeatureMembershipSubject.OwnedRelatedElement.RequireSingleOfType(nameof(endFeatureMembershipSubject)); } } From 73a71965b6212e2b1ba5f6c60272554f735b7101 Mon Sep 17 00:00:00 2001 From: atheate Date: Tue, 26 May 2026 15:52:22 +0200 Subject: [PATCH 2/2] File cleanup --- SysML2.NET/Extend/EndFeatureMembershipExtensions.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs b/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs index 5c121bc6..1e5ef201 100644 --- a/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs +++ b/SysML2.NET/Extend/EndFeatureMembershipExtensions.cs @@ -21,13 +21,7 @@ namespace SysML2.NET.Core.POCO.Core.Features { using System; - using System.Collections.Generic; - using SysML2.NET.Core.Root.Namespaces; - using SysML2.NET.Core.POCO.Core.Types; - using SysML2.NET.Core.POCO.Root.Annotations; - using SysML2.NET.Core.POCO.Root.Elements; - using SysML2.NET.Core.POCO.Root.Namespaces; using SysML2.NET.Extensions; /// @@ -54,6 +48,5 @@ internal static IFeature ComputeOwnedMemberFeature(this IEndFeatureMembership en return endFeatureMembershipSubject.OwnedRelatedElement.RequireSingleOfType(nameof(endFeatureMembershipSubject)); } - } }