Add PInvoke/Array tests (#19266)
[platform/upstream/coreclr.git] / tests / src / Interop / PInvoke / Array / MarshalArrayAsParam / AsDefault / AsDefaultTest.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 using System;
6 using System.Runtime.InteropServices;
7 using TestLibrary;
8
9 public class ArrayMarshal
10 {
11     public struct TestStruct
12     {
13         public int x;
14         public double d;
15         public long l;
16         public string str;
17     }
18
19     #region No attributes applied
20
21     [DllImport("MarshalArrayLPArrayNative")]
22     private static extern bool CStyle_Array_Int(int[] actual, int cActual);
23
24     [DllImport("MarshalArrayLPArrayNative")]
25     private static extern bool CStyle_Array_Uint(uint[] actual, int cActual);
26
27     [DllImport("MarshalArrayLPArrayNative")]
28     private static extern bool CStyle_Array_Short(short[] actual, int cActual);
29
30     [DllImport("MarshalArrayLPArrayNative")]
31     private static extern bool CStyle_Array_Word(ushort[] actual, int cActual);
32
33     [DllImport("MarshalArrayLPArrayNative")]
34     private static extern bool CStyle_Array_Long64(long[] actual, int cActual);
35
36     [DllImport("MarshalArrayLPArrayNative")]
37     private static extern bool CStyle_Array_ULong64(ulong[] actual, int cActual);
38
39     [DllImport("MarshalArrayLPArrayNative")]
40     private static extern bool CStyle_Array_Double(double[] actual, int cActual);
41
42     [DllImport("MarshalArrayLPArrayNative")]
43     private static extern bool CStyle_Array_Float(float[] actual, int cActual);
44
45     [DllImport("MarshalArrayLPArrayNative")]
46     private static extern bool CStyle_Array_Byte(byte[] actual, int cActual);
47
48     [DllImport("MarshalArrayLPArrayNative")]
49     private static extern bool CStyle_Array_Char(char[] actual, int cActual);
50
51     [DllImport("MarshalArrayLPArrayNative")]
52     private static extern bool CStyle_Array_LPCSTR(string[] actual, int cActual);
53
54     [DllImport("MarshalArrayLPArrayNative")]
55     private static extern bool CStyle_Array_LPSTR(string[] actual, int cActual);
56
57     [DllImport("MarshalArrayLPArrayNative")]
58     private static extern bool CStyle_Array_Struct(TestStruct[] actual, int cActual);
59
60     [DllImport("MarshalArrayLPArrayNative")]
61     private static extern bool CStyle_Array_Bool(bool[] actual, int cActual);
62
63     [DllImport("MarshalArrayLPArrayNative")]
64     private static extern bool CStyle_Array_Object(object[] actual, int cActual);
65     #endregion
66
67     #region InAttribute attribute applied
68
69     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Int")]
70     private static extern bool CStyle_Array_Int_In([In]int[] actual, int cActual);
71
72     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Uint")]
73     private static extern bool CStyle_Array_Uint_In([In]uint[] actual, int cActual);
74
75     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Short")]
76     private static extern bool CStyle_Array_Short_In([In]short[] actual, int cActual);
77
78     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Word")]
79     private static extern bool CStyle_Array_Word_In([In]ushort[] actual, int cActual);
80
81     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Long64")]
82     private static extern bool CStyle_Array_Long64_In([In]long[] actual, int cActual);
83
84     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_ULong64")]
85     private static extern bool CStyle_Array_ULong64_In([In]ulong[] actual, int cActual);
86
87     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Double")]
88     private static extern bool CStyle_Array_Double_In([In]double[] actual, int cActual);
89
90     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Float")]
91     private static extern bool CStyle_Array_Float_In([In]float[] actual, int cActual);
92
93     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Byte")]
94     private static extern bool CStyle_Array_Byte_In([In]byte[] actual, int cActual);
95
96     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Char")]
97     private static extern bool CStyle_Array_Char_In([In]char[] actual, int cActual);
98
99     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_LPCSTR")]
100     private static extern bool CStyle_Array_LPCSTR_In([In]string[] actual, int cActual);
101
102     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_LPSTR")]
103     private static extern bool CStyle_Array_LPSTR_In([In]string[] actual, int cActual);
104
105     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Struct")]
106     private static extern bool CStyle_Array_Struct_In([In]TestStruct[] actual, int cActual);
107
108     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Bool")]
109     private static extern bool CStyle_Array_Bool_In([In]bool[] actual, int cActual);
110
111     [DllImport("MarshalArrayLPArrayNative", EntryPoint = "CStyle_Array_Object")]
112     private static extern bool CStyle_Array_Object_In([In]object[] actual, int cActual);
113     #endregion
114
115     #region InAttribute and OutAttribute attributes applied
116
117     [DllImport("MarshalArrayLPArrayNative")]
118     private static extern bool CStyle_Array_Int_InOut(
119         [In, Out] int[] actual, int cActual);
120
121     [DllImport("MarshalArrayLPArrayNative")]
122     private static extern bool CStyle_Array_Int_InOut_Null(
123         [In, Out] int[] actual);
124
125     [DllImport("MarshalArrayLPArrayNative")]
126     private static extern bool CStyle_Array_Int_InOut_ZeroLength(
127         [In, Out] int[] actual);
128
129     [DllImport("MarshalArrayLPArrayNative")]
130     private static extern bool CStyle_Array_Object_InOut(
131         [In, Out] object[] actual, int cActual);
132
133     [DllImport("MarshalArrayLPArrayNative")]
134     private static extern bool CStyle_Array_Uint_InOut(
135         [In, Out] uint[] actual, int cActual);
136
137     [DllImport("MarshalArrayLPArrayNative")]
138     private static extern bool CStyle_Array_Short_InOut(
139         [In, Out] short[] actual, int cActual);
140
141     [DllImport("MarshalArrayLPArrayNative")]
142     private static extern bool CStyle_Array_Word_InOut(
143         [In, Out] ushort[] actual, int cActual);
144
145     [DllImport("MarshalArrayLPArrayNative")]
146     private static extern bool CStyle_Array_Long64_InOut(
147         [In, Out] long[] actual, int cActual);
148
149     [DllImport("MarshalArrayLPArrayNative")]
150     private static extern bool CStyle_Array_ULong64_InOut(
151         [In, Out] ulong[] actual, int cActual);
152
153     [DllImport("MarshalArrayLPArrayNative")]
154     private static extern bool CStyle_Array_Double_InOut(
155         [In, Out] double[] actual, int cActual);
156
157     [DllImport("MarshalArrayLPArrayNative")]
158     private static extern bool CStyle_Array_Float_InOut(
159         [In, Out] float[] actual, int cActual);
160
161     [DllImport("MarshalArrayLPArrayNative")]
162     private static extern bool CStyle_Array_Byte_InOut(
163         [In, Out] byte[] actual, int cActual);
164
165     [DllImport("MarshalArrayLPArrayNative")]
166     private static extern bool CStyle_Array_Char_InOut(
167         [In, Out] char[] actual, int cActual);
168
169     [DllImport("MarshalArrayLPArrayNative")]
170     private static extern bool CStyle_Array_LPSTR_InOut(
171         [In, Out] string[] actual, int cActual);
172
173     [DllImport("MarshalArrayLPArrayNative")]
174     private static extern bool CStyle_Array_Struct_InOut(
175         [In, Out] TestStruct[] actual, int cActual);
176
177     [DllImport("MarshalArrayLPArrayNative")]
178     private static extern bool CStyle_Array_Bool_InOut(
179         [In, Out] bool[] actual, int cActual);
180     #endregion
181
182     #region OutAttribute attributes applied
183
184     [DllImport("MarshalArrayLPArrayNative")]
185     private static extern bool CStyle_Array_Int_Out(
186         [Out] int[] actual, int cActual);
187
188     [DllImport("MarshalArrayLPArrayNative")]
189     private static extern bool CStyle_Array_Int_Out_Null(
190         [Out] int[] actual);
191
192     [DllImport("MarshalArrayLPArrayNative")]
193     private static extern bool CStyle_Array_Int_Out_ZeroLength(
194         [Out] int[] actual);
195
196     [DllImport("MarshalArrayLPArrayNative")]
197     private static extern bool CStyle_Array_Object_Out(
198         [Out] object[] actual, int cActual);
199
200     [DllImport("MarshalArrayLPArrayNative")]
201     private static extern bool CStyle_Array_Uint_Out(
202         [Out] uint[] actual, int cActual);
203
204     [DllImport("MarshalArrayLPArrayNative")]
205     private static extern bool CStyle_Array_Short_Out(
206         [Out] short[] actual, int cActual);
207
208     [DllImport("MarshalArrayLPArrayNative")]
209     private static extern bool CStyle_Array_Word_Out(
210         [Out] ushort[] actual, int cActual);
211
212     [DllImport("MarshalArrayLPArrayNative")]
213     private static extern bool CStyle_Array_Long64_Out(
214         [Out] long[] actual, int cActual);
215
216     [DllImport("MarshalArrayLPArrayNative")]
217     private static extern bool CStyle_Array_ULong64_Out(
218         [Out] ulong[] actual, int cActual);
219
220     [DllImport("MarshalArrayLPArrayNative")]
221     private static extern bool CStyle_Array_Double_Out(
222         [Out] double[] actual, int cActual);
223
224     [DllImport("MarshalArrayLPArrayNative")]
225     private static extern bool CStyle_Array_Float_Out(
226         [Out] float[] actual, int cActual);
227
228     [DllImport("MarshalArrayLPArrayNative")]
229     private static extern bool CStyle_Array_Byte_Out(
230         [Out] byte[] actual, int cActual);
231
232     [DllImport("MarshalArrayLPArrayNative")]
233     private static extern bool CStyle_Array_Char_Out(
234         [Out] char[] actual, int cActual);
235
236     [DllImport("MarshalArrayLPArrayNative")]
237     private static extern bool CStyle_Array_LPSTR_Out(
238         [Out] string[] actual, int cActual);
239
240     [DllImport("MarshalArrayLPArrayNative")]
241     private static extern bool CStyle_Array_Struct_Out(
242         [Out] TestStruct[] actual, int cActual);
243
244     [DllImport("MarshalArrayLPArrayNative")]
245     private static extern bool CStyle_Array_Bool_Out(
246         [Out] bool[] actual, int cActual);
247     #endregion
248
249     #region Marshal ByVal
250
251     private const int ARRAY_SIZE = 100;
252
253     private static T[] InitArray<T>(int size)
254     {
255         T[] array = new T[size];
256
257         for (int i = 0; i < array.Length; ++i)
258             array[i] = (T)Convert.ChangeType(i, typeof(T));
259
260         return array;
261     }
262
263     private static bool[] InitBoolArray(int size)
264     {
265         bool[] array = new bool[size];
266
267         for (int i = 0; i < array.Length; ++i)
268         {
269             if (i % 2 == 0)
270                 array[i] = true;
271             else
272                 array[i] = false;
273         }
274
275         return array;
276     }
277
278     private static TestStruct[] InitStructArray(int size)
279     {
280         TestStruct[] array = new TestStruct[size];
281
282         for (int i = 0; i < array.Length; ++i)
283         {
284             array[i].x = i;
285             array[i].d = i;
286             array[i].l = i;
287             array[i].str = i.ToString();
288         }
289
290         return array;
291     }
292
293     private static void TestMarshalByVal_NoAttributes()
294     {
295         Console.WriteLine("ByVal marshaling CLR array as c-style-array no attributes");
296
297         Assert.IsTrue(CStyle_Array_Int(InitArray<int>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Int");
298         Assert.IsTrue(CStyle_Array_Uint(InitArray<uint>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_Uint") ;
299         Assert.IsTrue(CStyle_Array_Short(InitArray<short>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_Short");
300         Assert.IsTrue(CStyle_Array_Word(InitArray<ushort>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_Word");
301         Assert.IsTrue(CStyle_Array_Long64(InitArray<long>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_Long64");
302         Assert.IsTrue(CStyle_Array_ULong64(InitArray<ulong>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_ULong64");
303         Assert.IsTrue(CStyle_Array_Double(InitArray<double>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_Double");
304         Assert.IsTrue(CStyle_Array_Float(InitArray<float>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_Float");
305         Assert.IsTrue(CStyle_Array_Byte(InitArray<byte>(ARRAY_SIZE), ARRAY_SIZE),"CStyle_Array_Byte");
306         Assert.IsTrue(CStyle_Array_Char(InitArray<char>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Char");
307
308         string[] strArr = InitArray<string>(ARRAY_SIZE);
309         // Test nesting null value scenario
310         strArr[strArr.Length / 2] = null;
311         Assert.IsTrue(CStyle_Array_LPCSTR(strArr, ARRAY_SIZE), "CStyle_Array_LPCSTR");
312         Assert.IsTrue(CStyle_Array_LPSTR(strArr, ARRAY_SIZE), "CStyle_Array_LPSTR");
313         Assert.IsTrue(CStyle_Array_Struct(InitStructArray(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Struct");
314
315         Assert.IsTrue(CStyle_Array_Bool(InitBoolArray(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Bool");
316
317         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
318         {
319             object[] oArr = InitArray<object>(ARRAY_SIZE);
320             // Test nesting null value scenario
321             oArr[oArr.Length / 2] = null;
322             Assert.IsTrue(CStyle_Array_Object(oArr, ARRAY_SIZE), "CStyle_Array_Object"); 
323         }
324     }
325
326     private static void TestMarshalByVal_In()
327     {
328         Console.WriteLine("ByVal marshaling  CLR array as c-style-array with InAttribute applied");
329
330         Assert.IsTrue(CStyle_Array_Int_In(InitArray<int>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Int_In");
331         Assert.IsTrue(CStyle_Array_Uint_In(InitArray<uint>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Uint_In");
332         Assert.IsTrue(CStyle_Array_Short_In(InitArray<short>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Short_In");
333         Assert.IsTrue(CStyle_Array_Word_In(InitArray<ushort>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Word_In");
334         Assert.IsTrue(CStyle_Array_Long64_In(InitArray<long>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Long64_In");
335         Assert.IsTrue(CStyle_Array_ULong64_In(InitArray<ulong>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_ULong64_In");
336         Assert.IsTrue(CStyle_Array_Double_In(InitArray<double>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Double_In");
337         Assert.IsTrue(CStyle_Array_Float_In(InitArray<float>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Float_In");
338         Assert.IsTrue(CStyle_Array_Byte_In(InitArray<byte>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Byte_In");
339         Assert.IsTrue(CStyle_Array_Char_In(InitArray<char>(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Char_In");
340
341         string[] strArr = InitArray<string>(ARRAY_SIZE);
342         // Test nesting null value scenario
343         strArr[strArr.Length / 2] = null;
344
345         Assert.IsTrue(CStyle_Array_LPCSTR_In(strArr, ARRAY_SIZE), "CStyle_Array_LPCSTR_In");
346         Assert.IsTrue(CStyle_Array_LPSTR_In(strArr, ARRAY_SIZE), "CStyle_Array_LPSTR_In");
347         Assert.IsTrue(CStyle_Array_Struct_In(InitStructArray(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Struct_In");
348         Assert.IsTrue(CStyle_Array_Bool_In(InitBoolArray(ARRAY_SIZE), ARRAY_SIZE), "CStyle_Array_Bool_In");
349         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
350         {
351             object[] oArr = InitArray<object>(ARRAY_SIZE);
352             // Test nesting null value scenario
353             oArr[oArr.Length / 2] = null;
354             Assert.IsTrue(CStyle_Array_Object_In(oArr, ARRAY_SIZE), "CStyle_Array_Object_In"); 
355         }
356     }
357
358     #endregion
359
360     #region Marshal InOut ByVal
361
362     private static void TestMarshalInOut_ByVal()
363     {
364         Console.WriteLine("By value marshaling CLR array as c-style-array with InAttribute and OutAttribute applied");
365         Console.WriteLine("CStyle_Array_Int_InOut");
366         int[] iArr = InitArray<int>(ARRAY_SIZE);
367         Assert.IsTrue(CStyle_Array_Int_InOut(iArr, ARRAY_SIZE), "CStyle_Array_Int_InOut");
368         Assert.IsTrue(Equals<int>(iArr, GetExpectedOutArray<int>(ARRAY_SIZE)), "CStyle_Array_Int_InOut:Equals<int>");
369
370         Console.WriteLine("CStyle_Array_Int_InOut_Null");
371         int[] iArrNull = null;
372         Assert.IsTrue(CStyle_Array_Int_InOut_Null(iArrNull), "CStyle_Array_Int_InOut_Null");
373         Assert.IsNull(iArrNull, "CStyle_Array_Int_InOut_Null:Equals<null>");
374
375         Console.WriteLine("CStyle_Array_Int_InOut_ZeroLength");
376         int[] iArrLength0 = InitArray<int>(0);
377         Assert.IsTrue(CStyle_Array_Int_InOut_ZeroLength(iArrLength0), "CStyle_Array_Int_InOut_ZeroLength");
378         Assert.AreEqual(0, iArrLength0.Length, "CStyle_Array_Int_InOut_ZeroLength:Length<!0>");
379
380         Console.WriteLine("CStyle_Array_Uint_InOut");
381         uint[] uiArr = InitArray<uint>(ARRAY_SIZE);
382         Assert.IsTrue(CStyle_Array_Uint_InOut(uiArr, ARRAY_SIZE), "CStyle_Array_Uint_InOut");
383         Assert.IsTrue(Equals<uint>(uiArr, GetExpectedOutArray<uint>(ARRAY_SIZE)), "CStyle_Array_Uint_InOut:Equals<uint>");
384
385         Console.WriteLine("CStyle_Array_Short_InOut");
386         short[] sArr = InitArray<short>(ARRAY_SIZE);
387         Assert.IsTrue(CStyle_Array_Short_InOut(sArr, ARRAY_SIZE), "CStyle_Array_Short_InOut");
388         Assert.IsTrue(Equals<short>(sArr, GetExpectedOutArray<short>(ARRAY_SIZE)), "CStyle_Array_Short_InOut:Equals<short>");
389
390         Console.WriteLine("CStyle_Array_Word_InOut");
391         ushort[] usArr = InitArray<ushort>(ARRAY_SIZE);
392         Assert.IsTrue(CStyle_Array_Word_InOut(usArr, ARRAY_SIZE), "CStyle_Array_Word_InOut");
393         Assert.IsTrue(Equals<ushort>(usArr, GetExpectedOutArray<ushort>(ARRAY_SIZE)), "CStyle_Array_Word_InOut:Equals<ushort>");
394
395         Console.WriteLine("CStyle_Array_Long64_InOut");
396         long[] lArr = InitArray<long>(ARRAY_SIZE);
397         Assert.IsTrue(CStyle_Array_Long64_InOut(lArr, ARRAY_SIZE), "CStyle_Array_Long64_InOut");
398         Assert.IsTrue(Equals<long>(lArr, GetExpectedOutArray<long>(ARRAY_SIZE)), "CStyle_Array_Long64_InOut:Equals<long>");
399
400         Console.WriteLine("CStyle_Array_ULong64_InOut");
401         ulong[] ulArr = InitArray<ulong>(ARRAY_SIZE);
402         Assert.IsTrue(CStyle_Array_ULong64_InOut(ulArr, ARRAY_SIZE), "CStyle_Array_ULong64_InOut");
403         Assert.IsTrue(Equals<ulong>(ulArr, GetExpectedOutArray<ulong>(ARRAY_SIZE)), "CStyle_Array_ULong64_InOut:Equals<ulong>");
404
405         Console.WriteLine("CStyle_Array_Double_InOut");
406         double[] dArr = InitArray<double>(ARRAY_SIZE);
407         Assert.IsTrue(CStyle_Array_Double_InOut(dArr, ARRAY_SIZE), "CStyle_Array_Double_InOut");
408         Assert.IsTrue(Equals<double>(dArr, GetExpectedOutArray<double>(ARRAY_SIZE)), "CStyle_Array_Double_InOut:Equals<double>");
409
410         Console.WriteLine("CStyle_Array_Float_InOut");
411         float[] fArr = InitArray<float>(ARRAY_SIZE);
412         Assert.IsTrue(CStyle_Array_Float_InOut(fArr, ARRAY_SIZE), "CStyle_Array_Float_InOut");
413         Assert.IsTrue(Equals<float>(fArr, GetExpectedOutArray<float>(ARRAY_SIZE)), "CStyle_Array_Float_InOut:Equals<float>");
414
415         Console.WriteLine("CStyle_Array_Byte_InOut");
416         byte[] bArr = InitArray<byte>(ARRAY_SIZE);
417         Assert.IsTrue(CStyle_Array_Byte_InOut(bArr, ARRAY_SIZE), "CStyle_Array_Byte_InOut");
418         Assert.IsTrue(Equals<byte>(bArr, GetExpectedOutArray<byte>(ARRAY_SIZE)), "CStyle_Array_Byte_InOut:Equals<byte>");
419
420         Console.WriteLine("CStyle_Array_Char_InOut");
421         char[] cArr = InitArray<char>(ARRAY_SIZE);
422         Assert.IsTrue(CStyle_Array_Char_InOut(cArr, ARRAY_SIZE), "CStyle_Array_Char_InOut");
423         Assert.IsTrue(Equals<char>(cArr, GetExpectedOutArray<char>(ARRAY_SIZE)), "CStyle_Array_Char_InOut:Equals<char>");
424
425         Console.WriteLine("CStyle_Array_LPSTR_InOut");
426         string[] strArr = InitArray<string>(ARRAY_SIZE);
427         strArr[strArr.Length / 2] = null;
428         Assert.IsTrue(CStyle_Array_LPSTR_InOut(strArr, ARRAY_SIZE), "CStyle_Array_LPSTR_InOut");
429         string[] expectedArr = GetExpectedOutArray<string>(ARRAY_SIZE);
430         // Test nesting null value scenario
431         expectedArr[expectedArr.Length / 2 - 1] = null;
432         Assert.IsTrue(Equals<string>(strArr, expectedArr), "CStyle_Array_LPSTR_InOut:Equals<string>");
433
434         Console.WriteLine("CStyle_Array_Struct_InOut");
435         TestStruct[] tsArr = InitStructArray(ARRAY_SIZE);
436         Assert.IsTrue(CStyle_Array_Struct_InOut(tsArr, ARRAY_SIZE), "CStyle_Array_Struct_InOut");
437         Assert.IsTrue(Equals<TestStruct>(tsArr, GetExpectedOutStructArray(ARRAY_SIZE)), "CStyle_Array_Struct_InOut:Equals<TestStruct>");
438
439         Console.WriteLine("CStyle_Array_Bool_InOut");
440         bool[] boolArr = InitBoolArray(ARRAY_SIZE);
441         Assert.IsTrue(CStyle_Array_Bool_InOut(boolArr, ARRAY_SIZE), "CStyle_Array_Bool_InOut");
442         Assert.IsTrue(Equals<bool>(boolArr, GetExpectedOutBoolArray(ARRAY_SIZE)), "CStyle_Array_Bool_InOut:Equals<bool>");
443
444         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
445         {
446             Console.WriteLine("CStyle_Array_Object_InOut");
447             object[] oArr = InitArray<object>(ARRAY_SIZE);
448             oArr[oArr.Length / 2] = null;
449             Assert.IsTrue(CStyle_Array_Object_InOut(oArr, ARRAY_SIZE), "CStyle_Array_Object_InOut");
450
451             object[] expectedOArr = GetExpectedOutArray<object>(ARRAY_SIZE);
452             // Test nesting null value scenario
453             expectedOArr[expectedOArr.Length / 2 - 1] = null;
454             Assert.IsTrue(Equals<object>(oArr, expectedOArr), "CStyle_Array_Object_InOut:Equals<object>"); 
455         }
456     }
457
458     private static bool Equals<T>(T[] arr1, T[] arr2)
459     {
460         if (arr1 == null && arr2 == null)
461             return true;
462         else if (arr1 == null && arr2 != null)
463             return false;
464         else if (arr1 != null && arr2 == null)
465             return false;
466         else if (arr1.Length != arr2.Length)
467             return false;
468
469         for (int i = 0; i < arr2.Length; ++i)
470         {
471             if (!Object.Equals(arr1[i], arr2[i]))
472             {
473                 Console.WriteLine("Array marshaling error: Index: {0} :  Actual:{1}, Expected:{2},", i, arr1[i], arr2[i]);
474                 return false;
475             }
476         }
477
478         return true;
479     }
480
481     private static T[] GetExpectedOutArray<T>(int size)
482     {
483         T[] array = new T[size];
484
485         for (int i = array.Length - 1; i >= 0; --i)
486             array[i] = (T)Convert.ChangeType(array.Length - 1 - i, typeof(T));
487
488         return array;
489     }
490
491     private static bool[] GetExpectedOutBoolArray(int size)
492     {
493         bool[] array = new bool[size];
494
495         for (int i = 0; i < array.Length; ++i)
496         {
497             if (i % 2 != 0)
498                 array[i] = true;
499             else
500                 array[i] = false;
501         }
502
503         return array;
504     }
505
506     private static TestStruct[] GetExpectedOutStructArray(int size)
507     {
508         TestStruct[] array = new TestStruct[size];
509
510         for (int i = array.Length - 1; i >= 0; --i)
511         {
512             int v = array.Length - 1 - i;
513             array[i].x = v;
514             array[i].d = v;
515             array[i].l = v;
516             array[i].str = v.ToString();
517         }
518
519         return array;
520     }
521
522     #endregion
523
524     #region Marshal Out ByVal
525
526     private static void TestMarshalOut_ByVal()
527     {
528         Console.WriteLine("By value marshaling CLR array as c-style-array with OutAttribute applied");
529
530         Console.WriteLine("CStyle_Array_Int_Out");
531         int[] iArr = new int[ARRAY_SIZE];
532         Assert.IsTrue(CStyle_Array_Int_Out(iArr, ARRAY_SIZE), "CStyle_Array_Int_Out");
533         Assert.IsTrue(Equals<int>(iArr, GetExpectedOutArray<int>(ARRAY_SIZE)), "CStyle_Array_Int_Out:Equals<int>");
534
535         Console.WriteLine("CStyle_Array_Int_Out_Null");
536         int[] iArrNull = null;
537         Assert.IsTrue(CStyle_Array_Int_Out_Null(iArrNull), "CStyle_Array_Int_Out_Null");
538         Assert.IsNull(iArrNull, "CStyle_Array_Int_Out_Null:Equals<null>");
539
540         Console.WriteLine("CStyle_Array_Int_Out_ZeroLength");
541         int[] iArrLength0 = new int[0];
542         Assert.IsTrue(CStyle_Array_Int_Out_ZeroLength(iArrLength0), "CStyle_Array_Int_Out_ZeroLength");
543         Assert.AreEqual(0, iArrLength0.Length, "CStyle_Array_Int_Out_ZeroLength:Length<!0>");
544
545         Console.WriteLine("CStyle_Array_Uint_Out");
546         uint[] uiArr = new uint[ARRAY_SIZE];
547         Assert.IsTrue(CStyle_Array_Uint_Out(uiArr, ARRAY_SIZE), "CStyle_Array_Uint_Out");
548         Assert.IsTrue(Equals<uint>(uiArr, GetExpectedOutArray<uint>(ARRAY_SIZE)), "CStyle_Array_Uint_Out:Equals<uint>");
549
550         Console.WriteLine("CStyle_Array_Short_Out");
551         short[] sArr = new short[ARRAY_SIZE];
552         Assert.IsTrue(CStyle_Array_Short_Out(sArr, ARRAY_SIZE), "CStyle_Array_Short_Out");
553         Assert.IsTrue(Equals<short>(sArr, GetExpectedOutArray<short>(ARRAY_SIZE)), "CStyle_Array_Short_Out:Equals<short>");
554
555         Console.WriteLine("CStyle_Array_Word_Out");
556         ushort[] usArr = new ushort[ARRAY_SIZE];
557         Assert.IsTrue(CStyle_Array_Word_Out(usArr, ARRAY_SIZE), "CStyle_Array_Word_Out");
558         Assert.IsTrue(Equals<ushort>(usArr, GetExpectedOutArray<ushort>(ARRAY_SIZE)), "CStyle_Array_Word_Out:Equals<ushort>");
559
560         Console.WriteLine("CStyle_Array_Long64_Out");
561         long[] lArr = new long[ARRAY_SIZE];
562         Assert.IsTrue(CStyle_Array_Long64_Out(lArr, ARRAY_SIZE), "CStyle_Array_Long64_Out");
563         Assert.IsTrue(Equals<long>(lArr, GetExpectedOutArray<long>(ARRAY_SIZE)), "CStyle_Array_Long64_Out:Equals<long>");
564
565         Console.WriteLine("CStyle_Array_ULong64_Out");
566         ulong[] ulArr = new ulong[ARRAY_SIZE];
567         Assert.IsTrue(CStyle_Array_ULong64_Out(ulArr, ARRAY_SIZE), "CStyle_Array_ULong64_Out");
568         Assert.IsTrue(Equals<ulong>(ulArr, GetExpectedOutArray<ulong>(ARRAY_SIZE)), "CStyle_Array_ULong64_Out:Equals<ulong>");
569
570         Console.WriteLine("CStyle_Array_Double_Out");
571         double[] dArr = new double[ARRAY_SIZE];
572         Assert.IsTrue(CStyle_Array_Double_Out(dArr, ARRAY_SIZE), "CStyle_Array_Double_Out");
573         Assert.IsTrue(Equals<double>(dArr, GetExpectedOutArray<double>(ARRAY_SIZE)), "CStyle_Array_Double_Out:Equals<double>");
574
575         Console.WriteLine("CStyle_Array_Float_Out");
576         float[] fArr = new float[ARRAY_SIZE];
577         Assert.IsTrue(CStyle_Array_Float_Out(fArr, ARRAY_SIZE), "CStyle_Array_Float_Out");
578         Assert.IsTrue(Equals<float>(fArr, GetExpectedOutArray<float>(ARRAY_SIZE)), "CStyle_Array_Float_Out:Equals<float>");
579
580         Console.WriteLine("CStyle_Array_Byte_Out");
581         byte[] bArr = new byte[ARRAY_SIZE];
582         Assert.IsTrue(CStyle_Array_Byte_Out(bArr, ARRAY_SIZE), "CStyle_Array_Byte_Out");
583         Assert.IsTrue(Equals<byte>(bArr, GetExpectedOutArray<byte>(ARRAY_SIZE)), "CStyle_Array_Byte_Out:Equals<byte>");
584
585         Console.WriteLine("CStyle_Array_Char_Out");
586         char[] cArr = new char[ARRAY_SIZE];
587         Assert.IsTrue(CStyle_Array_Char_Out(cArr, ARRAY_SIZE), "CStyle_Array_Char_Out");
588         Assert.IsTrue(Equals<char>(cArr, GetExpectedOutArray<char>(ARRAY_SIZE)), "CStyle_Array_Char_Out:Equals<char>");
589
590         Console.WriteLine("CStyle_Array_LPSTR_Out");
591         string[] strArr = new string[ARRAY_SIZE];
592         Assert.IsTrue(CStyle_Array_LPSTR_Out(strArr, ARRAY_SIZE), "CStyle_Array_LPSTR_Out");
593         string[] expectedArr = GetExpectedOutArray<string>(ARRAY_SIZE);
594         // Test nesting null value scenario
595         expectedArr[expectedArr.Length / 2 - 1] = null;
596         Assert.IsTrue(Equals<string>(strArr, expectedArr), "CStyle_Array_LPSTR_Out:Equals<string>");
597         Console.WriteLine("CStyle_Array_Struct_Out");
598         TestStruct[] tsArr = new TestStruct[ARRAY_SIZE];
599         Assert.IsTrue(CStyle_Array_Struct_Out(tsArr, ARRAY_SIZE), "CStyle_Array_Struct_Out");
600         Assert.IsTrue(Equals<TestStruct>(tsArr, GetExpectedOutStructArray(ARRAY_SIZE)), "Equals<TestStruct>");
601
602         Console.WriteLine("CStyle_Array_Bool_Out");
603         bool[] boolArr = new bool[ARRAY_SIZE];
604         Assert.IsTrue(CStyle_Array_Bool_Out(boolArr, ARRAY_SIZE), "CStyle_Array_Bool_Out");
605         Assert.IsTrue(Equals<bool>(boolArr, GetExpectedOutBoolArray(ARRAY_SIZE)), "CStyle_Array_Bool_Out:Equals<bool>");
606
607         if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
608         {
609             Console.WriteLine("CStyle_Array_Object_Out");
610             object[] oArr = new object[ARRAY_SIZE];
611             Assert.IsTrue(CStyle_Array_Object_Out(oArr, ARRAY_SIZE), "CStyle_Array_Object_Out");
612
613             object[] expectedOArr = GetExpectedOutArray<object>(ARRAY_SIZE);
614             // Test nesting null value scenario
615             expectedOArr[expectedOArr.Length / 2 - 1] = null;
616             Assert.IsTrue(Equals<object>(oArr, expectedOArr), "CStyle_Array_Object_Out:Equals<object>"); 
617         }
618     }
619
620     #endregion
621
622     public static int Main()
623     {
624         try
625         {
626             TestMarshalByVal_NoAttributes();
627             TestMarshalByVal_In();
628             TestMarshalInOut_ByVal();
629             TestMarshalOut_ByVal();
630             
631             Console.WriteLine("\nTest PASS.");
632             return 100;
633         }
634         catch (Exception e)
635         {
636             Console.WriteLine($"\nTEST FAIL: {e.Message}");
637             return 101;
638         }
639     }
640 }