1+ using Microsoft . CSharp . Activities ;
2+ using Microsoft . VisualBasic . Activities ;
3+ using Shouldly ;
4+ using System ;
5+ using System . Activities ;
6+ using System . Activities . Statements ;
7+ using System . Activities . Validation ;
8+ using System . Collections . Generic ;
9+ using System . Linq ;
10+ using TestCases . Workflows . WF4Samples ;
11+ using Xunit ;
12+
13+ namespace TestCases . Workflows ;
14+
15+ /// <summary>
16+ /// Tests for improved out argument assignability validation and compilation (STUD-76892)
17+ /// </summary>
18+ public class OutArgumentAssignabilityTests
19+ {
20+ private readonly ValidationSettings _useValidator = new ( ) { ForceExpressionCache = false } ;
21+
22+ #region Core Out Argument Type Compatibility Tests
23+
24+ [ Fact ]
25+ public void CS_OutArgument_SameType_ShouldSucceed ( )
26+ {
27+ var sequence = new Sequence ( ) ;
28+ sequence . Variables . Add ( new Variable < List < string > > ( "result" ) ) ;
29+
30+ var activity = new ImproveAssignabilityOutArgumentActivity ( ) ;
31+ activity . Result = new OutArgument < List < string > > ( new CSharpReference < List < string > > ( "result" ) ) ;
32+
33+ sequence . Activities . Add ( activity ) ;
34+
35+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
36+ validationResults . Errors . ShouldBeEmpty ( $ "Expected no validation errors, but got: { string . Join ( "; " , validationResults . Errors . Select ( e => e . Message ) ) } ") ;
37+ }
38+
39+ [ Fact ]
40+ public void CS_OutArgument_IncompatibleType_ShouldFail ( )
41+ {
42+ var sequence = new Sequence ( ) ;
43+ sequence . Variables . Add ( new Variable < string > ( "result" ) ) ; // Wrong type - should be List<string>
44+
45+ var activity = new ImproveAssignabilityOutArgumentActivity ( ) ;
46+ activity . Result = new OutArgument < List < string > > ( new CSharpReference < List < string > > ( "result" ) ) ;
47+
48+ sequence . Activities . Add ( activity ) ;
49+
50+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
51+ validationResults . Errors . Count . ShouldBe ( 1 ) ;
52+ validationResults . Errors [ 0 ] . Message . ShouldContain ( "Cannot implicitly convert type" ) ;
53+ }
54+
55+ #endregion
56+
57+ #region Nullable Type Assignability Tests
58+
59+ [ Fact ]
60+ public void CS_OutArgument_DateTime_ToNullableDateTime_ShouldSucceed ( )
61+ {
62+ var sequence = new Sequence ( ) ;
63+ sequence . Variables . Add ( new Variable < DateTime ? > ( "nullableResult" ) ) ;
64+
65+ var activity = new ImproveAssignabilityOutArgumentActivity ( ) ;
66+ activity . DateTimeOutArgument = new OutArgument < DateTime > ( new CSharpReference < DateTime > ( "nullableResult" ) ) ;
67+
68+ sequence . Activities . Add ( activity ) ;
69+
70+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
71+ validationResults . Errors . ShouldBeEmpty ( $ "Expected no validation errors for DateTime to DateTime? assignment, but got: { string . Join ( "; " , validationResults . Errors . Select ( e => e . Message ) ) } ") ;
72+ }
73+
74+ [ Fact ]
75+ public void CS_OutArgument_NullableDateTime_ToDateTime_ShouldFail ( )
76+ {
77+ var sequence = new Sequence ( ) ;
78+ sequence . Variables . Add ( new Variable < DateTime > ( "nonNullableResult" ) ) ;
79+
80+ var activity = new ImproveAssignabilityOutArgumentActivity ( ) ;
81+ activity . NullableDateTimeOutArgument = new OutArgument < DateTime ? > ( new CSharpReference < DateTime ? > ( "nonNullableResult" ) ) ; // Should fail
82+
83+ sequence . Activities . Add ( activity ) ;
84+
85+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
86+ validationResults . Errors . Count . ShouldBe ( 1 ) ;
87+ validationResults . Errors [ 0 ] . Message . ShouldContain ( "Cannot implicitly convert type" ) ;
88+ }
89+
90+ #endregion
91+
92+ #region Generic Type Assignability Tests
93+
94+ [ Fact ]
95+ public void CS_OutArgument_GenericList_CorrectType_ShouldSucceed ( )
96+ {
97+ var sequence = new Sequence ( ) ;
98+ sequence . Variables . Add ( new Variable < List < string > > ( "stringList" ) ) ;
99+
100+ var activity = new ImproveAssignabilityOutArgumentActivity ( ) ;
101+ activity . Result = new OutArgument < List < string > > ( new CSharpReference < List < string > > ( "stringList" ) ) ;
102+
103+ sequence . Activities . Add ( activity ) ;
104+
105+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
106+ validationResults . Errors . ShouldBeEmpty ( ) ;
107+ }
108+
109+ [ Fact ]
110+ public void CS_OutArgument_GenericList_WrongGenericType_ShouldFail ( )
111+ {
112+ var sequence = new Sequence ( ) ;
113+ sequence . Variables . Add ( new Variable < List < int > > ( "intList" ) ) ; // Wrong generic type
114+
115+ var activity = new ImproveAssignabilityOutArgumentActivity ( ) ;
116+ activity . Result = new OutArgument < List < string > > ( new CSharpReference < List < string > > ( "intList" ) ) ;
117+
118+ sequence . Activities . Add ( activity ) ;
119+
120+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
121+ validationResults . Errors . Count . ShouldBe ( 1 ) ;
122+ validationResults . Errors [ 0 ] . Message . ShouldContain ( "Cannot implicitly convert type" ) ;
123+ }
124+
125+ #endregion
126+
127+ #region Safe Cast Validation Tests
128+
129+ [ Fact ]
130+ public void CS_OutArgument_SafeCast_BaseToInterface_ShouldSucceed ( )
131+ {
132+ var sequence = new Sequence ( ) ;
133+ sequence . Variables . Add ( new Variable < IList < string > > ( "interfaceList" ) ) ;
134+
135+ var activity = new ImproveAssignabilityOutArgumentActivity ( ) ;
136+ activity . Result = new OutArgument < List < string > > ( new CSharpReference < List < string > > ( "interfaceList" ) ) ;
137+
138+ sequence . Activities . Add ( activity ) ;
139+
140+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
141+ validationResults . Errors . ShouldBeEmpty ( "List<string> should be assignable to IList<string>" ) ;
142+ }
143+
144+ [ Fact ]
145+ public void CS_OutArgument_UnsafeCast_InterfaceToBase_ShouldFail ( )
146+ {
147+ var sequence = new Sequence ( ) ;
148+ sequence . Variables . Add ( new Variable < List < string > > ( "concreteList" ) ) ;
149+
150+ // Try to assign IList<string> to List<string> - should fail without explicit cast
151+ var assign = new Assign < IList < string > >
152+ {
153+ To = new OutArgument < IList < string > > ( new CSharpReference < IList < string > > ( "concreteList" ) ) ,
154+ Value = new InArgument < IList < string > > ( new CSharpValue < IList < string > > ( "new List<string>()" ) )
155+ } ;
156+
157+ sequence . Activities . Add ( assign ) ;
158+
159+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
160+ validationResults . Errors . Count . ShouldBe ( 1 ) ;
161+ validationResults . Errors [ 0 ] . Message . ShouldContain ( "Cannot implicitly convert type" ) ;
162+ }
163+
164+ #endregion
165+
166+ #region Multiple Out Arguments Test
167+
168+ [ Fact ]
169+ public void ImproveAssignabilityOutArgumentActivity_AllArgumentTypes_ShouldValidate ( )
170+ {
171+ var sequence = new Sequence ( ) ;
172+ sequence . Variables . Add ( new Variable < List < string > > ( "stringListResult" ) ) ;
173+ sequence . Variables . Add ( new Variable < DateTime > ( "dateTimeResult" ) ) ;
174+ sequence . Variables . Add ( new Variable < DateTime ? > ( "nullableDateTimeResult" ) ) ;
175+
176+ var activity = new ImproveAssignabilityOutArgumentActivity
177+ {
178+ Result = new OutArgument < List < string > > ( new CSharpReference < List < string > > ( "stringListResult" ) ) ,
179+ DateTimeOutArgument = new OutArgument < DateTime > ( new CSharpReference < DateTime > ( "dateTimeResult" ) ) ,
180+ NullableDateTimeOutArgument = new OutArgument < DateTime ? > ( new CSharpReference < DateTime ? > ( "nullableDateTimeResult" ) )
181+ } ;
182+
183+ sequence . Activities . Add ( activity ) ;
184+
185+ var validationResults = ActivityValidationServices . Validate ( sequence , _useValidator ) ;
186+ validationResults . Errors . ShouldBeEmpty ( $ "All out arguments should validate correctly. Errors: { string . Join ( "; " , validationResults . Errors . Select ( e => e . Message ) ) } ") ;
187+ }
188+
189+ #endregion
190+ }
0 commit comments