diff --git a/CLAUDE.md b/CLAUDE.md
index 18c5b0f5..3fcd2f47 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -142,6 +142,7 @@ Auto-generated DTOs use structured namespaces reflecting the KerML/SysML package
## Key Conventions
+- **Paths are ALWAYS repo-relative — NEVER absolute.** This rule applies to every path the agent writes anywhere: code comments, XML doc `` and prose, source-string citations, error/log messages, commit messages, PR bodies, GitHub issue bodies, `.team-notes/` spec files, plan files, skill prompts and agent briefs (e.g. say `SysML2.NET/Extend/FooExtensions.cs`, NOT `C:\CODE\SysML2.NET\SysML2.NET\Extend\FooExtensions.cs` and NOT `/c/CODE/SysML2.NET/...`). Use forward slashes. Reason: absolute paths are user-/machine-specific and leak the local filesystem into the repo and into communication with other contributors — they break for anyone else, get stale on rename/move, and are noisy. The ONLY exception is the `Read` / `Edit` / `Write` tool `file_path` parameter, which the tool implementation requires to be absolute — those tool arguments are not user-visible artifacts. Everything you author as content must be repo-relative.
- Commit messages use prefix tags: `[Add]`, `[Update]`, `[Remove]`, `[Fix]` — except for issue-fixing commits produced by `/implement-extensions` and `/implement-extensions-batch`, which use the canonical short form `Fix #` (single issue) or `Fix # # …` (batch) so GitHub auto-closes the issues on merge.
- Main branch: `master`. Development branch: `development`. **All feature work targets `development`** via PR; `master` is downstream only.
- CI: GitHub Actions (`CodeQuality.yml`) — builds, tests, and runs SonarQube analysis
diff --git a/SysML2.NET.Tests/Extend/RenderingDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/RenderingDefinitionExtensionsTestFixture.cs
index dba4cacc..4ce2c853 100644
--- a/SysML2.NET.Tests/Extend/RenderingDefinitionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/RenderingDefinitionExtensionsTestFixture.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.POCO.Core.Types;
+ using SysML2.NET.Core.POCO.Systems.Parts;
using SysML2.NET.Core.POCO.Systems.Views;
+ using SysML2.NET.Extensions;
[TestFixture]
public class RenderingDefinitionExtensionsTestFixture
{
[Test]
- public void ComputeRendering_ThrowsNotSupportedException()
+ public void VerifyComputeRendering()
{
- Assert.That(() => ((IRenderingDefinition)null).ComputeRendering(), Throws.TypeOf());
+ Assert.That(() => ((IRenderingDefinition)null).ComputeRendering(), Throws.TypeOf());
+
+ var renderingDefinition = new RenderingDefinition();
+
+ // Empty: no usages wired → empty result.
+ Assert.That(renderingDefinition.ComputeRendering(), Is.Empty);
+
+ // Discrimination: PartUsage in usage (not IRenderingUsage) → excluded.
+ var partUsage = new PartUsage();
+ renderingDefinition.AssignOwnership(new FeatureMembership(), partUsage);
+
+ Assert.That(renderingDefinition.ComputeRendering(), Is.Empty);
+
+ // Positive: RenderingUsage wired via FeatureMembership → appears in usage → included.
+ var renderingUsage = new RenderingUsage();
+ renderingDefinition.AssignOwnership(new FeatureMembership(), renderingUsage);
+
+ Assert.That(renderingDefinition.ComputeRendering(), Is.EqualTo([renderingUsage]));
+
+ // Multiple: second RenderingUsage also returned.
+ var renderingUsage2 = new RenderingUsage();
+ renderingDefinition.AssignOwnership(new FeatureMembership(), renderingUsage2);
+
+ Assert.That(renderingDefinition.ComputeRendering(), Is.EqualTo([renderingUsage, renderingUsage2]));
}
}
}
diff --git a/SysML2.NET.Tests/Extend/RenderingUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/RenderingUsageExtensionsTestFixture.cs
index 08c0a25c..2576441b 100644
--- a/SysML2.NET.Tests/Extend/RenderingUsageExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/RenderingUsageExtensionsTestFixture.cs
@@ -1,38 +1,67 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
-//
+//
// 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.Parts;
using SysML2.NET.Core.POCO.Systems.Views;
+ using SysML2.NET.Extensions;
[TestFixture]
public class RenderingUsageExtensionsTestFixture
{
[Test]
- public void ComputeRenderingDefinition_ThrowsNotSupportedException()
+ public void VerifyComputeRenderingDefinition()
{
- Assert.That(() => ((IRenderingUsage)null).ComputeRenderingDefinition(), Throws.TypeOf());
+ Assert.That(() => ((IRenderingUsage)null).ComputeRenderingDefinition(), Throws.TypeOf());
+
+ var renderingUsage = new RenderingUsage();
+
+ // Empty: no OwnedRelationship → null.
+ Assert.That(renderingUsage.ComputeRenderingDefinition(), Is.Null);
+
+ // Negative: FeatureTyping whose Type is a non-RenderingDefinition (PartDefinition) → null.
+ var partDefinition = new PartDefinition();
+ var typingToPartDefinition = new FeatureTyping { Type = partDefinition };
+ renderingUsage.AssignOwnership(typingToPartDefinition);
+
+ Assert.That(renderingUsage.ComputeRenderingDefinition(), Is.Null);
+
+ // Positive: FeatureTyping whose Type is a RenderingDefinition → returned.
+ var renderingDefinition = new RenderingDefinition();
+ var typingToRenderingDefinition = new FeatureTyping { Type = renderingDefinition };
+ renderingUsage.AssignOwnership(typingToRenderingDefinition);
+
+ Assert.That(renderingUsage.ComputeRenderingDefinition(), Is.SameAs(renderingDefinition));
+
+ // Multiple: second RenderingDefinition typing present; FirstOrDefault returns the first match.
+ var renderingDefinition2 = new RenderingDefinition();
+ var typingToRenderingDefinition2 = new FeatureTyping { Type = renderingDefinition2 };
+ renderingUsage.AssignOwnership(typingToRenderingDefinition2);
+
+ Assert.That(renderingUsage.ComputeRenderingDefinition(), Is.SameAs(renderingDefinition));
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ViewDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewDefinitionExtensionsTestFixture.cs
index cf64bd5f..9ba97979 100644
--- a/SysML2.NET.Tests/Extend/ViewDefinitionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ViewDefinitionExtensionsTestFixture.cs
@@ -1,56 +1,162 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
-//
+//
// 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.Functions;
+ using SysML2.NET.Core.POCO.Kernel.Packages;
+ 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.Views;
+ using SysML2.NET.Extensions;
[TestFixture]
public class ViewDefinitionExtensionsTestFixture
{
[Test]
- public void ComputeSatisfiedViewpoint_ThrowsNotSupportedException()
+ public void VerifyComputeSatisfiedViewpoint()
{
- Assert.That(() => ((IViewDefinition)null).ComputeSatisfiedViewpoint(), Throws.TypeOf());
+ Assert.That(() => ((IViewDefinition)null).ComputeSatisfiedViewpoint(), Throws.TypeOf());
+
+ var viewDefinition = new ViewDefinition();
+
+ // Empty: no ownedRequirement → empty result.
+ Assert.That(viewDefinition.ComputeSatisfiedViewpoint(), Is.Empty);
+
+ // Discrimination: plain RequirementUsage (not IViewpointUsage) → excluded.
+ var plainRequirement = new RequirementUsage { IsComposite = true };
+ viewDefinition.AssignOwnership(new FeatureMembership(), plainRequirement);
+
+ Assert.That(viewDefinition.ComputeSatisfiedViewpoint(), Is.Empty);
+
+ // Predicate discrimination: ViewpointUsage with IsComposite = false → excluded.
+ var nonCompositeViewpoint = new ViewpointUsage { IsComposite = false };
+ viewDefinition.AssignOwnership(new FeatureMembership(), nonCompositeViewpoint);
+
+ Assert.That(viewDefinition.ComputeSatisfiedViewpoint(), Is.Empty);
+
+ // Positive: composite ViewpointUsage → included.
+ var compositeViewpoint = new ViewpointUsage { IsComposite = true };
+ viewDefinition.AssignOwnership(new FeatureMembership(), compositeViewpoint);
+
+ Assert.That(viewDefinition.ComputeSatisfiedViewpoint(), Is.EqualTo([compositeViewpoint]));
+
+ // Multiple: second composite ViewpointUsage also returned in iteration order.
+ var compositeViewpoint2 = new ViewpointUsage { IsComposite = true };
+ viewDefinition.AssignOwnership(new FeatureMembership(), compositeViewpoint2);
+
+ Assert.That(viewDefinition.ComputeSatisfiedViewpoint(), Is.EqualTo([compositeViewpoint, compositeViewpoint2]));
}
-
+
[Test]
- public void ComputeView_ThrowsNotSupportedException()
+ public void VerifyComputeView()
{
- Assert.That(() => ((IViewDefinition)null).ComputeView(), Throws.TypeOf());
+ Assert.That(() => ((IViewDefinition)null).ComputeView(), Throws.TypeOf());
+
+ var viewDefinition = new ViewDefinition();
+
+ // Empty: no usages → empty result.
+ Assert.That(viewDefinition.ComputeView(), Is.Empty);
+
+ // Discrimination: PartUsage in usage (not IViewUsage) → excluded.
+ var partUsage = new PartUsage();
+ viewDefinition.AssignOwnership(new FeatureMembership(), partUsage);
+
+ Assert.That(viewDefinition.ComputeView(), Is.Empty);
+
+ // Positive: ViewUsage → included.
+ var viewUsage = new ViewUsage();
+ viewDefinition.AssignOwnership(new FeatureMembership(), viewUsage);
+
+ Assert.That(viewDefinition.ComputeView(), Is.EqualTo([viewUsage]));
+
+ // Multiple: second ViewUsage also returned.
+ var viewUsage2 = new ViewUsage();
+ viewDefinition.AssignOwnership(new FeatureMembership(), viewUsage2);
+
+ Assert.That(viewDefinition.ComputeView(), Is.EqualTo([viewUsage, viewUsage2]));
}
-
+
[Test]
- public void ComputeViewCondition_ThrowsNotSupportedException()
+ public void VerifyComputeViewCondition()
{
- Assert.That(() => ((IViewDefinition)null).ComputeViewCondition(), Throws.TypeOf());
+ Assert.That(() => ((IViewDefinition)null).ComputeViewCondition(), Throws.TypeOf());
+
+ var viewDefinition = new ViewDefinition();
+
+ // Empty: no ownedMembership → empty result.
+ Assert.That(viewDefinition.ComputeViewCondition(), Is.Empty);
+
+ // Discrimination: non-ElementFilterMembership in ownedMembership → excluded.
+ var plainFeature = new Feature();
+ var plainMembership = new OwningMembership();
+ viewDefinition.AssignOwnership(plainMembership, plainFeature);
+
+ Assert.That(viewDefinition.ComputeViewCondition(), Is.Empty);
+
+ // Positive: ElementFilterMembership with a concrete IExpression → condition included.
+ var filterCondition = new BooleanExpression();
+ var filterMembership = new ElementFilterMembership();
+ viewDefinition.AssignOwnership(filterMembership, filterCondition);
+
+ Assert.That(viewDefinition.ComputeViewCondition(), Is.EqualTo([filterCondition]));
}
-
+
[Test]
- public void ComputeViewRendering_ThrowsNotSupportedException()
+ public void VerifyComputeViewRendering()
{
- Assert.That(() => ((IViewDefinition)null).ComputeViewRendering(), Throws.TypeOf());
+ Assert.That(() => ((IViewDefinition)null).ComputeViewRendering(), Throws.TypeOf());
+
+ var viewDefinition = new ViewDefinition();
+
+ // Empty: no featureMembership → null.
+ Assert.That(viewDefinition.ComputeViewRendering(), Is.Null);
+
+ // Discrimination: non-ViewRenderingMembership featureMembership → null.
+ var plainFeature = new Feature();
+ var plainFeatureMembership = new FeatureMembership();
+ viewDefinition.AssignOwnership(plainFeatureMembership, plainFeature);
+
+ Assert.That(viewDefinition.ComputeViewRendering(), Is.Null);
+
+ // Positive: ViewRenderingMembership whose ownedRendering is a RenderingUsage (no
+ // ownedReferenceSubsetting) → referencedRendering == ownedRendering → returned.
+ var renderingUsage = new RenderingUsage();
+ var viewRenderingMembership = new ViewRenderingMembership();
+ viewDefinition.AssignOwnership(viewRenderingMembership, renderingUsage);
+
+ Assert.That(viewDefinition.ComputeViewRendering(), Is.SameAs(renderingUsage));
+
+ // Multiple ViewRenderingMemberships: the first one wins (renderings->first() semantics).
+ var renderingUsage2 = new RenderingUsage();
+ var viewRenderingMembership2 = new ViewRenderingMembership();
+ viewDefinition.AssignOwnership(viewRenderingMembership2, renderingUsage2);
+
+ Assert.That(viewDefinition.ComputeViewRendering(), Is.SameAs(renderingUsage));
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ViewRenderingMembershipExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewRenderingMembershipExtensionsTestFixture.cs
index a3cbef04..0a6a5c4c 100644
--- a/SysML2.NET.Tests/Extend/ViewRenderingMembershipExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ViewRenderingMembershipExtensionsTestFixture.cs
@@ -1,44 +1,131 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
-//
+//
// 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.Views;
+ using SysML2.NET.Exceptions;
+ using SysML2.NET.Extensions;
[TestFixture]
public class ViewRenderingMembershipExtensionsTestFixture
{
[Test]
- public void ComputeOwnedRendering_ThrowsNotSupportedException()
+ public void VerifyComputeOwnedRendering()
{
- Assert.That(() => ((IViewRenderingMembership)null).ComputeOwnedRendering(), Throws.TypeOf());
+ Assert.That(() => ((IViewRenderingMembership)null).ComputeOwnedRendering(), Throws.TypeOf());
+
+ // Empty OwnedRelatedElement → [1..1] violation: throws IncompleteModelException.
+ var emptyMembership = new ViewRenderingMembership();
+
+ Assert.That(() => emptyMembership.ComputeOwnedRendering(), Throws.TypeOf());
+
+ // Single non-IRenderingUsage in OwnedRelatedElement (zero matches of target type) →
+ // [1..1] violation: throws IncompleteModelException.
+ var nonRenderingMembership = new ViewRenderingMembership();
+ var nonRenderingElement = new Namespace();
+ ((IContainedRelationship)nonRenderingMembership).OwnedRelatedElement.Add(nonRenderingElement);
+
+ Assert.That(() => nonRenderingMembership.ComputeOwnedRendering(), Throws.TypeOf());
+
+ // Single IRenderingUsage wired via parent → returned.
+ var owningDefinition = new ViewDefinition();
+ var renderingMembership = new ViewRenderingMembership();
+ var renderingUsage = new RenderingUsage();
+ owningDefinition.AssignOwnership(renderingMembership, renderingUsage);
+
+ Assert.That(renderingMembership.ComputeOwnedRendering(), Is.SameAs(renderingUsage));
+
+ // Two IRenderingUsage in OwnedRelatedElement → [1..1] violation: throws IncompleteModelException.
+ var twoRenderingMembership = new ViewRenderingMembership();
+ var firstRendering = new RenderingUsage();
+ var secondRendering = new RenderingUsage();
+ ((IContainedRelationship)twoRenderingMembership).OwnedRelatedElement.Add(firstRendering);
+ ((IContainedRelationship)twoRenderingMembership).OwnedRelatedElement.Add(secondRendering);
+
+ Assert.That(() => twoRenderingMembership.ComputeOwnedRendering(), Throws.TypeOf());
+
+ // Mixed: annotation (Namespace) alongside a single IRenderingUsage — the type filter
+ // picks out the RenderingUsage regardless of its position.
+ var mixedMembership = new ViewRenderingMembership();
+ var siblingNamespace = new Namespace();
+ var mixedRendering = new RenderingUsage();
+ ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(siblingNamespace);
+ ((IContainedRelationship)mixedMembership).OwnedRelatedElement.Add(mixedRendering);
+
+ Assert.That(mixedMembership.ComputeOwnedRendering(), Is.SameAs(mixedRendering));
}
-
+
[Test]
- public void ComputeReferencedRendering_ThrowsNotSupportedException()
+ public void VerifyComputeReferencedRendering()
{
- Assert.That(() => ((IViewRenderingMembership)null).ComputeReferencedRendering(), Throws.TypeOf());
+ Assert.That(() => ((IViewRenderingMembership)null).ComputeReferencedRendering(), Throws.TypeOf());
+
+ // No ownedRendering in OwnedRelatedElement (malformed) → IncompleteModelException
+ // propagated from ComputeOwnedRendering.
+ var emptyMembership = new ViewRenderingMembership();
+
+ Assert.That(() => emptyMembership.ComputeReferencedRendering(), Throws.TypeOf());
+
+ // Populated, no ownedReferenceSubsetting on the ownedRendering →
+ // referencedFeature is null → referencedRendering == ownedRendering.
+ var owningDefinition = new ViewDefinition();
+ var renderingMembership = new ViewRenderingMembership();
+ var renderingUsage = new RenderingUsage();
+ owningDefinition.AssignOwnership(renderingMembership, renderingUsage);
+
+ Assert.That(renderingMembership.ComputeReferencedRendering(), Is.SameAs(renderingUsage));
+
+ // Populated, with ownedReferenceSubsetting whose ReferencedFeature is itself a
+ // RenderingUsage → referencedRendering == that RenderingUsage.
+ var owningDefinition2 = new ViewDefinition();
+ var renderingMembership2 = new ViewRenderingMembership();
+ var ownedRenderingUsage = new RenderingUsage();
+ owningDefinition2.AssignOwnership(renderingMembership2, ownedRenderingUsage);
+
+ var referencedRenderingUsage = new RenderingUsage();
+ var referenceSubsetting = new ReferenceSubsetting { ReferencedFeature = referencedRenderingUsage };
+ ownedRenderingUsage.AssignOwnership(referenceSubsetting);
+
+ Assert.That(renderingMembership2.ComputeReferencedRendering(), Is.SameAs(referencedRenderingUsage));
+
+ // Populated, with ownedReferenceSubsetting whose ReferencedFeature is a non-RenderingUsage
+ // Feature → referencedRendering is null (else null branch of the OCL).
+ var owningDefinition3 = new ViewDefinition();
+ var renderingMembership3 = new ViewRenderingMembership();
+ var ownedRenderingUsage3 = new RenderingUsage();
+ owningDefinition3.AssignOwnership(renderingMembership3, ownedRenderingUsage3);
+
+ var partUsageTarget = new PartUsage();
+ var referenceSubsetting3 = new ReferenceSubsetting { ReferencedFeature = partUsageTarget };
+ ownedRenderingUsage3.AssignOwnership(referenceSubsetting3);
+
+ Assert.That(renderingMembership3.ComputeReferencedRendering(), Is.Null);
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs
index 731f6308..332d594c 100644
--- a/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs
@@ -76,7 +76,7 @@ public void VerifyComputeIncludeAsExposedOperation()
var element = new Feature();
- // Case (a) — empty conditions: ViewUsage has no ElementFilterMembership in membership;
+ // Case (a) — empty conditions: ViewUsage has no ElementFilterMembership in membership =>
// forAll over empty sequence is vacuously true → returns true.
Assert.That(viewUsage.ComputeIncludeAsExposedOperation(element), Is.True);
@@ -94,7 +94,7 @@ public void VerifyComputeIncludeAsExposedOperation()
// false → metadataFeatures.Any(cond.CheckCondition) is false → forAll fails →
// element is excluded → returns false.
// Note: AnnotationExtensions.ComputeAnnotatingElement remains a NotSupportedException
- // stub (C:\CODE\SysML2.NET\SysML2.NET\Extend\AnnotationExtensions.cs), but it is not
+ // stub (SysML2.NET\SysML2.NET\Extend\AnnotationExtensions.cs), but it is not
// reached here because element.ownedAnnotation is empty.
var filterCondition = new BooleanExpression();
var filterMembership = new ElementFilterMembership();
@@ -217,15 +217,14 @@ public void VerifyComputeViewRendering()
Assert.That(viewUsage.ComputeViewRendering(), Is.Null);
- // STUB-BLOCKER: Wiring a ViewRenderingMembership and reading its referencedRendering
- // property dispatches to ViewRenderingMembershipExtensions.ComputeReferencedRendering,
- // which is a NotSupportedException stub. The populated positive case cannot be tested
- // cleanly until that upstream stub is implemented.
+ // Populated: a ViewRenderingMembership whose ownedRendering is a RenderingUsage and
+ // which has no ownedReferenceSubsetting → ViewRenderingMembership.referencedRendering
+ // falls back to ownedRendering, so the result is that same RenderingUsage.
var renderingUsage = new RenderingUsage();
var viewRenderingMembership = new ViewRenderingMembership();
viewUsage.AssignOwnership(viewRenderingMembership, renderingUsage);
- Assert.That(() => viewUsage.ComputeViewRendering(), Throws.TypeOf());
+ Assert.That(viewUsage.ComputeViewRendering(), Is.SameAs(renderingUsage));
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs
index 8134b1b3..1903b971 100644
--- a/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ViewpointDefinitionExtensionsTestFixture.cs
@@ -1,38 +1,54 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
-//
+//
// 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.Systems.Requirements;
using SysML2.NET.Core.POCO.Systems.Views;
+ using SysML2.NET.Extensions;
[TestFixture]
public class ViewpointDefinitionExtensionsTestFixture
{
[Test]
- public void ComputeViewpointStakeholder_ThrowsNotSupportedException()
+ public void VerifyComputeViewpointStakeholder()
{
- Assert.That(() => ((IViewpointDefinition)null).ComputeViewpointStakeholder(), Throws.TypeOf());
+ Assert.That(() => ((IViewpointDefinition)null).ComputeViewpointStakeholder(), Throws.TypeOf());
+
+ var viewpointDefinition = new ViewpointDefinition();
+
+ // 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.
+ var framedMembership = new FramedConcernMembership();
+ var concernUsage = new ConcernUsage();
+ viewpointDefinition.AssignOwnership(framedMembership, concernUsage);
+
+ Assert.That(() => viewpointDefinition.ComputeViewpointStakeholder(), Throws.TypeOf());
}
}
}
diff --git a/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs
index 6beade63..0250100c 100644
--- a/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ViewpointUsageExtensionsTestFixture.cs
@@ -1,44 +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.Core.Types;
+ using SysML2.NET.Core.POCO.Systems.Constraints;
+ using SysML2.NET.Core.POCO.Systems.Requirements;
using SysML2.NET.Core.POCO.Systems.Views;
+ using SysML2.NET.Extensions;
[TestFixture]
public class ViewpointUsageExtensionsTestFixture
{
[Test]
- public void ComputeViewpointDefinition_ThrowsNotSupportedException()
+ public void VerifyComputeViewpointDefinition()
{
- Assert.That(() => ((IViewpointUsage)null).ComputeViewpointDefinition(), Throws.TypeOf());
+ Assert.That(() => ((IViewpointUsage)null).ComputeViewpointDefinition(), Throws.TypeOf());
+
+ var viewpointUsage = new ViewpointUsage();
+
+ // Empty: no OwnedRelationship → null.
+ Assert.That(viewpointUsage.ComputeViewpointDefinition(), Is.Null);
+
+ // Negative: FeatureTyping whose Type is a non-ViewpointDefinition (Feature) → null.
+ var nonViewpointType = new Feature();
+ var typingToNonViewpoint = new FeatureTyping { Type = nonViewpointType };
+ viewpointUsage.AssignOwnership(typingToNonViewpoint);
+
+ Assert.That(viewpointUsage.ComputeViewpointDefinition(), Is.Null);
+
+ // Positive: FeatureTyping whose Type is a ViewpointDefinition → returned.
+ var viewpointDefinition = new ViewpointDefinition();
+ var typingToViewpointDefinition = new FeatureTyping { Type = viewpointDefinition };
+ viewpointUsage.AssignOwnership(typingToViewpointDefinition);
+
+ Assert.That(viewpointUsage.ComputeViewpointDefinition(), Is.SameAs(viewpointDefinition));
+
+ // Multiple typings: second ViewpointDefinition present; FirstOrDefault returns the first match.
+ var viewpointDefinition2 = new ViewpointDefinition();
+ var typingToViewpointDefinition2 = new FeatureTyping { Type = viewpointDefinition2 };
+ viewpointUsage.AssignOwnership(typingToViewpointDefinition2);
+
+ Assert.That(viewpointUsage.ComputeViewpointDefinition(), Is.SameAs(viewpointDefinition));
}
-
+
[Test]
- public void ComputeViewpointStakeholder_ThrowsNotSupportedException()
+ public void VerifyComputeViewpointStakeholder()
{
- Assert.That(() => ((IViewpointUsage)null).ComputeViewpointStakeholder(), Throws.TypeOf());
+ Assert.That(() => ((IViewpointUsage)null).ComputeViewpointStakeholder(), Throws.TypeOf());
+
+ var viewpointUsage = new ViewpointUsage();
+
+ // 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.
+ var framedMembership = new FramedConcernMembership();
+ var concernUsage = new ConcernUsage();
+ viewpointUsage.AssignOwnership(framedMembership, concernUsage);
+
+ Assert.That(() => viewpointUsage.ComputeViewpointStakeholder(), Throws.TypeOf());
}
}
}
diff --git a/SysML2.NET/Extend/RenderingDefinitionExtensions.cs b/SysML2.NET/Extend/RenderingDefinitionExtensions.cs
index 25a96c1b..b45ba763 100644
--- a/SysML2.NET/Extend/RenderingDefinitionExtensions.cs
+++ b/SysML2.NET/Extend/RenderingDefinitionExtensions.cs
@@ -22,6 +22,7 @@ namespace SysML2.NET.Core.POCO.Systems.Views
{
using System;
using System.Collections.Generic;
+ using System.Linq;
using SysML2.NET.Core.Core.Types;
using SysML2.NET.Core.Root.Namespaces;
@@ -74,10 +75,11 @@ internal static class RenderingDefinitionExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeRendering(this IRenderingDefinition renderingDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return renderingDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(renderingDefinitionSubject))
+ : [..renderingDefinitionSubject.usage.OfType()];
}
}
diff --git a/SysML2.NET/Extend/RenderingUsageExtensions.cs b/SysML2.NET/Extend/RenderingUsageExtensions.cs
index e2423955..5da2be50 100644
--- a/SysML2.NET/Extend/RenderingUsageExtensions.cs
+++ b/SysML2.NET/Extend/RenderingUsageExtensions.cs
@@ -22,6 +22,7 @@ namespace SysML2.NET.Core.POCO.Systems.Views
{
using System;
using System.Collections.Generic;
+ using System.Linq;
using SysML2.NET.Core.Core.Types;
using SysML2.NET.Core.Root.Namespaces;
@@ -71,10 +72,15 @@ internal static class RenderingUsageExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IRenderingDefinition ComputeRenderingDefinition(this IRenderingUsage renderingUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return renderingUsageSubject == null
+ ? throw new ArgumentNullException(nameof(renderingUsageSubject))
+ : renderingUsageSubject.OwnedRelationship
+ .OfType()
+ .Select(featureTyping => featureTyping.Type)
+ .OfType()
+ .FirstOrDefault();
}
}
diff --git a/SysML2.NET/Extend/ViewDefinitionExtensions.cs b/SysML2.NET/Extend/ViewDefinitionExtensions.cs
index 348f6912..733d9144 100644
--- a/SysML2.NET/Extend/ViewDefinitionExtensions.cs
+++ b/SysML2.NET/Extend/ViewDefinitionExtensions.cs
@@ -22,6 +22,7 @@ namespace SysML2.NET.Core.POCO.Systems.Views
{
using System;
using System.Collections.Generic;
+ using System.Linq;
using SysML2.NET.Core.Core.Types;
using SysML2.NET.Core.Root.Namespaces;
@@ -29,6 +30,7 @@ namespace SysML2.NET.Core.POCO.Systems.Views
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Kernel.Functions;
+ using SysML2.NET.Core.POCO.Kernel.Packages;
using SysML2.NET.Core.POCO.Root.Annotations;
using SysML2.NET.Core.POCO.Root.Elements;
using SysML2.NET.Core.POCO.Root.Namespaces;
@@ -77,10 +79,11 @@ internal static class ViewDefinitionExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeSatisfiedViewpoint(this IViewDefinition viewDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(viewDefinitionSubject))
+ : [..viewDefinitionSubject.ownedRequirement.OfType().Where(viewpointUsage => viewpointUsage.IsComposite)];
}
///
@@ -98,10 +101,11 @@ internal static List ComputeSatisfiedViewpoint(this IViewDefini
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeView(this IViewDefinition viewDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(viewDefinitionSubject))
+ : [..viewDefinitionSubject.usage.OfType()];
}
///
@@ -121,10 +125,16 @@ internal static List ComputeView(this IViewDefinition viewDefinition
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeViewCondition(this IViewDefinition viewDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(viewDefinitionSubject))
+ : [
+ ..viewDefinitionSubject.ownedMembership
+ .OfType()
+ .Select(elementFilterMembership => elementFilterMembership.condition)
+ .Where(condition => condition != null)
+ ];
}
///
@@ -147,10 +157,16 @@ internal static List ComputeViewCondition(this IViewDefinition view
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IRenderingUsage ComputeViewRendering(this IViewDefinition viewDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ if (viewDefinitionSubject == null)
+ {
+ throw new ArgumentNullException(nameof(viewDefinitionSubject));
+ }
+
+ var renderings = viewDefinitionSubject.featureMembership.OfType().ToList();
+
+ return renderings.Count == 0 ? null : renderings[0].referencedRendering;
}
}
diff --git a/SysML2.NET/Extend/ViewRenderingMembershipExtensions.cs b/SysML2.NET/Extend/ViewRenderingMembershipExtensions.cs
index 2e799cd4..277f53d5 100644
--- a/SysML2.NET/Extend/ViewRenderingMembershipExtensions.cs
+++ b/SysML2.NET/Extend/ViewRenderingMembershipExtensions.cs
@@ -22,8 +22,10 @@ namespace SysML2.NET.Core.POCO.Systems.Views
{
using System;
using System.Collections.Generic;
+ using System.Linq;
using SysML2.NET.Core.Root.Namespaces;
+ using SysML2.NET.Extensions;
using SysML2.NET.Core.POCO.Core.Features;
using SysML2.NET.Core.POCO.Core.Types;
using SysML2.NET.Core.POCO.Root.Annotations;
@@ -45,25 +47,55 @@ internal static class ViewRenderingMembershipExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IRenderingUsage ComputeOwnedRendering(this IViewRenderingMembership viewRenderingMembershipSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ if (viewRenderingMembershipSubject == null)
+ {
+ throw new ArgumentNullException(nameof(viewRenderingMembershipSubject));
+ }
+
+ return viewRenderingMembershipSubject.OwnedRelatedElement.RequireSingleOfType(nameof(viewRenderingMembershipSubject));
}
///
/// Computes the derived property.
///
+ ///
+ /// OCL2.0:
+ ///
+ /// referencedRendering =
+ /// let referencedFeature : Feature =
+ /// ownedRendering.referencedFeatureTarget() in
+ /// if referencedFeature = null then ownedRendering
+ /// else if referencedFeature.oclIsKindOf(RenderingUsage) then
+ /// refrencedFeature.oclAsType(RenderingUsage)
+ /// else null
+ /// endif endif
+ ///
+ ///
///
/// The subject
///
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IRenderingUsage ComputeReferencedRendering(this IViewRenderingMembership viewRenderingMembershipSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ if (viewRenderingMembershipSubject == null)
+ {
+ throw new ArgumentNullException(nameof(viewRenderingMembershipSubject));
+ }
+
+ var ownedRendering = viewRenderingMembershipSubject.ownedRendering;
+
+ var referencedFeature = ownedRendering?.ReferencedFeatureTarget();
+
+ if (referencedFeature == null)
+ {
+ return ownedRendering;
+ }
+
+ return referencedFeature as IRenderingUsage;
}
}
diff --git a/SysML2.NET/Extend/ViewpointDefinitionExtensions.cs b/SysML2.NET/Extend/ViewpointDefinitionExtensions.cs
index 5058444b..127a26b1 100644
--- a/SysML2.NET/Extend/ViewpointDefinitionExtensions.cs
+++ b/SysML2.NET/Extend/ViewpointDefinitionExtensions.cs
@@ -22,6 +22,7 @@ namespace SysML2.NET.Core.POCO.Systems.Views
{
using System;
using System.Collections.Generic;
+ using System.Linq;
using SysML2.NET.Core.Core.Types;
using SysML2.NET.Core.Root.Namespaces;
@@ -78,10 +79,17 @@ internal static class ViewpointDefinitionExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeViewpointStakeholder(this IViewpointDefinition viewpointDefinitionSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ // The OCL uses "featureMemberhsip" which is a typo in the XMI source; the correct C# property is featureMembership.
+ return viewpointDefinitionSubject == null
+ ? throw new ArgumentNullException(nameof(viewpointDefinitionSubject))
+ : [
+ ..viewpointDefinitionSubject.framedConcern
+ .SelectMany(concern => concern.featureMembership)
+ .OfType()
+ .Select(stakeholderMembership => stakeholderMembership.ownedStakeholderParameter)
+ ];
}
}
diff --git a/SysML2.NET/Extend/ViewpointUsageExtensions.cs b/SysML2.NET/Extend/ViewpointUsageExtensions.cs
index 0165ae27..2662b0da 100644
--- a/SysML2.NET/Extend/ViewpointUsageExtensions.cs
+++ b/SysML2.NET/Extend/ViewpointUsageExtensions.cs
@@ -22,6 +22,7 @@ namespace SysML2.NET.Core.POCO.Systems.Views
{
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 ViewpointUsageExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IViewpointDefinition ComputeViewpointDefinition(this IViewpointUsage viewpointUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewpointUsageSubject == null
+ ? throw new ArgumentNullException(nameof(viewpointUsageSubject))
+ : viewpointUsageSubject.OwnedRelationship
+ .OfType()
+ .Select(featureTyping => featureTyping.Type)
+ .OfType()
+ .FirstOrDefault();
}
///
@@ -95,10 +101,17 @@ internal static IViewpointDefinition ComputeViewpointDefinition(this IViewpointU
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeViewpointStakeholder(this IViewpointUsage viewpointUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ // The OCL uses "featureMemberhsip" which is a typo in the XMI source; the correct C# property is featureMembership.
+ return viewpointUsageSubject == null
+ ? throw new ArgumentNullException(nameof(viewpointUsageSubject))
+ : [
+ ..viewpointUsageSubject.framedConcern
+ .SelectMany(concern => concern.featureMembership)
+ .OfType()
+ .Select(stakeholderMembership => stakeholderMembership.ownedStakeholderParameter)
+ ];
}
}