diff --git a/SysML2.NET.Tests/Extend/ReferenceUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ReferenceUsageExtensionsTestFixture.cs index 0dabebb5..28a7dda0 100644 --- a/SysML2.NET.Tests/Extend/ReferenceUsageExtensionsTestFixture.cs +++ b/SysML2.NET.Tests/Extend/ReferenceUsageExtensionsTestFixture.cs @@ -1,7 +1,7 @@ -// ------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------- // // -// Copyright 2022-2026 Starion Group S.A. +// Copyright (C) 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. @@ -21,18 +21,93 @@ 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.Core.POCO.Systems.Parts; + using SysML2.NET.Core.POCO.Systems.States; + using SysML2.NET.Core.Systems.States; + using SysML2.NET.Extensions; [TestFixture] public class ReferenceUsageExtensionsTestFixture { [Test] - public void ComputeIsReference_ThrowsNotSupportedException() + public void VerifyComputeIsReference() { - Assert.That(() => ((IReferenceUsage)null).ComputeIsReference(), Throws.TypeOf()); + Assert.That(() => ((IReferenceUsage)null).ComputeIsReference(), Throws.TypeOf()); + + // Any non-null IReferenceUsage returns true — this is a constant-true redefinition. + var referenceUsage = new ReferenceUsage(); + + Assert.That(referenceUsage.ComputeIsReference(), Is.True); + + // Even when IsComposite is set to true, the ReferenceUsage redefinition overrides + // the base Usage::isReference (= not isComposite) logic and still returns true. + var compositeReferenceUsage = new ReferenceUsage { IsComposite = true }; + + Assert.That(compositeReferenceUsage.ComputeIsReference(), Is.True); + } + + [Test] + public void VerifyComputeRedefinedNamingFeatureOperation() + { + Assert.That(() => ((IReferenceUsage)null).ComputeRedefinedNamingFeatureOperation(), Throws.TypeOf()); + + // Branch 1: owningType == null — no owning FeatureMembership → falls through to + // UsageExtensions.ComputeRedefinedNamingFeatureOperation → ComputeNamingFeatureOperation + // → null (no IRedefinition in OwnedRelationship on a bare ReferenceUsage). + var bareSubject = new ReferenceUsage(); + + Assert.That(bareSubject.ComputeRedefinedNamingFeatureOperation(), Is.Null); + + // Branch 2: owningType is a non-ITransitionUsage (PartUsage) → OCL condition + // owningType.oclIsKindOf(TransitionUsage) is false → falls through → null. + var partUsageOwner = new PartUsage(); + var subjectInPartUsage = new ReferenceUsage(); + partUsageOwner.AssignOwnership(new FeatureMembership(), subjectInPartUsage); + + Assert.That(subjectInPartUsage.ComputeRedefinedNamingFeatureOperation(), Is.Null); + + // Branch 3: owningType is an ITransitionUsage but self is NOT InputParameter(2). + // Only one input parameter is wired, so InputParameter(2) returns null (≠ self) → falls through → null. + var transitionUsageSingleParam = new TransitionUsage(); + var onlyParam = new ReferenceUsage { Direction = FeatureDirectionKind.In }; + transitionUsageSingleParam.AssignOwnership(new FeatureMembership(), onlyParam); + + Assert.That(onlyParam.ComputeRedefinedNamingFeatureOperation(), Is.Null); + + // Branch 4: owningType is an ITransitionUsage, self IS InputParameter(2), but + // triggerAction is empty → TriggerPayloadParameter() returns null → result is null. + var transitionUsageNoTrigger = new TransitionUsage(); + var firstParamNoTrigger = new ReferenceUsage { Direction = FeatureDirectionKind.In }; + var secondParamNoTrigger = new ReferenceUsage { Direction = FeatureDirectionKind.In }; + transitionUsageNoTrigger.AssignOwnership(new FeatureMembership(), firstParamNoTrigger); + transitionUsageNoTrigger.AssignOwnership(new FeatureMembership(), secondParamNoTrigger); + + Assert.That(secondParamNoTrigger.ComputeRedefinedNamingFeatureOperation(), Is.Null); + + // Branch 5: owningType is an ITransitionUsage, self IS InputParameter(2), and + // triggerAction is non-empty → TriggerPayloadParameter() accesses triggerAction[0].payloadParameter + // → AcceptActionUsage.parameter → StepExtensions.ComputeParameter, which is still a stub. + // Assert the stub propagates rather than silently returning the wrong value. + var transitionUsageWithTrigger = new TransitionUsage(); + var firstParamWithTrigger = new ReferenceUsage { Direction = FeatureDirectionKind.In }; + var secondParamWithTrigger = new ReferenceUsage { Direction = FeatureDirectionKind.In }; + transitionUsageWithTrigger.AssignOwnership(new FeatureMembership(), firstParamWithTrigger); + transitionUsageWithTrigger.AssignOwnership(new FeatureMembership(), secondParamWithTrigger); + + var triggerFeatureMembership = new TransitionFeatureMembership { Kind = TransitionFeatureKind.Trigger }; + var triggerAcceptAction = new AcceptActionUsage(); + transitionUsageWithTrigger.AssignOwnership(triggerFeatureMembership, triggerAcceptAction); + + Assert.That( + () => secondParamWithTrigger.ComputeRedefinedNamingFeatureOperation(), + Throws.TypeOf()); } } } diff --git a/SysML2.NET/Extend/ReferenceUsageExtensions.cs b/SysML2.NET/Extend/ReferenceUsageExtensions.cs index 7f6a98f8..4026cfec 100644 --- a/SysML2.NET/Extend/ReferenceUsageExtensions.cs +++ b/SysML2.NET/Extend/ReferenceUsageExtensions.cs @@ -1,61 +1,33 @@ // ------------------------------------------------------------------------------------------------- // -// -// Copyright (C) 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 -// +// +// Copyright (C) 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.Core.POCO.Systems.DefinitionAndUsage { using System; - using System.Collections.Generic; - 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.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.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.Requirements; 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 - /// the interface + /// The class provides extensions methods for + /// the interface /// internal static class ReferenceUsageExtensions { @@ -63,15 +35,19 @@ internal static class ReferenceUsageExtensions /// Computes the derived property. /// /// - /// The subject + /// The subject /// /// /// the computed result /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static bool ComputeIsReference(this IReferenceUsage referenceUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (referenceUsageSubject == null) + { + throw new ArgumentNullException(nameof(referenceUsageSubject)); + } + + return true; } /// @@ -89,15 +65,25 @@ internal static bool ComputeIsReference(this IReferenceUsage referenceUsageSubje /// /// /// - /// The subject + /// The subject /// /// /// The expected /// - [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal static IFeature ComputeRedefinedNamingFeatureOperation(this IReferenceUsage referenceUsageSubject) { - throw new NotSupportedException("Create a GitHub issue when this method is required"); + if (referenceUsageSubject == null) + { + throw new ArgumentNullException(nameof(referenceUsageSubject)); + } + + if (referenceUsageSubject.owningType is ITransitionUsage transitionUsage + && transitionUsage.InputParameter(2) == referenceUsageSubject) + { + return transitionUsage.TriggerPayloadParameter(); + } + + return UsageExtensions.ComputeRedefinedNamingFeatureOperation(referenceUsageSubject); } } }