11// -------------------------------------------------------------------------------------------------
22// <copyright file="ExpressionExtensionsTestFixture.cs" company="Starion Group S.A.">
3- //
3+ //
44// Copyright 2022-2026 Starion Group S.A.
5- //
5+ //
66// Licensed under the Apache License, Version 2.0 (the "License");
77// you may not use this file except in compliance with the License.
88// You may obtain a copy of the License at
9- //
9+ //
1010// http://www.apache.org/licenses/LICENSE-2.0
11- //
11+ //
1212// Unless required by applicable law or agreed to in writing, software
1313// distributed under the License is distributed on an "AS IS" BASIS,
1414// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1515// See the License for the specific language governing permissions and
1616// limitations under the License.
17- //
17+ //
1818// </copyright>
1919// ------------------------------------------------------------------------------------------------
2020
@@ -28,15 +28,73 @@ namespace SysML2.NET.Tests.Extend
2828 using SysML2 . NET . Core . Core . Types ;
2929 using SysML2 . NET . Core . POCO . Core . Features ;
3030 using SysML2 . NET . Core . POCO . Core . Types ;
31- using SysML2 . NET . Core . POCO . Kernel . Expressions ;
3231 using SysML2 . NET . Core . POCO . Kernel . FeatureValues ;
3332 using SysML2 . NET . Core . POCO . Kernel . Functions ;
34- using SysML2 . NET . Core . POCO . Root . Elements ;
3533 using SysML2 . NET . Extensions ;
3634
35+ using Type = SysML2 . NET . Core . POCO . Core . Types . Type ;
36+
3737 [ TestFixture ]
3838 public class ExpressionExtensionsTestFixture
3939 {
40+ [ Test ]
41+ public void VerifyComputeCheckConditionOperation ( )
42+ {
43+ // Null guard on subject.
44+ Assert . That ( ( ) => ( ( IExpression ) null ) . ComputeCheckConditionOperation ( null ) , Throws . TypeOf < ArgumentNullException > ( ) ) ;
45+
46+ var expression = new Expression ( ) ;
47+
48+ // target == null: forwarded to Evaluate; empty-resultExprs branch returns [] → false (Count != 1).
49+ Assert . That ( expression . ComputeCheckConditionOperation ( null ) , Is . False ) ;
50+
51+ // Empty: Evaluate returns [] (no ResultExpressionMembership) → false (Count != 1).
52+ Assert . That ( expression . ComputeCheckConditionOperation ( null ) , Is . False ) ;
53+
54+ // Populated case: ResultExpressionMembership wired — Evaluate delegates through the inner
55+ // (empty) Expression and returns the empty list. CheckCondition requires Count == 1 AND
56+ // a LiteralBoolean { Value: true }, so it returns false.
57+ var expressionWithRem = new Expression ( ) ;
58+ var resultExprMembership = new ResultExpressionMembership ( ) ;
59+ var innerExpression = new Expression ( ) ;
60+ expressionWithRem . AssignOwnership ( resultExprMembership , innerExpression ) ;
61+
62+ Assert . That ( expressionWithRem . ComputeCheckConditionOperation ( null ) , Is . False ) ;
63+ }
64+
65+ [ Test ]
66+ public void VerifyComputeEvaluateOperation ( )
67+ {
68+ // Null guard on subject.
69+ Assert . That ( ( ) => ( ( IExpression ) null ) . ComputeEvaluateOperation ( null ) , Throws . TypeOf < ArgumentNullException > ( ) ) ;
70+
71+ var expression = new Expression ( ) ;
72+
73+ // target == null is permitted for the empty branch (base body doesn't dereference target).
74+ Assert . That ( ( ) => expression . ComputeEvaluateOperation ( null ) , Throws . Nothing ) ;
75+
76+ // Empty: no IResultExpressionMembership in ownedFeatureMembership → returns empty list.
77+ Assert . That ( expression . ComputeEvaluateOperation ( null ) , Is . Empty ) ;
78+
79+ // Discrimination: FeatureMembership with non-ResultExpressionMembership type → still empty.
80+ var plainMembership = new FeatureMembership ( ) ;
81+ var plainFeature = new Feature ( ) ;
82+ expression . AssignOwnership ( plainMembership , plainFeature ) ;
83+
84+ Assert . That ( expression . ComputeEvaluateOperation ( null ) , Is . Empty ) ;
85+
86+ // Populated case: ResultExpressionMembership wired — the production code resolves
87+ // resultExpressionMembership.ownedResultExpression (the inner Expression) and recursively
88+ // calls Evaluate on it. The inner Expression is itself empty (no nested
89+ // ResultExpressionMembership), so its Evaluate returns the empty list.
90+ var expressionWithRem = new Expression ( ) ;
91+ var resultExprMembership = new ResultExpressionMembership ( ) ;
92+ var innerExpression = new Expression ( ) ;
93+ expressionWithRem . AssignOwnership ( resultExprMembership , innerExpression ) ;
94+
95+ Assert . That ( expressionWithRem . ComputeEvaluateOperation ( null ) , Is . Empty ) ;
96+ }
97+
4098 [ Test ]
4199 public void VerifyComputeFunction ( )
42100 {
@@ -48,7 +106,7 @@ public void VerifyComputeFunction()
48106 Assert . That ( expression . ComputeFunction ( ) , Is . Null ) ;
49107
50108 // Negative: FeatureTyping pointing at a non-Function Type → null.
51- var nonFunctionType = new SysML2 . NET . Core . POCO . Core . Types . Type ( ) ;
109+ var nonFunctionType = new Type ( ) ;
52110 var typingToNonFunction = new FeatureTyping { Type = nonFunctionType } ;
53111 expression . AssignOwnership ( typingToNonFunction ) ;
54112
@@ -93,38 +151,6 @@ public void VerifyComputeIsModelLevelEvaluable()
93151 Assert . That ( expressionWithNonImplied . ComputeIsModelLevelEvaluable ( ) , Is . False ) ;
94152 }
95153
96- [ Test ]
97- public void VerifyComputeResult ( )
98- {
99- Assert . That ( ( ) => ( ( IExpression ) null ) . ComputeResult ( ) , Throws . TypeOf < ArgumentNullException > ( ) ) ;
100-
101- var expression = new Expression ( ) ;
102-
103- // Empty: no featureMembership → null.
104- Assert . That ( expression . ComputeResult ( ) , Is . Null ) ;
105-
106- // Negative: FeatureMembership with non-ReturnParameterMembership → null.
107- var featureMembership = new FeatureMembership ( ) ;
108- var plainFeature = new Feature ( ) ;
109- expression . AssignOwnership ( featureMembership , plainFeature ) ;
110-
111- Assert . That ( expression . ComputeResult ( ) , Is . Null ) ;
112-
113- // Positive: one ReturnParameterMembership with ownedMemberParameter set → that Feature returned.
114- var resultFeature = new Feature ( ) ;
115- var returnParamMembership = new ReturnParameterMembership ( ) ;
116- expression . AssignOwnership ( returnParamMembership , resultFeature ) ;
117-
118- Assert . That ( expression . ComputeResult ( ) , Is . SameAs ( resultFeature ) ) ;
119-
120- // Multiple ReturnParameterMemberships (illegal per OCL validation but tolerated) → first returned.
121- var secondResultFeature = new Feature ( ) ;
122- var secondReturnParamMembership = new ReturnParameterMembership ( ) ;
123- expression . AssignOwnership ( secondReturnParamMembership , secondResultFeature ) ;
124-
125- Assert . That ( expression . ComputeResult ( ) , Is . SameAs ( resultFeature ) ) ;
126- }
127-
128154 [ Test ]
129155 public void VerifyComputeModelLevelEvaluableOperation ( )
130156 {
@@ -205,85 +231,49 @@ public void VerifyComputeModelLevelEvaluableOperation()
205231
206232 Assert . That ( expressionWithValuation . ComputeModelLevelEvaluableOperation ( [ ] ) , Is . True ) ;
207233
208- // BRANCH_B: ownedFeature under ResultExpressionMembership — STUB-BLOCKER.
209- // Although BRANCH_B logic only accesses owningFeatureMembership and calls ModelLevelEvaluable
210- // on the inner Expression, the production code first computes expressionSubject.result (line 157
211- // of ExpressionExtensions.cs), which traverses featureMembership → inheritedMembership →
212- // ownedFeature → ResultExpressionMembership.ownedMemberFeature → ownedResultExpression →
213- // ResultExpressionMembershipExtensions.ComputeOwnedResultExpression, which is a stub.
214- // Therefore the BRANCH_B recursion path cannot be exercised until that stub is implemented.
234+ // BRANCH_B: ownedFeature owned via ResultExpressionMembership — passes branchB.
235+ // The inner Expression is empty (no specializations, no features), so its recursive
236+ // ModelLevelEvaluable call returns true; the outer Expression's single owned feature
237+ // satisfies branchB (owningFeatureMembership is IResultExpressionMembership AND
238+ // innerExpression.ModelLevelEvaluable is true). Outer returns true.
215239 var expressionBranchB = new Expression ( ) ;
216240 var innerExpression = new Expression ( ) ;
217241 var resultExprMembershipB = new ResultExpressionMembership ( ) ;
218242 expressionBranchB . AssignOwnership ( resultExprMembershipB , innerExpression ) ;
219243
220- Assert . That (
221- ( ) => expressionBranchB . ComputeModelLevelEvaluableOperation ( [ ] ) ,
222- Throws . TypeOf < NotSupportedException > ( ) ) ;
244+ Assert . That ( expressionBranchB . ComputeModelLevelEvaluableOperation ( [ ] ) , Is . True ) ;
223245 }
224246
225247 [ Test ]
226- public void VerifyComputeEvaluateOperation ( )
248+ public void VerifyComputeResult ( )
227249 {
228- // Null guard on subject.
229- Assert . That ( ( ) => ( ( IExpression ) null ) . ComputeEvaluateOperation ( null ) , Throws . TypeOf < ArgumentNullException > ( ) ) ;
250+ Assert . That ( ( ) => ( ( IExpression ) null ) . ComputeResult ( ) , Throws . TypeOf < ArgumentNullException > ( ) ) ;
230251
231252 var expression = new Expression ( ) ;
232253
233- // target == null is permitted for the empty branch (base body doesn't dereference target).
234- Assert . That ( ( ) => expression . ComputeEvaluateOperation ( null ) , Throws . Nothing ) ;
235-
236- // Empty: no IResultExpressionMembership in ownedFeatureMembership → returns empty list.
237- Assert . That ( expression . ComputeEvaluateOperation ( null ) , Is . Empty ) ;
254+ // Empty: no featureMembership → null.
255+ Assert . That ( expression . ComputeResult ( ) , Is . Null ) ;
238256
239- // Discrimination : FeatureMembership with non-ResultExpressionMembership type → still empty .
240- var plainMembership = new FeatureMembership ( ) ;
257+ // Negative : FeatureMembership with non-ReturnParameterMembership → null .
258+ var featureMembership = new FeatureMembership ( ) ;
241259 var plainFeature = new Feature ( ) ;
242- expression . AssignOwnership ( plainMembership , plainFeature ) ;
243-
244- Assert . That ( expression . ComputeEvaluateOperation ( null ) , Is . Empty ) ;
245-
246- // STUB-BLOCKER: wire a ResultExpressionMembership → the production code calls
247- // resultExpressionMembership.ownedResultExpression, which dispatches to
248- // ResultExpressionMembershipExtensions.ComputeOwnedResultExpression, which is a stub
249- // that throws NotSupportedException. Assert the stub propagates.
250- var expressionWithRem = new Expression ( ) ;
251- var resultExprMembership = new ResultExpressionMembership ( ) ;
252- var innerExpression = new Expression ( ) ;
253- expressionWithRem . AssignOwnership ( resultExprMembership , innerExpression ) ;
254-
255- // ResultExpressionMembershipExtensions.ComputeOwnedResultExpression is a stub — NSE expected.
256- Assert . That (
257- ( ) => expressionWithRem . ComputeEvaluateOperation ( null ) ,
258- Throws . TypeOf < NotSupportedException > ( ) ) ;
259- }
260-
261- [ Test ]
262- public void VerifyComputeCheckConditionOperation ( )
263- {
264- // Null guard on subject.
265- Assert . That ( ( ) => ( ( IExpression ) null ) . ComputeCheckConditionOperation ( null ) , Throws . TypeOf < ArgumentNullException > ( ) ) ;
260+ expression . AssignOwnership ( featureMembership , plainFeature ) ;
266261
267- var expression = new Expression ( ) ;
262+ Assert . That ( expression . ComputeResult ( ) , Is . Null ) ;
268263
269- // target == null: forwarded to Evaluate; empty-resultExprs branch returns [] → false (Count != 1).
270- Assert . That ( expression . ComputeCheckConditionOperation ( null ) , Is . False ) ;
264+ // Positive: one ReturnParameterMembership with ownedMemberParameter set → that Feature returned.
265+ var resultFeature = new Feature ( ) ;
266+ var returnParamMembership = new ReturnParameterMembership ( ) ;
267+ expression . AssignOwnership ( returnParamMembership , resultFeature ) ;
271268
272- // Empty: Evaluate returns [] (no ResultExpressionMembership) → false (Count != 1).
273- Assert . That ( expression . ComputeCheckConditionOperation ( null ) , Is . False ) ;
269+ Assert . That ( expression . ComputeResult ( ) , Is . SameAs ( resultFeature ) ) ;
274270
275- // STUB-BLOCKER: wire a ResultExpressionMembership → Evaluate delegates to ComputeEvaluateOperation,
276- // which accesses resultExpressionMembership.ownedResultExpression →
277- // ResultExpressionMembershipExtensions.ComputeOwnedResultExpression is a stub → NSE propagates.
278- var expressionWithRem = new Expression ( ) ;
279- var resultExprMembership = new ResultExpressionMembership ( ) ;
280- var innerExpression = new Expression ( ) ;
281- expressionWithRem . AssignOwnership ( resultExprMembership , innerExpression ) ;
271+ // Multiple ReturnParameterMemberships (illegal per OCL validation but tolerated) → first returned.
272+ var secondResultFeature = new Feature ( ) ;
273+ var secondReturnParamMembership = new ReturnParameterMembership ( ) ;
274+ expression . AssignOwnership ( secondReturnParamMembership , secondResultFeature ) ;
282275
283- // ResultExpressionMembershipExtensions.ComputeOwnedResultExpression is a stub — NSE expected.
284- Assert . That (
285- ( ) => expressionWithRem . ComputeCheckConditionOperation ( null ) ,
286- Throws . TypeOf < NotSupportedException > ( ) ) ;
276+ Assert . That ( expression . ComputeResult ( ) , Is . SameAs ( resultFeature ) ) ;
287277 }
288278 }
289279}
0 commit comments