From fbaaa7d29465097530b7b80b0e0d0c1730b20ee3 Mon Sep 17 00:00:00 2001 From: atheate Date: Fri, 31 Jul 2026 14:54:45 +0200 Subject: [PATCH] Fix #140 #151 #163 #206 --- ...ForLoopActionUsageExtensionsTestFixture.cs | 64 ++++++++++++--- .../LoopActionUsageExtensionsTestFixture.cs | 46 ++++++++--- ...PerformActionUsageExtensionsTestFixture.cs | 64 ++++++++++++--- ...ileLoopActionUsageExtensionsTestFixture.cs | 79 ++++++++++++++++--- .../Extend/ForLoopActionUsageExtensions.cs | 14 +++- .../Extend/LoopActionUsageExtensions.cs | 8 +- .../Extend/PerformActionUsageExtensions.cs | 24 +++++- .../Extend/WhileLoopActionUsageExtensions.cs | 10 ++- 8 files changed, 249 insertions(+), 60 deletions(-) diff --git a/SysML2.NET.Tests/Extend/ForLoopActionUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ForLoopActionUsageExtensionsTestFixture.cs index d456f3f6..61dc373d 100644 --- a/SysML2.NET.Tests/Extend/ForLoopActionUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/ForLoopActionUsageExtensionsTestFixture.cs @@ -1,44 +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 NUnit.Framework; - + + using SysML2.NET.Core.Core.Types; + using SysML2.NET.Core.POCO.Core.Types; + using SysML2.NET.Core.POCO.Kernel.Expressions; + using SysML2.NET.Core.POCO.Kernel.FeatureValues; using SysML2.NET.Core.POCO.Systems.Actions; + using SysML2.NET.Core.POCO.Systems.Attributes; + using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage; + using SysML2.NET.Extensions; [TestFixture] public class ForLoopActionUsageExtensionsTestFixture { [Test] - public void ComputeLoopVariable_ThrowsNotSupportedException() + public void VerifyComputeLoopVariable() { - Assert.That(() => ((IForLoopActionUsage)null).ComputeLoopVariable(), Throws.TypeOf()); + Assert.That(() => ((IForLoopActionUsage)null).ComputeLoopVariable(), Throws.TypeOf()); + + // No ownedFeature -> ownedFeature.FirstOrDefault() is null -> null. + Assert.That(new ForLoopActionUsage().ComputeLoopVariable(), Is.Null); + + // First ownedFeature IS a ReferenceUsage -> returned via the as-cast. + var subjectWithLoopVariable = new ForLoopActionUsage(); + var loopVariable = new ReferenceUsage(); + subjectWithLoopVariable.AssignOwnership(new FeatureMembership(), loopVariable); + + // First ownedFeature is NOT a ReferenceUsage -> the as-cast yields null. + var subjectWithNonReferenceFirstFeature = new ForLoopActionUsage(); + subjectWithNonReferenceFirstFeature.AssignOwnership(new FeatureMembership(), new AttributeUsage()); + + using (Assert.EnterMultipleScope()) + { + // loopVariable = ownedFeature->first() as ReferenceUsage + Assert.That(subjectWithLoopVariable.ComputeLoopVariable(), Is.SameAs(loopVariable)); + Assert.That(subjectWithNonReferenceFirstFeature.ComputeLoopVariable(), Is.Null); + } } - + [Test] - public void ComputeSeqArgument_ThrowsNotSupportedException() + public void VerifyComputeSeqArgument() { - Assert.That(() => ((IForLoopActionUsage)null).ComputeSeqArgument(), Throws.TypeOf()); + Assert.That(() => ((IForLoopActionUsage)null).ComputeSeqArgument(), Throws.TypeOf()); + + // No input parameter -> argument(1) is out of range -> null. + Assert.That(new ForLoopActionUsage().ComputeSeqArgument(), Is.Null); + + var seqExpression = new LiteralInteger(); + var subjectWithSeqArgument = new ForLoopActionUsage(); + var inputParameter = new ReferenceUsage { Direction = FeatureDirectionKind.In }; + subjectWithSeqArgument.AssignOwnership(new FeatureMembership(), inputParameter); + inputParameter.AssignOwnership(new FeatureValue(), seqExpression); + + // seqArgument = argument(1) + Assert.That(subjectWithSeqArgument.ComputeSeqArgument(), Is.SameAs(seqExpression)); } } } diff --git a/SysML2.NET.Tests/Extend/LoopActionUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/LoopActionUsageExtensionsTestFixture.cs index 200e7a85..ea3ee8fb 100644 --- a/SysML2.NET.Tests/Extend/LoopActionUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/LoopActionUsageExtensionsTestFixture.cs @@ -1,38 +1,64 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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.Core.Types; using SysML2.NET.Core.POCO.Systems.Actions; + using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage; + using SysML2.NET.Extensions; [TestFixture] public class LoopActionUsageExtensionsTestFixture { [Test] - public void ComputeBodyAction_ThrowsNotSupportedException() + public void VerifyComputeBodyAction() { - Assert.That(() => ((ILoopActionUsage)null).ComputeBodyAction(), Throws.TypeOf()); + // LoopActionUsage is abstract, so the concrete ILoopActionUsage subtype WhileLoopActionUsage is used as subject. + Assert.That(() => ((ILoopActionUsage)null).ComputeBodyAction(), Throws.TypeOf()); + + // No input parameters -> inputParameter(2) is out of range -> null. + Assert.That(new WhileLoopActionUsage().ComputeBodyAction(), Is.Null); + + // Position-2 input parameter that IS an ActionUsage -> returned via the as-cast. + var subjectWithBodyAction = new WhileLoopActionUsage(); + var bodyActionParameter = new ActionUsage { Direction = FeatureDirectionKind.In }; + subjectWithBodyAction.AssignOwnership(new FeatureMembership(), new ReferenceUsage { Direction = FeatureDirectionKind.In }); + subjectWithBodyAction.AssignOwnership(new FeatureMembership(), bodyActionParameter); + + // Position-2 input parameter that is NOT an ActionUsage -> the as-cast yields null. + var subjectWithNonActionSecondParameter = new WhileLoopActionUsage(); + subjectWithNonActionSecondParameter.AssignOwnership(new FeatureMembership(), new ReferenceUsage { Direction = FeatureDirectionKind.In }); + subjectWithNonActionSecondParameter.AssignOwnership(new FeatureMembership(), new ReferenceUsage { Direction = FeatureDirectionKind.In }); + + using (Assert.EnterMultipleScope()) + { + // bodyAction = inputParameter(2) as ActionUsage + Assert.That(subjectWithBodyAction.ComputeBodyAction(), Is.SameAs(bodyActionParameter)); + Assert.That(subjectWithNonActionSecondParameter.ComputeBodyAction(), Is.Null); + } } } } diff --git a/SysML2.NET.Tests/Extend/PerformActionUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/PerformActionUsageExtensionsTestFixture.cs index 49e6706c..f3339c9b 100644 --- a/SysML2.NET.Tests/Extend/PerformActionUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/PerformActionUsageExtensionsTestFixture.cs @@ -1,38 +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 NUnit.Framework; - + + using SysML2.NET.Core.POCO.Core.Features; using SysML2.NET.Core.POCO.Systems.Actions; + using SysML2.NET.Core.POCO.Systems.Attributes; + using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage; + using SysML2.NET.Extensions; [TestFixture] public class PerformActionUsageExtensionsTestFixture { [Test] - public void ComputePerformedAction_ThrowsNotSupportedException() + public void VerifyComputePerformedAction() + { + Assert.That(() => ((IPerformActionUsage)null).ComputePerformedAction(), Throws.TypeOf()); + + // No ownedReferenceSubsetting -> referencedFeatureTarget() is null -> returns self. + var subjectNoReferent = new PerformActionUsage(); + + Assert.That(subjectNoReferent.ComputePerformedAction(), Is.SameAs(subjectNoReferent)); + + // ReferenceSubsetting whose referent IS an ActionUsage -> returns that ActionUsage. + var subjectWithActionReferent = new PerformActionUsage(); + var actionReferent = new ActionUsage(); + subjectWithActionReferent.AssignOwnership(new ReferenceSubsetting { ReferencedFeature = actionReferent }); + + // ReferenceSubsetting whose referent is NOT an ActionUsage -> the as-cast yields null. + var subjectWithNonActionReferent = new PerformActionUsage(); + subjectWithNonActionReferent.AssignOwnership(new ReferenceSubsetting { ReferencedFeature = new AttributeUsage() }); + + using (Assert.EnterMultipleScope()) + { + Assert.That(subjectWithActionReferent.ComputePerformedAction(), Is.SameAs(actionReferent)); + Assert.That(subjectWithNonActionReferent.ComputePerformedAction(), Is.Null); + } + } + + [Test] + public void VerifyComputeRedefinedNamingFeatureOperation() { - Assert.That(() => ((IPerformActionUsage)null).ComputePerformedAction(), Throws.TypeOf()); + Assert.That(() => ((IPerformActionUsage)null).ComputeRedefinedNamingFeatureOperation(), Throws.TypeOf()); + + // performedAction <> self (an ActionUsage referent) -> returns that performedAction. + var subjectWithActionReferent = new PerformActionUsage(); + var actionReferent = new ActionUsage(); + subjectWithActionReferent.AssignOwnership(new ReferenceSubsetting { ReferencedFeature = actionReferent }); + + // performedAction == self (no referent) -> falls through to the Usage-level namingFeature. + var subjectNoReferent = new PerformActionUsage(); + + using (Assert.EnterMultipleScope()) + { + Assert.That(subjectWithActionReferent.ComputeRedefinedNamingFeatureOperation(), Is.SameAs(actionReferent)); + Assert.That(subjectNoReferent.ComputeRedefinedNamingFeatureOperation(), Is.EqualTo(UsageExtensions.ComputeRedefinedNamingFeatureOperation(subjectNoReferent))); + } } } } diff --git a/SysML2.NET.Tests/Extend/WhileLoopActionUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/WhileLoopActionUsageExtensionsTestFixture.cs index 5a6d1a59..f8f9c619 100644 --- a/SysML2.NET.Tests/Extend/WhileLoopActionUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/WhileLoopActionUsageExtensionsTestFixture.cs @@ -1,44 +1,97 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // -// +// // 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.Core.Types; + using SysML2.NET.Core.POCO.Kernel.Expressions; using SysML2.NET.Core.POCO.Systems.Actions; + using SysML2.NET.Core.POCO.Systems.DefinitionAndUsage; + using SysML2.NET.Extensions; [TestFixture] public class WhileLoopActionUsageExtensionsTestFixture { [Test] - public void ComputeUntilArgument_ThrowsNotSupportedException() + public void VerifyComputeWhileArgument() { - Assert.That(() => ((IWhileLoopActionUsage)null).ComputeUntilArgument(), Throws.TypeOf()); + Assert.That(() => ((IWhileLoopActionUsage)null).ComputeWhileArgument(), Throws.TypeOf()); + + // No input parameters -> inputParameter(1) is out of range -> null. + Assert.That(new WhileLoopActionUsage().ComputeWhileArgument(), Is.Null); + + // Position-1 input parameter that IS an Expression -> returned via the as-cast. + var whileExpression = new LiteralInteger { Direction = FeatureDirectionKind.In }; + var subjectWithWhileArgument = new WhileLoopActionUsage(); + subjectWithWhileArgument.AssignOwnership(new FeatureMembership(), whileExpression); + + // Position-1 input parameter that is NOT an Expression -> the as-cast yields null. + var subjectWithNonExpressionFirstParameter = new WhileLoopActionUsage(); + subjectWithNonExpressionFirstParameter.AssignOwnership(new FeatureMembership(), new ReferenceUsage { Direction = FeatureDirectionKind.In }); + + using (Assert.EnterMultipleScope()) + { + // whileArgument = inputParameter(1) as Expression + Assert.That(subjectWithWhileArgument.ComputeWhileArgument(), Is.SameAs(whileExpression)); + Assert.That(subjectWithNonExpressionFirstParameter.ComputeWhileArgument(), Is.Null); + } } - + [Test] - public void ComputeWhileArgument_ThrowsNotSupportedException() + public void VerifyComputeUntilArgument() { - Assert.That(() => ((IWhileLoopActionUsage)null).ComputeWhileArgument(), Throws.TypeOf()); + Assert.That(() => ((IWhileLoopActionUsage)null).ComputeUntilArgument(), Throws.TypeOf()); + + // No input parameters -> inputParameter(3) is out of range -> null. + Assert.That(new WhileLoopActionUsage().ComputeUntilArgument(), Is.Null); + + // Only two input parameters -> inputParameter(3) is out of range -> null. + var subjectWithTwoParameters = new WhileLoopActionUsage(); + subjectWithTwoParameters.AssignOwnership(new FeatureMembership(), new LiteralInteger { Direction = FeatureDirectionKind.In }); + subjectWithTwoParameters.AssignOwnership(new FeatureMembership(), new LiteralInteger { Direction = FeatureDirectionKind.In }); + + // Three input parameters where position-3 IS an Expression -> returned via the as-cast. + var untilExpression = new LiteralInteger { Direction = FeatureDirectionKind.In }; + var subjectWithUntilArgument = new WhileLoopActionUsage(); + subjectWithUntilArgument.AssignOwnership(new FeatureMembership(), new LiteralInteger { Direction = FeatureDirectionKind.In }); + subjectWithUntilArgument.AssignOwnership(new FeatureMembership(), new LiteralInteger { Direction = FeatureDirectionKind.In }); + subjectWithUntilArgument.AssignOwnership(new FeatureMembership(), untilExpression); + + // Three input parameters where position-3 is NOT an Expression -> the as-cast yields null. + var subjectWithNonExpressionThirdParameter = new WhileLoopActionUsage(); + subjectWithNonExpressionThirdParameter.AssignOwnership(new FeatureMembership(), new LiteralInteger { Direction = FeatureDirectionKind.In }); + subjectWithNonExpressionThirdParameter.AssignOwnership(new FeatureMembership(), new LiteralInteger { Direction = FeatureDirectionKind.In }); + subjectWithNonExpressionThirdParameter.AssignOwnership(new FeatureMembership(), new ReferenceUsage { Direction = FeatureDirectionKind.In }); + + using (Assert.EnterMultipleScope()) + { + // untilArgument = inputParameter(3) as Expression + Assert.That(subjectWithUntilArgument.ComputeUntilArgument(), Is.SameAs(untilExpression)); + Assert.That(subjectWithTwoParameters.ComputeUntilArgument(), Is.Null); + Assert.That(subjectWithNonExpressionThirdParameter.ComputeUntilArgument(), Is.Null); + } } } } diff --git a/SysML2.NET/Extend/ForLoopActionUsageExtensions.cs b/SysML2.NET/Extend/ForLoopActionUsageExtensions.cs index f3d418fa..47e6939b 100644 --- a/SysML2.NET/Extend/ForLoopActionUsageExtensions.cs +++ b/SysML2.NET/Extend/ForLoopActionUsageExtensions.cs @@ -22,6 +22,7 @@ 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; @@ -84,10 +85,14 @@ internal static class ForLoopActionUsageExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IReferenceUsage ComputeLoopVariable(this IForLoopActionUsage forLoopActionUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (forLoopActionUsageSubject == null) + { + throw new ArgumentNullException(nameof(forLoopActionUsageSubject)); + } + + return forLoopActionUsageSubject.ownedFeature.FirstOrDefault() as IReferenceUsage; } /// @@ -105,10 +110,11 @@ internal static IReferenceUsage ComputeLoopVariable(this IForLoopActionUsage for /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IExpression ComputeSeqArgument(this IForLoopActionUsage forLoopActionUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + return forLoopActionUsageSubject == null + ? throw new ArgumentNullException(nameof(forLoopActionUsageSubject)) + : forLoopActionUsageSubject.Argument(1); } } diff --git a/SysML2.NET/Extend/LoopActionUsageExtensions.cs b/SysML2.NET/Extend/LoopActionUsageExtensions.cs index 729fd992..e055e378 100644 --- a/SysML2.NET/Extend/LoopActionUsageExtensions.cs +++ b/SysML2.NET/Extend/LoopActionUsageExtensions.cs @@ -84,10 +84,14 @@ internal static class LoopActionUsageExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IActionUsage ComputeBodyAction(this ILoopActionUsage loopActionUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (loopActionUsageSubject == null) + { + throw new ArgumentNullException(nameof(loopActionUsageSubject)); + } + + return loopActionUsageSubject.InputParameter(2) as IActionUsage; } } diff --git a/SysML2.NET/Extend/PerformActionUsageExtensions.cs b/SysML2.NET/Extend/PerformActionUsageExtensions.cs index fd823a26..93508cf0 100644 --- a/SysML2.NET/Extend/PerformActionUsageExtensions.cs +++ b/SysML2.NET/Extend/PerformActionUsageExtensions.cs @@ -72,10 +72,18 @@ internal static class PerformActionUsageExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IActionUsage ComputePerformedAction(this IPerformActionUsage performActionUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (performActionUsageSubject == null) + { + throw new ArgumentNullException(nameof(performActionUsageSubject)); + } + + var referencedFeatureTarget = performActionUsageSubject.ReferencedFeatureTarget(); + + return referencedFeatureTarget == null + ? performActionUsageSubject + : referencedFeatureTarget as IActionUsage; } /// @@ -97,10 +105,18 @@ internal static IActionUsage ComputePerformedAction(this IPerformActionUsage per /// /// The expected /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IFeature ComputeRedefinedNamingFeatureOperation(this IPerformActionUsage performActionUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (performActionUsageSubject == null) + { + throw new ArgumentNullException(nameof(performActionUsageSubject)); + } + + var performedAction = performActionUsageSubject.performedAction; + + return !ReferenceEquals(performedAction, performActionUsageSubject) + ? performedAction + : UsageExtensions.ComputeRedefinedNamingFeatureOperation(performActionUsageSubject); } } } diff --git a/SysML2.NET/Extend/WhileLoopActionUsageExtensions.cs b/SysML2.NET/Extend/WhileLoopActionUsageExtensions.cs index c89f1643..7ad13bd7 100644 --- a/SysML2.NET/Extend/WhileLoopActionUsageExtensions.cs +++ b/SysML2.NET/Extend/WhileLoopActionUsageExtensions.cs @@ -84,10 +84,11 @@ internal static class WhileLoopActionUsageExtensions /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IExpression ComputeUntilArgument(this IWhileLoopActionUsage whileLoopActionUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + return whileLoopActionUsageSubject == null + ? throw new ArgumentNullException(nameof(whileLoopActionUsageSubject)) + : whileLoopActionUsageSubject.InputParameter(3) as IExpression; } /// @@ -111,10 +112,11 @@ internal static IExpression ComputeUntilArgument(this IWhileLoopActionUsage whil /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IExpression ComputeWhileArgument(this IWhileLoopActionUsage whileLoopActionUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + return whileLoopActionUsageSubject == null + ? throw new ArgumentNullException(nameof(whileLoopActionUsageSubject)) + : whileLoopActionUsageSubject.InputParameter(1) as IExpression; } }