New tests.
[mono.git] / mcs / class / corlib / Test / System.Reflection / FieldInfoTest.cs
1 //
2 // FieldInfoTest - NUnit Test Cases for the FieldInfo class
3 //
4 // Authors:
5 //      Zoltan Varga (vargaz@freemail.hu)
6 //      Gert Driesen (drieseng@users.sourceforge.net)
7 //
8 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Threading;
33 using System.Reflection;
34 #if !TARGET_JVM
35 using System.Reflection.Emit;
36 #endif // TARGET_JVM
37 using System.Runtime.InteropServices;
38
39 using NUnit.Framework;
40
41 namespace MonoTests.System.Reflection
42 {
43         [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 64)]
44         public class Class1
45         {
46                 [FieldOffset (32)]
47                 public int i;
48         }
49
50         [StructLayout(LayoutKind.Sequential)]
51         public class Class2
52         {
53                 [MarshalAsAttribute(UnmanagedType.Bool)]
54                 public int f0;
55
56                 [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)]
57                 public string[] f1;
58
59                 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=100)]
60                 public string f2;
61
62                 [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof (Marshal1), MarshalCookie="5")]
63                 public int f3;
64
65                 [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof (Marshal1), MarshalCookie = "5")]
66                 public object f4;
67
68                 [Obsolete]
69                 public int f5;
70         }
71
72         public class Class3 : Class2
73         {
74         }
75
76         [TestFixture]
77         public class FieldInfoTest
78         {
79                 [NonSerialized]
80                 public int i;
81
82                 [Test]
83                 public void IsDefined_AttributeType_Null ()
84                 {
85                         Type type = typeof (FieldInfoTest);
86                         FieldInfo field = type.GetField ("i");
87
88                         try {
89                                 field.IsDefined ((Type) null, false);
90                                 Assert.Fail ("#1");
91                         } catch (ArgumentNullException ex) {
92                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
93                                 Assert.IsNull (ex.InnerException, "#3");
94                                 Assert.IsNotNull (ex.Message, "#4");
95                                 Assert.IsNotNull (ex.ParamName, "#5");
96                                 Assert.AreEqual ("attributeType", ex.ParamName, "#6");
97                         }
98                 }
99
100                 [Test]
101                 public void GetCustomAttributes ()
102                 {
103                         object [] attrs;
104                         FieldInfo fi;
105
106                         fi = typeof (Class2).GetField ("f5");
107
108                         attrs = fi.GetCustomAttributes (false);
109                         Assert.AreEqual (1, attrs.Length, "#B1");
110                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#B2");
111                         attrs = fi.GetCustomAttributes (true);
112                         Assert.AreEqual (1, attrs.Length, "#B3");
113                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#B4");
114                         attrs = fi.GetCustomAttributes (typeof (MarshalAsAttribute), false);
115                         Assert.AreEqual (0, attrs.Length, "#B5");
116                         attrs = fi.GetCustomAttributes (typeof (MarshalAsAttribute), true);
117                         Assert.AreEqual (0, attrs.Length, "#B6");
118                         attrs = fi.GetCustomAttributes (typeof (ObsoleteAttribute), false);
119                         Assert.AreEqual (1, attrs.Length, "#B7");
120                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#B8");
121                         attrs = fi.GetCustomAttributes (typeof (ObsoleteAttribute), true);
122                         Assert.AreEqual (1, attrs.Length, "#B9");
123                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#B10");
124
125                         fi = typeof (Class3).GetField ("f5");
126
127                         attrs = fi.GetCustomAttributes (false);
128                         Assert.AreEqual (1, attrs.Length, "#D1");
129                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#D2");
130                         attrs = fi.GetCustomAttributes (true);
131                         Assert.AreEqual (1, attrs.Length, "#D3");
132                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#D4");
133                         attrs = fi.GetCustomAttributes (typeof (MarshalAsAttribute), false);
134                         Assert.AreEqual (0, attrs.Length, "#D5");
135                         attrs = fi.GetCustomAttributes (typeof (MarshalAsAttribute), true);
136                         Assert.AreEqual (0, attrs.Length, "#D6");
137                         attrs = fi.GetCustomAttributes (typeof (ObsoleteAttribute), false);
138                         Assert.AreEqual (1, attrs.Length, "#D7");
139                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#D8");
140                         attrs = fi.GetCustomAttributes (typeof (ObsoleteAttribute), true);
141                         Assert.AreEqual (1, attrs.Length, "#D9");
142                         Assert.AreEqual (typeof (ObsoleteAttribute), attrs [0].GetType (), "#D10");
143                 }
144
145                 [Test] // GetFieldFromHandle (RuntimeFieldHandle)
146                 public void GetFieldFromHandle1_Handle_Zero ()
147                 {
148                         RuntimeFieldHandle fh = new RuntimeFieldHandle ();
149
150                         try {
151                                 FieldInfo.GetFieldFromHandle (fh);
152                                 Assert.Fail ("#1");
153                         } catch (ArgumentException ex) {
154                                 // Handle is not initialized
155                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
156                                 Assert.IsNull (ex.InnerException, "#3");
157                                 Assert.IsNotNull (ex.Message, "#4");
158                                 Assert.IsNull (ex.ParamName, "#5");
159                         }
160                 }
161
162 #if NET_2_0
163                 [Test] // GetFieldFromHandle (RuntimeFieldHandle, RuntimeTypeHandle)
164                 public void GetFieldFromHandle2_DeclaringType_Zero ()
165                 {
166                         RuntimeTypeHandle th = new RuntimeTypeHandle ();
167                         FieldInfo fi1 = typeof (Class2).GetField ("f5");
168                         RuntimeFieldHandle fh = fi1.FieldHandle;
169
170                         FieldInfo fi2 = FieldInfo.GetFieldFromHandle (fh, th);
171                         Assert.IsNotNull (fi2, "#1");
172                         Assert.AreSame (fi1.DeclaringType, fi2.DeclaringType, "#2");
173                         Assert.AreEqual (fi1.FieldType, fi2.FieldType, "#3");
174                         Assert.AreEqual (fi1.Name, fi2.Name, "#4");
175                 }
176
177                 [Test] // GetFieldFromHandle (RuntimeFieldHandle, RuntimeTypeHandle)
178                 public void GetFieldFromHandle2_Handle_Generic ()
179                 {
180                         FieldInfoTest<string> instance = new FieldInfoTest<string> ();
181                         Type t = instance.GetType ();
182
183                         FieldInfo fi1 = t.GetField ("TestField");
184                         RuntimeFieldHandle fh = fi1.FieldHandle;
185                         RuntimeTypeHandle th = t.TypeHandle;
186
187                         FieldInfo fi2 = FieldInfo.GetFieldFromHandle (fh, th);
188                         Assert.IsNotNull (fi2, "#1");
189                         Assert.AreSame (t, fi2.DeclaringType, "#2");
190                         Assert.AreEqual (typeof (string), fi2.FieldType, "#3");
191                         Assert.AreEqual ("TestField", fi2.Name, "#4");
192                 }
193
194                 [Test] // GetFieldFromHandle (RuntimeFieldHandle, RuntimeTypeHandle)
195                 [Category ("NotWorking")]
196                 [Category ("NotDotNet")] // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=343449
197                 public void GetFieldFromHandle2_Handle_GenericDefinition ()
198                 {
199                         Type t1 = typeof (FieldInfoTest<>);
200                         FieldInfo fi1 = t1.GetField ("TestField");
201                         RuntimeFieldHandle fh = fi1.FieldHandle;
202
203                         FieldInfoTest<string> instance = new FieldInfoTest<string> ();
204                         Type t2 = instance.GetType ();
205                         RuntimeTypeHandle th = t2.TypeHandle;
206
207                         FieldInfo fi2 = FieldInfo.GetFieldFromHandle (fh, th);
208                         Assert.IsNotNull (fi2, "#1");
209                         Assert.AreSame (t2, fi2.DeclaringType, "#2");
210                         Assert.AreEqual (typeof (string), fi2.FieldType, "#3");
211                         Assert.AreEqual ("TestField", fi2.Name, "#4");
212                 }
213
214                 [Test] // GetFieldFromHandle (RuntimeFieldHandle, RuntimeTypeHandle)
215                 public void GetFieldFromHandle2_Handle_Zero ()
216                 {
217                         object instance = new Class2 ();
218                         RuntimeTypeHandle th = Type.GetTypeHandle (instance);
219                         RuntimeFieldHandle fh = new RuntimeFieldHandle ();
220
221                         try {
222                                 FieldInfo.GetFieldFromHandle (fh, th);
223                                 Assert.Fail ("#1");
224                         } catch (ArgumentException ex) {
225                                 // Handle is not initialized
226                                 Assert.AreEqual (typeof (ArgumentException), ex.GetType (), "#2");
227                                 Assert.IsNull (ex.InnerException, "#3");
228                                 Assert.IsNotNull (ex.Message, "#4");
229                                 Assert.IsNull (ex.ParamName, "#5");
230                         }
231                 }
232
233                 [Test]
234                 [ExpectedException (typeof (ArgumentException))]
235                 public void GetFieldFromHandle2_Incompatible ()
236                 {
237                         RuntimeFieldHandle fh = typeof (FieldInfoTest<int>).GetField ("TestField").FieldHandle;
238
239                         FieldInfoTest<string> instance = new FieldInfoTest<string> ();
240                         Type t2 = instance.GetType ();
241                         RuntimeTypeHandle th = t2.TypeHandle;
242
243                         FieldInfo fi2 = FieldInfo.GetFieldFromHandle (fh, th);
244                 }
245 #endif
246
247                 [Test]
248                 public void PseudoCustomAttributes ()
249                 {
250                         object [] attrs;
251                         Type t = typeof (FieldInfoTest);
252
253 #if NET_2_0
254                         Assert.AreEqual (1, t.GetField ("i").GetCustomAttributes (typeof (NonSerializedAttribute), true).Length);
255 #else
256                         Assert.AreEqual (0, t.GetField ("i").GetCustomAttributes (typeof (NonSerializedAttribute), true).Length);
257 #endif
258
259                         attrs = typeof (Class1).GetField ("i").GetCustomAttributes (true);
260 #if NET_2_0
261                         Assert.AreEqual (1, attrs.Length, "#B1");
262                         FieldOffsetAttribute field_attr = (FieldOffsetAttribute) attrs [0];
263                         Assert.AreEqual (32, field_attr.Value, "#B2");
264 #else
265                         Assert.AreEqual (0, attrs.Length, "#B1");
266 #endif
267
268                         MarshalAsAttribute attr;
269
270                         attrs = typeof (Class2).GetField ("f0").GetCustomAttributes (true);
271 #if NET_2_0
272                         Assert.AreEqual (1, attrs.Length, "#C1");
273                         attr = (MarshalAsAttribute) attrs [0];
274                         Assert.AreEqual (UnmanagedType.Bool, attr.Value, "#C2");
275 #else
276                         Assert.AreEqual (0, attrs.Length, "#C1");
277 #endif
278
279                         attrs = typeof (Class2).GetField ("f1").GetCustomAttributes (true);
280 #if NET_2_0
281                         Assert.AreEqual (1, attrs.Length, "#D1");
282                         attr = (MarshalAsAttribute) attrs [0];
283                         Assert.AreEqual (UnmanagedType.LPArray, attr.Value, "#D2");
284                         Assert.AreEqual (UnmanagedType.LPStr, attr.ArraySubType, "#D3");
285 #else
286                         Assert.AreEqual (0, attrs.Length, "#D1");
287 #endif
288
289                         attrs = typeof (Class2).GetField ("f2").GetCustomAttributes (true);
290 #if NET_2_0
291                         Assert.AreEqual (1, attrs.Length, "#E1");
292                         attr = (MarshalAsAttribute) attrs [0];
293                         Assert.AreEqual (UnmanagedType.ByValTStr, attr.Value, "#E2");
294                         Assert.AreEqual (100, attr.SizeConst, "#E3");
295 #else
296                         Assert.AreEqual (0, attrs.Length, "#E1");
297 #endif
298
299                         attrs = typeof (Class2).GetField ("f3").GetCustomAttributes (true);
300 #if NET_2_0
301                         Assert.AreEqual (1, attrs.Length, "#F1");
302                         attr = (MarshalAsAttribute) attrs [0];
303                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#F2");
304                         Assert.AreEqual ("5", attr.MarshalCookie, "#F3");
305                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#F4");
306 #else
307                         Assert.AreEqual (0, attrs.Length, "#F1");
308 #endif
309
310                         attrs = typeof (Class3).GetField ("f3").GetCustomAttributes (false);
311 #if NET_2_0
312                         Assert.AreEqual (1, attrs.Length, "#G1");
313                         attr = (MarshalAsAttribute) attrs [0];
314                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#G2");
315                         Assert.AreEqual ("5", attr.MarshalCookie, "#G3");
316                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#G4");
317 #else
318                         Assert.AreEqual (0, attrs.Length, "#G1");
319 #endif
320
321                         attrs = typeof (Class3).GetField ("f3").GetCustomAttributes (true);
322 #if NET_2_0
323                         Assert.AreEqual (1, attrs.Length, "#H1");
324                         attr = (MarshalAsAttribute) attrs [0];
325                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#H2");
326                         Assert.AreEqual ("5", attr.MarshalCookie, "#H3");
327                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#H4");
328 #else
329                         Assert.AreEqual (0, attrs.Length, "#H1");
330 #endif
331
332                         // bug #82465
333                         attrs = typeof (Class2).GetField ("f3").GetCustomAttributes (true);
334 #if NET_2_0
335                         Assert.AreEqual (1, attrs.Length, "#I1");
336                         attr = (MarshalAsAttribute) attrs [0];
337                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#I2");
338                         Assert.AreEqual ("5", attr.MarshalCookie, "#I3");
339                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#I4");
340 #else
341                         Assert.AreEqual (0, attrs.Length, "#I1");
342 #endif
343                 }
344
345                 class Foo {
346                         public static int static_field;
347                         public int field;
348                 }
349
350                 [ExpectedException (typeof (ArgumentException))]
351                 public void GetValueWrongObject ()
352                 {
353                         Foo f = new Foo ();
354
355                         typeof (Foo).GetField ("field").GetValue (typeof (int));
356                 }
357
358                 public void GetValueWrongObjectStatic ()
359                 {
360                         Foo f = new Foo ();
361
362                         // This is allowed in MS.NET
363                         typeof (Foo).GetField ("static_field").GetValue (typeof (int));
364                 }
365
366 #if NET_2_0
367 #if !TARGET_JVM // ReflectionOnlyLoad not supported for TARGET_JVM
368                 [Test]
369                 [ExpectedException (typeof (InvalidOperationException))]
370                 public void GetValueOnRefOnlyAssembly ()
371                 {
372                         Assembly assembly = Assembly.ReflectionOnlyLoad (typeof (FieldInfoTest).Assembly.FullName);
373                         Type t = assembly.GetType (typeof (RefOnlyFieldClass).FullName);
374                         FieldInfo f = t.GetField ("RefOnlyField", BindingFlags.Static | BindingFlags.NonPublic);
375                         f.GetValue (null);
376                 }
377         
378                 [Test]
379                 [ExpectedException (typeof (InvalidOperationException))]
380                 public void SetValueOnRefOnlyAssembly ()
381                 {
382                         Assembly assembly = Assembly.ReflectionOnlyLoad (typeof (FieldInfoTest).Assembly.FullName);
383                         Type t = assembly.GetType (typeof (RefOnlyFieldClass).FullName);
384                         FieldInfo f = t.GetField ("RefOnlyField", BindingFlags.Static | BindingFlags.NonPublic);
385                         f.SetValue (null, 8);
386                 }
387 #endif // TARGET_JVM
388
389                 const int literal = 42;
390
391                 [Test]
392                 [ExpectedException (typeof (FieldAccessException))]
393                 public void SetValueOnLiteralField ()
394                 {
395                         FieldInfo f = typeof (FieldInfoTest).GetField ("literal", BindingFlags.Static | BindingFlags.NonPublic);
396                         f.SetValue (null, 0);
397                 }
398
399                 public int? nullable_field;
400
401                 public static int? static_nullable_field;
402
403                 [Test]
404                 public void NullableTests ()
405                 {
406                         FieldInfoTest t = new FieldInfoTest ();
407
408                         FieldInfo fi = typeof (FieldInfoTest).GetField ("nullable_field");
409
410                         fi.SetValue (t, 101);
411                         Assert.AreEqual (101, fi.GetValue (t));
412                         fi.SetValue (t, null);
413                         Assert.AreEqual (null, fi.GetValue (t));
414
415                         FieldInfo fi2 = typeof (FieldInfoTest).GetField ("static_nullable_field");
416
417                         fi2.SetValue (t, 101);
418                         Assert.AreEqual (101, fi2.GetValue (t));
419                         fi2.SetValue (t, null);
420                         Assert.AreEqual (null, fi2.GetValue (t));
421                 }
422         
423 #if !TARGET_JVM // TypeBuilder not supported for TARGET_JVM
424                 [Test]
425                 public void NonPublicTests ()
426                 {
427                         Assembly assembly = Assembly.ReflectionOnlyLoad (typeof (FieldInfoTest).Assembly.FullName);
428                 
429                         Type t = assembly.GetType (typeof (NonPublicFieldClass).FullName);
430
431                         // try to get non-public field
432                         FieldInfo fi = t.GetField ("protectedField");
433                         Assert.IsNull (fi);
434                         // get it for real
435                         fi = t.GetField ("protectedField", BindingFlags.NonPublic | BindingFlags.Instance);
436                         Assert.IsNotNull (fi);
437                 }
438 #endif // TARGET_JVM
439
440                 [Test]
441                 public void GetRawDefaultValue ()
442                 {
443                         Assert.AreEqual (5, typeof (FieldInfoTest).GetField ("int_field").GetRawConstantValue ());
444                         Assert.AreEqual (Int64.MaxValue, typeof (FieldInfoTest).GetField ("long_field").GetRawConstantValue ());
445                         Assert.AreEqual (2, typeof (FieldInfoTest).GetField ("int_enum_field").GetRawConstantValue ());
446                         Assert.AreEqual (typeof (int), typeof (FieldInfoTest).GetField ("int_enum_field").GetRawConstantValue ().GetType ());
447                         Assert.AreEqual (2, typeof (FieldInfoTest).GetField ("long_enum_field").GetRawConstantValue ());
448                         Assert.AreEqual (typeof (long), typeof (FieldInfoTest).GetField ("long_enum_field").GetRawConstantValue ().GetType ());
449                         Assert.AreEqual ("Hello", typeof (FieldInfoTest).GetField ("string_field").GetRawConstantValue ());
450                         Assert.AreEqual (null, typeof (FieldInfoTest).GetField ("object_field").GetRawConstantValue ());
451                 }
452
453                 [Test]
454                 [ExpectedException (typeof (InvalidOperationException))]
455                 public void GetRawDefaultValueNoDefault ()
456                 {
457                         typeof (FieldInfoTest).GetField ("non_const_field").GetRawConstantValue ();
458                 }
459
460                 [Test]
461                 [ExpectedException (typeof (InvalidOperationException))]
462                 public void GetValueOpenGeneric ()
463                 {
464                         typeof(Foo<>).GetField ("field").GetValue (null);
465                 }
466
467                 [Test]
468                 [ExpectedException (typeof (InvalidOperationException))]
469                 public void SetValueOpenGeneric ()
470                 {
471                         typeof(Foo<>).GetField ("field").SetValue (null, 0);
472                 }
473
474                 [Test]
475                 public void GetValueOnConstantOfOpenGeneric ()
476                 {
477                         Assert.AreEqual (10, typeof(Foo<>).GetField ("constant").GetValue (null), "#1");
478                         Assert.AreEqual ("waa", typeof(Foo<>).GetField ("sconstant").GetValue (null), "#2");
479                         Assert.AreEqual (IntEnum.Third, typeof(Foo<>).GetField ("econstant").GetValue (null), "#3");
480                 }
481
482                 public class Foo<T>
483                 {
484                          /*
485                         The whole point of this field is to make sure we don't create the vtable layout
486                         when loading the value of constants for Foo<>. See bug #594942.
487
488                         */
489                         public T dummy;
490                         public static int field;
491                         public const int constant = 10;
492                         public const string sconstant = "waa";
493                         public const IntEnum econstant = IntEnum.Third;
494                 }
495
496                 public enum IntEnum {
497                         First = 1,
498                         Second = 2,
499                         Third = 3
500                 }
501
502                 public enum LongEnum : long {
503                         First = 1,
504                         Second = 2,
505                         Third = 3
506                 }
507
508                 public const int int_field = 5;
509                 public const long long_field = Int64.MaxValue;
510                 public const IntEnum int_enum_field = IntEnum.Second;
511                 public const LongEnum long_enum_field = LongEnum.Second;
512                 public const string string_field = "Hello";
513                 public const FieldInfoTest object_field = null;
514                 public int non_const_field;
515         
516 #endif
517         }
518
519 #if NET_2_0
520         // Helper classes
521         class RefOnlyFieldClass 
522         {
523                 // Helper property
524                 static int RefOnlyField;
525         }
526
527         class NonPublicFieldClass
528         {
529                 protected int protectedField;
530         }
531
532         public class FieldInfoTest<T>
533         {
534                 public T TestField;
535         }
536 #endif
537 }