diff --git a/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs b/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs
index 8f990dd47..b3d230674 100644
--- a/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs
+++ b/SysML2.NET.Tests/Extend/ViewUsageExtensionsTestFixture.cs
@@ -1,58 +1,229 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
-//
+//
// 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.Requirements;
using SysML2.NET.Core.POCO.Systems.Views;
+ using SysML2.NET.Extensions;
[TestFixture]
public class ViewUsageExtensionsTestFixture
{
[Test]
- public void ComputeExposedElement_ThrowsNotSupportedException()
+ public void VerifyComputeExposedElement()
{
- Assert.That(() => ((IViewUsage)null).ComputeExposedElement(), Throws.TypeOf());
+ Assert.That(() => ((IViewUsage)null).ComputeExposedElement(), Throws.TypeOf());
+
+ var viewUsage = new ViewUsage();
+
+ // Empty: no ownedImport → empty list.
+ Assert.That(viewUsage.ComputeExposedElement(), Is.Empty);
+
+ // Discrimination: non-Expose import (MembershipImport) → excluded.
+ var nonExposeMembership = new MembershipImport();
+ viewUsage.AssignOwnership(nonExposeMembership);
+
+ Assert.That(viewUsage.ComputeExposedElement(), Is.Empty);
+
+ // STUB-BLOCKER: adding a MembershipExpose dispatches ComputeExposedElement to
+ // MembershipExpose.ImportedMemberships(excluded), which calls
+ // MembershipImportExtensions.ComputeRedefinedImportedMembershipsOperation — a
+ // NotSupportedException stub. The populated positive case cannot be tested until that
+ // upstream stub is implemented.
+ var membershipExpose = new MembershipExpose();
+ viewUsage.AssignOwnership(membershipExpose);
+
+ Assert.That(() => viewUsage.ComputeExposedElement(), Throws.TypeOf());
}
+
[Test]
- public void ComputeSatisfiedViewpoint_ThrowsNotSupportedException()
+ public void VerifyComputeSatisfiedViewpoint()
{
- Assert.That(() => ((IViewUsage)null).ComputeSatisfiedViewpoint(), Throws.TypeOf());
+ Assert.That(() => ((IViewUsage)null).ComputeSatisfiedViewpoint(), Throws.TypeOf());
+
+ var viewUsage = new ViewUsage();
+
+ // Empty: no nestedRequirement → empty list.
+ Assert.That(viewUsage.ComputeSatisfiedViewpoint(), Is.Empty);
+
+ // Discrimination: plain RequirementUsage (not ViewpointUsage) → excluded.
+ var plainRequirement = new RequirementUsage { IsComposite = true };
+ var plainRequirementMembership = new FeatureMembership();
+ viewUsage.AssignOwnership(plainRequirementMembership, plainRequirement);
+
+ Assert.That(viewUsage.ComputeSatisfiedViewpoint(), Is.Empty);
+
+ // Predicate discrimination: ViewpointUsage with IsComposite = false → excluded.
+ var nonCompositeViewpoint = new ViewpointUsage { IsComposite = false };
+ var nonCompositeViewpointMembership = new FeatureMembership();
+ viewUsage.AssignOwnership(nonCompositeViewpointMembership, nonCompositeViewpoint);
+
+ Assert.That(viewUsage.ComputeSatisfiedViewpoint(), Is.Empty);
+
+ // Positive: ViewpointUsage with IsComposite = true → returned.
+ var compositeViewpoint1 = new ViewpointUsage { IsComposite = true };
+ var compositeViewpointMembership1 = new FeatureMembership();
+ viewUsage.AssignOwnership(compositeViewpointMembership1, compositeViewpoint1);
+
+ Assert.That(viewUsage.ComputeSatisfiedViewpoint(), Is.EqualTo([compositeViewpoint1]));
+
+ // Populated: second composite ViewpointUsage also returned in iteration order.
+ var compositeViewpoint2 = new ViewpointUsage { IsComposite = true };
+ var compositeViewpointMembership2 = new FeatureMembership();
+ viewUsage.AssignOwnership(compositeViewpointMembership2, compositeViewpoint2);
+
+ Assert.That(viewUsage.ComputeSatisfiedViewpoint(), Is.EqualTo([compositeViewpoint1, compositeViewpoint2]));
+ }
+
+ [Test]
+ public void VerifyComputeViewCondition()
+ {
+ Assert.That(() => ((IViewUsage)null).ComputeViewCondition(), Throws.TypeOf());
+
+ var viewUsage = new ViewUsage();
+
+ // Empty: no ownedMembership → empty list.
+ Assert.That(viewUsage.ComputeViewCondition(), Is.Empty);
+
+ // Discrimination: non-ElementFilterMembership in ownedMembership → excluded.
+ var nonFilterFeature = new Feature();
+ var nonFilterMembership = new FeatureMembership();
+ viewUsage.AssignOwnership(nonFilterMembership, nonFilterFeature);
+
+ Assert.That(viewUsage.ComputeViewCondition(), Is.Empty);
+
+ // STUB-BLOCKER: Wiring an ElementFilterMembership and reading its condition property
+ // dispatches to ElementFilterMembershipExtensions.ComputeCondition, which is a NotSupportedException
+ // stub. The populated case cannot be tested cleanly until that upstream stub is implemented.
+ var filterCondition = new BooleanExpression();
+ var filterMembership = new ElementFilterMembership();
+ viewUsage.AssignOwnership(filterMembership, filterCondition);
+
+ Assert.That(() => viewUsage.ComputeViewCondition(), Throws.TypeOf());
}
+
[Test]
- public void ComputeViewCondition_ThrowsNotSupportedException()
+ public void VerifyComputeViewDefinition()
{
- Assert.That(() => ((IViewUsage)null).ComputeViewCondition(), Throws.TypeOf());
+ Assert.That(() => ((IViewUsage)null).ComputeViewDefinition(), Throws.TypeOf());
+
+ var viewUsage = new ViewUsage();
+
+ // Empty: no FeatureTyping → null.
+ Assert.That(viewUsage.ComputeViewDefinition(), Is.Null);
+
+ // Negative: FeatureTyping whose Type is a non-ViewDefinition → null.
+ var nonViewDefinitionType = new Feature();
+ var typingToNonViewDefinition = new FeatureTyping { Type = nonViewDefinitionType };
+ viewUsage.AssignOwnership(typingToNonViewDefinition);
+
+ Assert.That(viewUsage.ComputeViewDefinition(), Is.Null);
+
+ // Positive: FeatureTyping whose Type is a ViewDefinition → returned.
+ var viewDefinition1 = new ViewDefinition();
+ var typingToViewDefinition1 = new FeatureTyping { Type = viewDefinition1 };
+ viewUsage.AssignOwnership(typingToViewDefinition1);
+
+ Assert.That(viewUsage.ComputeViewDefinition(), Is.SameAs(viewDefinition1));
+
+ // Multiple: two ViewDefinition typings → first returned (FirstOrDefault).
+ var viewDefinition2 = new ViewDefinition();
+ var typingToViewDefinition2 = new FeatureTyping { Type = viewDefinition2 };
+ viewUsage.AssignOwnership(typingToViewDefinition2);
+
+ Assert.That(viewUsage.ComputeViewDefinition(), Is.SameAs(viewDefinition1));
}
+
[Test]
- public void ComputeViewDefinition_ThrowsNotSupportedException()
+ public void VerifyComputeViewRendering()
{
- Assert.That(() => ((IViewUsage)null).ComputeViewDefinition(), Throws.TypeOf());
+ Assert.That(() => ((IViewUsage)null).ComputeViewRendering(), Throws.TypeOf());
+
+ var viewUsage = new ViewUsage();
+
+ // Empty: no featureMembership → null.
+ Assert.That(viewUsage.ComputeViewRendering(), Is.Null);
+
+ // Discrimination: non-ViewRenderingMembership featureMembership → null.
+ var plainFeature = new Feature();
+ var plainFeatureMembership = new FeatureMembership();
+ viewUsage.AssignOwnership(plainFeatureMembership, plainFeature);
+
+ 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.
+ var renderingUsage = new RenderingUsage();
+ var viewRenderingMembership = new ViewRenderingMembership();
+ viewUsage.AssignOwnership(viewRenderingMembership, renderingUsage);
+
+ Assert.That(() => viewUsage.ComputeViewRendering(), Throws.TypeOf());
}
+
[Test]
- public void ComputeViewRendering_ThrowsNotSupportedException()
+ public void VerifyComputeIncludeAsExposedOperation()
{
- Assert.That(() => ((IViewUsage)null).ComputeViewRendering(), Throws.TypeOf());
+ // Null guard on subject.
+ Assert.That(() => ((IViewUsage)null).ComputeIncludeAsExposedOperation(new Feature()), Throws.TypeOf());
+
+ var viewUsage = new ViewUsage();
+
+ // Null guard on element parameter.
+ Assert.That(() => viewUsage.ComputeIncludeAsExposedOperation(null), Throws.TypeOf());
+
+ var element = new Feature();
+
+ // 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);
+
+ // Case (a) variant: non-filter memberships present, still no ElementFilterMembership →
+ // conditions remain empty → vacuously true.
+ var nonFilterFeature = new Feature();
+ var nonFilterMembership = new FeatureMembership();
+ viewUsage.AssignOwnership(nonFilterMembership, nonFilterFeature);
+
+ Assert.That(viewUsage.ComputeIncludeAsExposedOperation(element), Is.True);
+
+ // Cases (b), (c), (d) — STUB-BLOCKER: adding an ElementFilterMembership and reading its
+ // condition property dispatches to ElementFilterMembershipExtensions.ComputeCondition,
+ // which is a NotSupportedException stub. Additionally, annotation.annotatingElement
+ // dispatches to AnnotationExtensions.ComputeAnnotatingElement (also stubbed). These
+ // cases cannot be tested cleanly until the upstream stubs are implemented.
+ var filterCondition = new BooleanExpression();
+ var filterMembership = new ElementFilterMembership();
+ viewUsage.AssignOwnership(filterMembership, filterCondition);
+
+ Assert.That(() => viewUsage.ComputeIncludeAsExposedOperation(element), Throws.TypeOf());
}
}
}
diff --git a/SysML2.NET/Extend/ViewUsageExtensions.cs b/SysML2.NET/Extend/ViewUsageExtensions.cs
index f8e71a04a..37f995e0f 100644
--- a/SysML2.NET/Extend/ViewUsageExtensions.cs
+++ b/SysML2.NET/Extend/ViewUsageExtensions.cs
@@ -1,4 +1,4 @@
-// -------------------------------------------------------------------------------------------------
+// -------------------------------------------------------------------------------------------------
//
//
// Copyright (C) 2022-2026 Starion Group S.A.
@@ -22,40 +22,15 @@ 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;
- using SysML2.NET.Core.Systems.Occurrences;
- 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.Kernel.Classes;
using SysML2.NET.Core.POCO.Kernel.Functions;
- using SysML2.NET.Core.POCO.Kernel.Structures;
+ using SysML2.NET.Core.POCO.Kernel.Metadata;
+ 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;
- 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.DefinitionAndUsage;
- 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;
///
/// The class provides extensions methods for
@@ -81,10 +56,19 @@ internal static class ViewUsageExtensions
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeExposedElement(this IViewUsage viewUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewUsageSubject == null
+ ? throw new ArgumentNullException(nameof(viewUsageSubject))
+ : [
+ ..viewUsageSubject.ownedImport
+ .OfType()
+ .SelectMany(expose => expose.ImportedMemberships([]))
+ .Select(membership => membership.MemberElement)
+ .Where(memberElement => memberElement != null)
+ .Where(viewUsageSubject.IncludeAsExposed)
+ .Distinct()
+ ];
}
///
@@ -104,10 +88,11 @@ internal static List ComputeExposedElement(this IViewUsage viewUsageSu
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeSatisfiedViewpoint(this IViewUsage viewUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewUsageSubject == null
+ ? throw new ArgumentNullException(nameof(viewUsageSubject))
+ : [..viewUsageSubject.nestedRequirement.OfType().Where(viewpointUsage => viewpointUsage.IsComposite)];
}
///
@@ -127,10 +112,16 @@ internal static List ComputeSatisfiedViewpoint(this IViewUsage
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static List ComputeViewCondition(this IViewUsage viewUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewUsageSubject == null
+ ? throw new ArgumentNullException(nameof(viewUsageSubject))
+ : [
+ ..viewUsageSubject.ownedMembership
+ .OfType()
+ .Select(elementFilterMembership => elementFilterMembership.condition)
+ .Where(condition => condition != null)
+ ];
}
///
@@ -142,10 +133,15 @@ internal static List ComputeViewCondition(this IViewUsage viewUsage
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IViewDefinition ComputeViewDefinition(this IViewUsage viewUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ return viewUsageSubject == null
+ ? throw new ArgumentNullException(nameof(viewUsageSubject))
+ : viewUsageSubject.OwnedRelationship
+ .OfType()
+ .Select(featureTyping => featureTyping.Type)
+ .OfType()
+ .FirstOrDefault();
}
///
@@ -168,10 +164,16 @@ internal static IViewDefinition ComputeViewDefinition(this IViewUsage viewUsageS
///
/// the computed result
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static IRenderingUsage ComputeViewRendering(this IViewUsage viewUsageSubject)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ if (viewUsageSubject == null)
+ {
+ throw new ArgumentNullException(nameof(viewUsageSubject));
+ }
+
+ var renderings = viewUsageSubject.featureMembership.OfType().ToList();
+
+ return renderings.Count == 0 ? null : renderings[0].referencedRendering;
}
///
@@ -198,10 +200,30 @@ internal static IRenderingUsage ComputeViewRendering(this IViewUsage viewUsageSu
///
/// The expected
///
- [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal static bool ComputeIncludeAsExposedOperation(this IViewUsage viewUsageSubject, IElement element)
{
- throw new NotSupportedException("Create a GitHub issue when this method is required");
+ if (viewUsageSubject == null)
+ {
+ throw new ArgumentNullException(nameof(viewUsageSubject));
+ }
+
+ if (element == null)
+ {
+ throw new ArgumentNullException(nameof(element));
+ }
+
+ var metadataFeatures = element.ownedAnnotation
+ .Select(annotation => annotation.annotatingElement)
+ .OfType()
+ .ToList();
+
+ var conditions = viewUsageSubject.membership
+ .OfType()
+ .Select(elementFilterMembership => elementFilterMembership.condition)
+ .Where(condition => condition != null)
+ .ToList();
+
+ return conditions.All(condition => metadataFeatures.Any(condition.CheckCondition));
}
}
}