Merge pull request #1949 from lewurm/fixtype
[mono.git] / mcs / class / corlib / Test / System.Reflection / PropertyInfoTest.cs
1 //
2 // PropertyInfoTest.cs - NUnit Test Cases for PropertyInfo
3 //
4 // Author:
5 //      Gert Driesen (drieseng@users.sourceforge.net)
6 //
7 // (C) 2004-2007 Gert Driesen
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29
30 using System;
31 using System.Reflection;
32 using System.Runtime.InteropServices;
33 using System.Threading;
34 #if !MONOTOUCH
35 using System.Reflection.Emit;
36 #endif
37 using System.IO;
38
39 using NUnit.Framework;
40
41 namespace MonoTests.System.Reflection
42 {
43         [TestFixture]
44         public class PropertyInfoTest
45         {
46                 [Test]
47                 public void GetAccessorsTest ()
48                 {
49                         Type type = typeof (TestClass);
50                         PropertyInfo property = type.GetProperty ("ReadOnlyProperty");
51                         Assert.IsNotNull (property.Module, "#0");
52
53                         MethodInfo [] methods = property.GetAccessors (true);
54                         Assert.AreEqual (1, methods.Length, "#A1");
55                         Assert.IsNotNull (methods [0], "#A2");
56                         Assert.AreEqual ("get_ReadOnlyProperty", methods [0].Name, "#A3");
57
58                         methods = property.GetAccessors (false);
59                         Assert.AreEqual (1, methods.Length, "#B1");
60                         Assert.IsNotNull (methods [0], "#B2");
61                         Assert.AreEqual ("get_ReadOnlyProperty", methods [0].Name, "#B3");
62
63                         property = typeof (Base).GetProperty ("P");
64
65                         methods = property.GetAccessors (true);
66                         Assert.AreEqual (2, methods.Length, "#C1");
67                         Assert.IsNotNull (methods [0], "#C2");
68                         Assert.IsNotNull (methods [1], "#C3");
69                         Assert.IsTrue (HasMethod (methods, "get_P"), "#C4");
70                         Assert.IsTrue (HasMethod (methods, "set_P"), "#C5");
71
72                         methods = property.GetAccessors (false);
73                         Assert.AreEqual (2, methods.Length, "#D1");
74                         Assert.IsNotNull (methods [0], "#D2");
75                         Assert.IsNotNull (methods [1], "#D3");
76                         Assert.IsTrue (HasMethod (methods, "get_P"), "#D4");
77                         Assert.IsTrue (HasMethod (methods, "set_P"), "#D5");
78
79                         methods = property.GetAccessors ();
80                         Assert.AreEqual (2, methods.Length, "#E1");
81                         Assert.IsNotNull (methods [0], "#E2");
82                         Assert.IsNotNull (methods [1], "#E3");
83                         Assert.IsTrue (HasMethod (methods, "get_P"), "#E4");
84                         Assert.IsTrue (HasMethod (methods, "set_P"), "#E5");
85
86                         property = typeof (TestClass).GetProperty ("Private",
87                                 BindingFlags.NonPublic | BindingFlags.Instance);
88
89                         methods = property.GetAccessors (true);
90                         Assert.AreEqual (2, methods.Length, "#F1");
91                         Assert.IsNotNull (methods [0], "#F2");
92                         Assert.IsNotNull (methods [1], "#F3");
93                         Assert.IsTrue (HasMethod (methods, "get_Private"), "#F4");
94                         Assert.IsTrue (HasMethod (methods, "set_Private"), "#F5");
95
96                         methods = property.GetAccessors (false);
97                         Assert.AreEqual (0, methods.Length, "#G");
98
99                         methods = property.GetAccessors ();
100                         Assert.AreEqual (0, methods.Length, "#H");
101
102                         property = typeof (TestClass).GetProperty ("PrivateSetter");
103
104                         methods = property.GetAccessors (true);
105                         Assert.AreEqual (2, methods.Length, "#H1");
106                         Assert.IsNotNull (methods [0], "#H2");
107                         Assert.IsNotNull (methods [1], "#H3");
108                         Assert.IsTrue (HasMethod (methods, "get_PrivateSetter"), "#H4");
109                         Assert.IsTrue (HasMethod (methods, "set_PrivateSetter"), "#H5");
110
111                         methods = property.GetAccessors (false);
112                         Assert.AreEqual (1, methods.Length, "#I1");
113                         Assert.IsNotNull (methods [0], "#I2");
114                         Assert.AreEqual ("get_PrivateSetter", methods [0].Name, "#I3");
115
116                         methods = property.GetAccessors ();
117                         Assert.AreEqual (1, methods.Length, "#J1");
118                         Assert.IsNotNull (methods [0], "#J2");
119                         Assert.AreEqual ("get_PrivateSetter", methods [0].Name, "#J3");
120                 }
121
122                 [Test]
123                 public void GetCustomAttributes ()
124                 {
125                         object [] attrs;
126                         PropertyInfo p = typeof (Base).GetProperty ("P");
127
128                         attrs = p.GetCustomAttributes (false);
129                         Assert.AreEqual (1, attrs.Length, "#A1");
130                         Assert.AreEqual (typeof (ThisAttribute), attrs [0].GetType (), "#A2");
131                         attrs = p.GetCustomAttributes (true);
132                         Assert.AreEqual (1, attrs.Length, "#A3");
133                         Assert.AreEqual (typeof (ThisAttribute), attrs [0].GetType (), "#A4");
134
135                         p = typeof (Base).GetProperty ("T");
136
137                         attrs = p.GetCustomAttributes (false);
138                         Assert.AreEqual (2, attrs.Length, "#B1");
139                         Assert.IsTrue (HasAttribute (attrs, typeof (ThisAttribute)), "#B2");
140                         Assert.IsTrue (HasAttribute (attrs, typeof (ComVisibleAttribute)), "#B3");
141                         attrs = p.GetCustomAttributes (true);
142                         Assert.AreEqual (2, attrs.Length, "#B41");
143                         Assert.IsTrue (HasAttribute (attrs, typeof (ThisAttribute)), "#B5");
144                         Assert.IsTrue (HasAttribute (attrs, typeof (ComVisibleAttribute)), "#B6");
145
146                         p = typeof (Base).GetProperty ("Z");
147
148                         attrs = p.GetCustomAttributes (false);
149                         Assert.AreEqual (0, attrs.Length, "#C1");
150                         attrs = p.GetCustomAttributes (true);
151                         Assert.AreEqual (0, attrs.Length, "#C2");
152                 }
153
154                 [Test]
155                 public void GetCustomAttributes_Inherited ()
156                 {
157                         object [] attrs;
158                         PropertyInfo p = typeof (Derived).GetProperty ("P");
159
160                         attrs = p.GetCustomAttributes (false);
161                         Assert.AreEqual (0, attrs.Length, "#A1");
162                         attrs = p.GetCustomAttributes (true);
163                         Assert.AreEqual (0, attrs.Length, "#A3");
164
165                         p = typeof (Derived).GetProperty ("T");
166
167                         attrs = p.GetCustomAttributes (false);
168                         Assert.AreEqual (2, attrs.Length, "#B1");
169                         Assert.IsTrue (HasAttribute (attrs, typeof (ThisAttribute)), "#B2");
170                         Assert.IsTrue (HasAttribute (attrs, typeof (ComVisibleAttribute)), "#B3");
171                         attrs = p.GetCustomAttributes (true);
172                         Assert.AreEqual (2, attrs.Length, "#B41");
173                         Assert.IsTrue (HasAttribute (attrs, typeof (ThisAttribute)), "#B5");
174                         Assert.IsTrue (HasAttribute (attrs, typeof (ComVisibleAttribute)), "#B6");
175
176                         p = typeof (Derived).GetProperty ("Z");
177
178                         attrs = p.GetCustomAttributes (false);
179                         Assert.AreEqual (0, attrs.Length, "#C1");
180                         attrs = p.GetCustomAttributes (true);
181                         Assert.AreEqual (0, attrs.Length, "#C2");
182                 }
183
184                 [Test]
185                 public void IsDefined_AttributeType_Null ()
186                 {
187                         Type derived = typeof (Derived);
188                         PropertyInfo pi = derived.GetProperty ("P");
189
190                         try {
191                                 pi.IsDefined ((Type) null, false);
192                                 Assert.Fail ("#1");
193                         } catch (ArgumentNullException ex) {
194                                 Assert.AreEqual (typeof (ArgumentNullException), ex.GetType (), "#2");
195                                 Assert.IsNull (ex.InnerException, "#3");
196                                 Assert.IsNotNull (ex.Message, "#4");
197                                 Assert.IsNotNull (ex.ParamName, "#5");
198                                 Assert.AreEqual ("attributeType", ex.ParamName, "#6");
199                         }
200                 }
201
202                 [Test]
203                 public void AccessorsReflectedType ()
204                 {
205                         PropertyInfo pi = typeof (Derived).GetProperty ("T");
206                         Assert.AreEqual (typeof (Derived), pi.GetGetMethod ().ReflectedType);
207                         Assert.AreEqual (typeof (Derived), pi.GetSetMethod ().ReflectedType);
208                 }
209
210                 [Test] // bug #399985
211                 public void SetValue_Enum ()
212                 {
213                         TestClass t = new TestClass ();
214                         PropertyInfo pi = t.GetType ().GetProperty ("Targets");
215                         pi.SetValue (t, AttributeTargets.Field, null);
216                         Assert.AreEqual (AttributeTargets.Field, t.Targets, "#1");
217                         pi.SetValue (t, (int) AttributeTargets.Interface, null);
218                         Assert.AreEqual (AttributeTargets.Interface, t.Targets, "#2");
219                 }
220
221                 public class ThisAttribute : Attribute
222                 {
223                 }
224
225                 class Base
226                 {
227                         [ThisAttribute]
228                         public virtual string P {
229                                 get { return null; }
230                                 set { }
231                         }
232
233                         [ThisAttribute]
234                         [ComVisible (false)]
235                         public virtual string T {
236                                 get { return null; }
237                                 set { }
238                         }
239
240                         public virtual string Z {
241                                 get { return null; }
242                                 set { }
243                         }
244                 }
245
246                 class Derived : Base
247                 {
248                         public override string P {
249                                 get { return null; }
250                                 set { }
251                         }
252                 }
253
254                 static void RunTest (Type t, bool use_getter) {
255                         var p = t.GetProperty ("Item");
256                         var idx = p.GetIndexParameters ();
257                         var m_args = t.GetMethod (use_getter ? "get_Item" : "set_Item").GetParameters ();
258
259                         Assert.AreEqual (2, idx.Length, "#1");
260
261                         Assert.AreEqual (typeof (double), idx [0].ParameterType, "#2");
262                         Assert.AreEqual (p, idx [0].Member, "#3");
263                         Assert.AreEqual ("a", idx [0].Name, "#4");
264                         Assert.AreEqual (0, idx [0].Position, "#5");
265                         Assert.AreEqual (m_args [0].MetadataToken, idx [0].MetadataToken, "#6");
266                         Assert.AreEqual (ParameterAttributes.None, idx [0].Attributes, "#7");
267
268                         Assert.AreEqual (typeof (string), idx [1].ParameterType, "#8");
269                         Assert.AreEqual (p, idx [1].Member, "#9");
270                         Assert.AreEqual ("b", idx [1].Name, "#10");
271                         Assert.AreEqual (1, idx [1].Position, "#11");
272                         Assert.AreEqual (m_args [1].MetadataToken, idx [1].MetadataToken, "#12");
273                         Assert.AreEqual (ParameterAttributes.None, idx [1].Attributes, "#13");
274
275                         var idx2 = p.GetIndexParameters ();
276
277                         //No interning exposed
278                         Assert.AreNotSame (idx, idx2, "#14");
279                         Assert.AreNotSame (idx [0], idx2 [1], "#15");
280                 }
281
282                 [Test]
283                 public void GetIndexParameterReturnsObjectsBoundToTheProperty ()
284                 {
285                         RunTest (typeof (TestA), false);
286                         RunTest (typeof (TestB), true);
287                 }
288
289                 public class TestA {
290                         public int this[double a, string b] {
291                                 set {}
292                         }
293                 }
294
295                 public class TestB {
296                         public int this[double a, string b] {
297                                 get { return 1; }
298                                 set {}
299                         }
300                 }
301
302                 [Test]
303                 public void GetIndexParameterReturnedObjectsCustomAttributes () {
304                         var pa = typeof (TestC).GetProperty ("Item").GetIndexParameters () [0];
305                         Assert.IsTrue (pa.IsDefined (typeof (ParamArrayAttribute), false), "#1");
306
307                         var pb = typeof (TestD).GetProperty ("Item").GetIndexParameters () [0];
308                         Assert.IsTrue (pb.IsDefined (typeof (ParamArrayAttribute), false), "#2");
309
310                         Assert.AreEqual (1, Attribute.GetCustomAttributes (pa).Length, "#3");
311                         Assert.AreEqual (1, Attribute.GetCustomAttributes (pb).Length, "#4");
312
313                         Assert.AreEqual (0, pa.GetOptionalCustomModifiers ().Length, "#5");
314                         Assert.AreEqual (0, pb.GetRequiredCustomModifiers ().Length, "#6");
315                 }
316
317                 public class TestC {
318                         public int this[params double[] a] {
319                                 get { return 99; }
320                         }
321                 }
322
323                 public class TestD {
324                         public int this[params double[] a] {
325                                 set { }
326                         }
327                 }
328
329                 static string CreateTempAssembly ()
330                 {
331                         FileStream f = null;
332                         string path;
333                         Random rnd;
334                         int num = 0;
335
336                         rnd = new Random ();
337                         do {
338                                 num = rnd.Next ();
339                                 num++;
340                                 path = Path.Combine (Path.GetTempPath (), "tmp" + num.ToString ("x") + ".dll");
341
342                                 try {
343                                         f = new FileStream (path, FileMode.CreateNew);
344                                 } catch { }
345                         } while (f == null);
346
347                         f.Close ();
348
349
350                         return "tmp" + num.ToString ("x") + ".dll";
351                 }
352
353                 public class TestE {
354                         public int PropE {
355                                 get { return 99; }
356                         }
357                 }
358 #if !MONOTOUCH
359                 [Test]
360                 public void ConstantValue () {
361                         /*This test looks scary because we can't generate a default value with C# */
362                         var assemblyName = new AssemblyName ();
363                         assemblyName.Name = "MonoTests.System.Reflection.Emit.PropertyInfoTest";
364                         string an = CreateTempAssembly ();
365
366                         var assembly = Thread.GetDomain ().DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.RunAndSave, Path.GetTempPath ());
367                         var module = assembly.DefineDynamicModule ("module1", an);
368
369                         var tb = module.DefineType ("Test", TypeAttributes.Public);
370                         var prop = tb.DefineProperty ("Prop", PropertyAttributes.HasDefault, typeof (string), new Type [0]);
371
372                         var getter = tb.DefineMethod ("get_Prop", MethodAttributes.Public, typeof (string), new Type [0]);
373                         var ilgen = getter.GetILGenerator ();
374                         ilgen.Emit (OpCodes.Ldnull);
375                         ilgen.Emit (OpCodes.Ret);
376
377                         var setter = tb.DefineMethod ("set_Prop", MethodAttributes.Public, null, new Type [1] { typeof (string) });
378                         setter.GetILGenerator ().Emit (OpCodes.Ret);
379
380                         prop.SetConstant ("test");
381                         prop.SetGetMethod (getter);
382                         prop.SetSetMethod (setter);
383
384                         tb.CreateType ();
385
386                         File.Delete (Path.Combine (Path.GetTempPath (), an));
387                         assembly.Save (an);
388
389                         var asm = Assembly.LoadFrom (Path.Combine (Path.GetTempPath (), an));
390                         var t = asm.GetType ("Test");
391                         var p = t.GetProperty ("Prop");
392                         Assert.AreEqual ("test", p.GetConstantValue (), "#1");
393
394                         File.Delete (Path.Combine (Path.GetTempPath (), an));
395
396                         var pa = typeof (TestE).GetProperty ("PropE");
397                         try {
398                                 pa.GetConstantValue ();
399                                 Assert.Fail ("#2");
400                         } catch (InvalidOperationException) {
401                         }
402                 }
403 #endif
404
405                 public class A<T>
406                 {
407                         public string Property {
408                                 get { return typeof (T).FullName; }
409                         }
410                 }
411
412                 public int? nullable_field;
413
414                 public int? NullableProperty {
415                         get { return nullable_field; }
416                         set { nullable_field = value; }
417                 }
418
419                 [Test]
420                 public void NullableTests ()
421                 {
422                         PropertyInfoTest t = new PropertyInfoTest ();
423
424                         PropertyInfo pi = typeof(PropertyInfoTest).GetProperty("NullableProperty");
425
426                         pi.SetValue (t, 100, null);
427                         Assert.AreEqual (100, pi.GetValue (t, null));
428                         pi.SetValue (t, null, null);
429                         Assert.AreEqual (null, pi.GetValue (t, null));
430                 }
431
432                 [Test]
433                 public void Bug77160 ()
434                 {
435                         object instance = new A<string> ();
436                         Type type = instance.GetType ();
437                         PropertyInfo property = type.GetProperty ("Property");
438                         Assert.AreEqual (typeof (string).FullName, property.GetValue (instance, null));
439                 }
440
441                 [Test]
442                 public void ToStringTest ()
443                 {
444                         var pa = typeof (TestC).GetProperty ("Item");
445                         Assert.AreEqual ("Int32 Item [Double[]]", pa.ToString ());
446                 }
447
448                 static bool HasAttribute (object [] attrs, Type attributeType)
449                 {
450                         foreach (object attr in attrs)
451                                 if (attr.GetType () == attributeType)
452                                         return true;
453                         return false;
454                 }
455
456                 static bool HasMethod (MethodInfo [] methods, string name)
457                 {
458                         foreach (MethodInfo method in methods)
459                                 if (method.Name == name)
460                                         return true;
461                         return false;
462                 }
463
464                 private class TestClass
465                 {
466                         private AttributeTargets _targets = AttributeTargets.Assembly;
467
468                         public AttributeTargets Targets {
469                                 get { return _targets; }
470                                 set { _targets = value; }
471                         }
472
473                         public string ReadOnlyProperty {
474                                 get { return string.Empty; }
475                         }
476
477                         private string Private {
478                                 get { return null; }
479                                 set { }
480                         }
481
482                         public string PrivateSetter {
483                                 get { return null; }
484                                 private set { }
485                         }
486                 }
487
488                 [Test] // bug #633671
489                 public void DeclaringTypeOfPropertyFromInheritedTypePointsToBase ()
490                 {
491                         var inherit1 = typeof(InheritsFromClassWithNullableDateTime);
492                         var siblingProperty = inherit1.GetProperty("Property1");
493
494                         Assert.AreEqual (typeof (ClassWithNullableDateTime), siblingProperty.DeclaringType, "#1");
495                         Assert.AreEqual (typeof (InheritsFromClassWithNullableDateTime), siblingProperty.ReflectedType, "#2");
496
497                         //The check is done twice since the bug is related to getting those 2 properties multiple times.
498                         Assert.AreEqual (typeof (ClassWithNullableDateTime), siblingProperty.DeclaringType, "#3");
499                         Assert.AreEqual (typeof (InheritsFromClassWithNullableDateTime), siblingProperty.ReflectedType, "#4");
500                 }
501
502                 class Super { public long A { get; private set; } }
503
504                 class Sub : Super { }
505
506                 [Test]
507                 public void PrivateSetterFromDerivedType ()
508                 {
509                         var prop = typeof (Sub).GetProperty ("A");
510                         Assert.AreEqual (1, prop.GetAccessors (true).Length, "#1");
511                         Assert.IsFalse (prop.CanWrite, "#2");
512                         Assert.IsNull (prop.GetSetMethod (true), "#3");
513                 }
514
515                 public class ClassWithNullableDateTime
516                 {
517                         public DateTime? Property1 { get; set; }
518                 }
519         
520                 public class InheritsFromClassWithNullableDateTime : ClassWithNullableDateTime
521                 {
522                 }
523
524                 public static int ThrowingProperty {
525                         get {
526                                 throw new ObjectDisposedException("TestClass");
527                         }
528                 }
529
530                 [Test]
531                 public void GetException () {
532                         var prop = typeof(PropertyInfoTest).GetProperty("ThrowingProperty");
533                         try {
534                                 prop.GetValue (null, null);
535                                 Assert.Fail ();
536                         } catch (TargetInvocationException ex) {
537                                 Assert.IsTrue (ex.InnerException is ObjectDisposedException);
538                         }
539                 }
540
541                 public class DefaultValueTest
542                 {
543                         public string this[int val, string param = "test"]
544                         {
545                                 get{ return val + param; }
546                         }
547                 }
548
549
550                 [Test]
551                 public void PropertyWithDefaultValue ()
552                 {
553                         var parameters = typeof (DefaultValueTest).GetProperty ("Item").GetIndexParameters ();
554                         var defaultParam = parameters[parameters.Length - 1];
555                         Assert.AreEqual ("param", defaultParam.Name, "#1");
556                         Assert.AreEqual ("test", defaultParam.DefaultValue, "#2");
557                 }
558         }
559 }