2008-12-08 Atsushi Enomoto <atsushi@ximian.com>
[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 #endif
233
234                 [Test]
235                 public void PseudoCustomAttributes ()
236                 {
237                         object [] attrs;
238                         Type t = typeof (FieldInfoTest);
239
240 #if NET_2_0
241                         Assert.AreEqual (1, t.GetField ("i").GetCustomAttributes (typeof (NonSerializedAttribute), true).Length);
242 #else
243                         Assert.AreEqual (0, t.GetField ("i").GetCustomAttributes (typeof (NonSerializedAttribute), true).Length);
244 #endif
245
246                         attrs = typeof (Class1).GetField ("i").GetCustomAttributes (true);
247 #if NET_2_0
248                         Assert.AreEqual (1, attrs.Length, "#B1");
249                         FieldOffsetAttribute field_attr = (FieldOffsetAttribute) attrs [0];
250                         Assert.AreEqual (32, field_attr.Value, "#B2");
251 #else
252                         Assert.AreEqual (0, attrs.Length, "#B1");
253 #endif
254
255                         MarshalAsAttribute attr;
256
257                         attrs = typeof (Class2).GetField ("f0").GetCustomAttributes (true);
258 #if NET_2_0
259                         Assert.AreEqual (1, attrs.Length, "#C1");
260                         attr = (MarshalAsAttribute) attrs [0];
261                         Assert.AreEqual (UnmanagedType.Bool, attr.Value, "#C2");
262 #else
263                         Assert.AreEqual (0, attrs.Length, "#C1");
264 #endif
265
266                         attrs = typeof (Class2).GetField ("f1").GetCustomAttributes (true);
267 #if NET_2_0
268                         Assert.AreEqual (1, attrs.Length, "#D1");
269                         attr = (MarshalAsAttribute) attrs [0];
270                         Assert.AreEqual (UnmanagedType.LPArray, attr.Value, "#D2");
271                         Assert.AreEqual (UnmanagedType.LPStr, attr.ArraySubType, "#D3");
272 #else
273                         Assert.AreEqual (0, attrs.Length, "#D1");
274 #endif
275
276                         attrs = typeof (Class2).GetField ("f2").GetCustomAttributes (true);
277 #if NET_2_0
278                         Assert.AreEqual (1, attrs.Length, "#E1");
279                         attr = (MarshalAsAttribute) attrs [0];
280                         Assert.AreEqual (UnmanagedType.ByValTStr, attr.Value, "#E2");
281                         Assert.AreEqual (100, attr.SizeConst, "#E3");
282 #else
283                         Assert.AreEqual (0, attrs.Length, "#E1");
284 #endif
285
286                         attrs = typeof (Class2).GetField ("f3").GetCustomAttributes (true);
287 #if NET_2_0
288                         Assert.AreEqual (1, attrs.Length, "#F1");
289                         attr = (MarshalAsAttribute) attrs [0];
290                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#F2");
291                         Assert.AreEqual ("5", attr.MarshalCookie, "#F3");
292                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#F4");
293 #else
294                         Assert.AreEqual (0, attrs.Length, "#F1");
295 #endif
296
297                         attrs = typeof (Class3).GetField ("f3").GetCustomAttributes (false);
298 #if NET_2_0
299                         Assert.AreEqual (1, attrs.Length, "#G1");
300                         attr = (MarshalAsAttribute) attrs [0];
301                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#G2");
302                         Assert.AreEqual ("5", attr.MarshalCookie, "#G3");
303                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#G4");
304 #else
305                         Assert.AreEqual (0, attrs.Length, "#G1");
306 #endif
307
308                         attrs = typeof (Class3).GetField ("f3").GetCustomAttributes (true);
309 #if NET_2_0
310                         Assert.AreEqual (1, attrs.Length, "#H1");
311                         attr = (MarshalAsAttribute) attrs [0];
312                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#H2");
313                         Assert.AreEqual ("5", attr.MarshalCookie, "#H3");
314                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#H4");
315 #else
316                         Assert.AreEqual (0, attrs.Length, "#H1");
317 #endif
318
319                         // bug #82465
320                         attrs = typeof (Class2).GetField ("f3").GetCustomAttributes (true);
321 #if NET_2_0
322                         Assert.AreEqual (1, attrs.Length, "#I1");
323                         attr = (MarshalAsAttribute) attrs [0];
324                         Assert.AreEqual (UnmanagedType.CustomMarshaler, attr.Value, "#I2");
325                         Assert.AreEqual ("5", attr.MarshalCookie, "#I3");
326                         Assert.AreEqual (typeof (Marshal1), Type.GetType (attr.MarshalType), "#I4");
327 #else
328                         Assert.AreEqual (0, attrs.Length, "#I1");
329 #endif
330                 }
331
332                 class Foo {
333                         public static int static_field;
334                         public int field;
335                 }
336
337                 [ExpectedException (typeof (ArgumentException))]
338                 public void GetValueWrongObject ()
339                 {
340                         Foo f = new Foo ();
341
342                         typeof (Foo).GetField ("field").GetValue (typeof (int));
343                 }
344
345                 public void GetValueWrongObjectStatic ()
346                 {
347                         Foo f = new Foo ();
348
349                         // This is allowed in MS.NET
350                         typeof (Foo).GetField ("static_field").GetValue (typeof (int));
351                 }
352
353 #if NET_2_0
354 #if !TARGET_JVM // ReflectionOnlyLoad not supported for TARGET_JVM
355                 [Test]
356                 [ExpectedException (typeof (InvalidOperationException))]
357                 public void GetValueOnRefOnlyAssembly ()
358                 {
359                         Assembly assembly = Assembly.ReflectionOnlyLoad (typeof (FieldInfoTest).Assembly.FullName);
360                         Type t = assembly.GetType (typeof (RefOnlyFieldClass).FullName);
361                         FieldInfo f = t.GetField ("RefOnlyField", BindingFlags.Static | BindingFlags.NonPublic);
362                         f.GetValue (null);
363                 }
364         
365                 [Test]
366                 [ExpectedException (typeof (InvalidOperationException))]
367                 public void SetValueOnRefOnlyAssembly ()
368                 {
369                         Assembly assembly = Assembly.ReflectionOnlyLoad (typeof (FieldInfoTest).Assembly.FullName);
370                         Type t = assembly.GetType (typeof (RefOnlyFieldClass).FullName);
371                         FieldInfo f = t.GetField ("RefOnlyField", BindingFlags.Static | BindingFlags.NonPublic);
372                         f.SetValue (null, 8);
373                 }
374 #endif // TARGET_JVM
375
376                 const int literal = 42;
377
378                 [Test]
379                 [ExpectedException (typeof (FieldAccessException))]
380                 public void SetValueOnLiteralField ()
381                 {
382                         FieldInfo f = typeof (FieldInfoTest).GetField ("literal", BindingFlags.Static | BindingFlags.NonPublic);
383                         f.SetValue (null, 0);
384                 }
385
386                 public int? nullable_field;
387
388                 public static int? static_nullable_field;
389
390                 [Test]
391                 public void NullableTests ()
392                 {
393                         FieldInfoTest t = new FieldInfoTest ();
394
395                         FieldInfo fi = typeof (FieldInfoTest).GetField ("nullable_field");
396
397                         fi.SetValue (t, 101);
398                         Assert.AreEqual (101, fi.GetValue (t));
399                         fi.SetValue (t, null);
400                         Assert.AreEqual (null, fi.GetValue (t));
401
402                         FieldInfo fi2 = typeof (FieldInfoTest).GetField ("static_nullable_field");
403
404                         fi2.SetValue (t, 101);
405                         Assert.AreEqual (101, fi2.GetValue (t));
406                         fi2.SetValue (t, null);
407                         Assert.AreEqual (null, fi2.GetValue (t));
408                 }
409         
410 #if !TARGET_JVM // TypeBuilder not supported for TARGET_JVM
411                 [Test]
412                 public void NonPublicTests ()
413                 {
414                         Assembly assembly = Assembly.ReflectionOnlyLoad (typeof (FieldInfoTest).Assembly.FullName);
415                 
416                         Type t = assembly.GetType (typeof (NonPublicFieldClass).FullName);
417
418                         // try to get non-public field
419                         FieldInfo fi = t.GetField ("protectedField");
420                         Assert.IsNull (fi);
421                         // get it for real
422                         fi = t.GetField ("protectedField", BindingFlags.NonPublic | BindingFlags.Instance);
423                         Assert.IsNotNull (fi);
424                         // get via typebuilder
425                         FieldInfo f = TypeBuilder.GetField (t, fi);
426                         Assert.IsNotNull (f);
427                 }
428 #endif // TARGET_JVM
429
430                 [Test]
431                 public void GetRawDefaultValue ()
432                 {
433                         Assert.AreEqual (5, typeof (FieldInfoTest).GetField ("int_field").GetRawConstantValue ());
434                         Assert.AreEqual (Int64.MaxValue, typeof (FieldInfoTest).GetField ("long_field").GetRawConstantValue ());
435                         Assert.AreEqual (2, typeof (FieldInfoTest).GetField ("int_enum_field").GetRawConstantValue ());
436                         Assert.AreEqual (typeof (int), typeof (FieldInfoTest).GetField ("int_enum_field").GetRawConstantValue ().GetType ());
437                         Assert.AreEqual (2, typeof (FieldInfoTest).GetField ("long_enum_field").GetRawConstantValue ());
438                         Assert.AreEqual (typeof (long), typeof (FieldInfoTest).GetField ("long_enum_field").GetRawConstantValue ().GetType ());
439                         Assert.AreEqual ("Hello", typeof (FieldInfoTest).GetField ("string_field").GetRawConstantValue ());
440                         Assert.AreEqual (null, typeof (FieldInfoTest).GetField ("object_field").GetRawConstantValue ());
441                 }
442
443                 [Test]
444                 [ExpectedException (typeof (InvalidOperationException))]
445                 public void GetRawDefaultValueNoDefault ()
446                 {
447                         typeof (FieldInfoTest).GetField ("non_const_field").GetRawConstantValue ();
448                 }
449
450 #if NET_2_0
451                 [Test]
452                 [ExpectedException (typeof (InvalidOperationException))]
453                 public void GetValueOpenGeneric ()
454                 {
455                         typeof(Foo<>).GetField ("field").GetValue (null);
456                 }
457
458                 [Test]
459                 [ExpectedException (typeof (InvalidOperationException))]
460                 public void SetValueOpenGeneric ()
461                 {
462                         typeof(Foo<>).GetField ("field").SetValue (null, 0);
463                 }
464
465                 [Test]
466                 public void GetValueOnConstantOfOpenGeneric ()
467                 {
468                         Assert.AreEqual (10, typeof(Foo<>).GetField ("constant").GetValue (null), "#1");
469                 }
470
471                 public class Foo<T>
472                 {
473                         public static int field;
474                         public const int constant = 10;
475                 }
476 #endif
477
478                 public enum IntEnum {
479                         First = 1,
480                         Second = 2,
481                         Third = 3
482                 }
483
484                 public enum LongEnum : long {
485                         First = 1,
486                         Second = 2,
487                         Third = 3
488                 }
489
490                 public const int int_field = 5;
491                 public const long long_field = Int64.MaxValue;
492                 public const IntEnum int_enum_field = IntEnum.Second;
493                 public const LongEnum long_enum_field = LongEnum.Second;
494                 public const string string_field = "Hello";
495                 public const FieldInfoTest object_field = null;
496                 public int non_const_field;
497         
498 #endif
499         }
500
501 #if NET_2_0
502         // Helper classes
503         class RefOnlyFieldClass 
504         {
505                 // Helper property
506                 static int RefOnlyField;
507         }
508
509         class NonPublicFieldClass
510         {
511                 protected int protectedField;
512         }
513
514         public class FieldInfoTest<T>
515         {
516                 public T TestField;
517         }
518 #endif
519 }