Rename the mobile_static profile to aot_only
[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 && !FULL_AOT_RUNTIME
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 && !FULL_AOT_RUNTIME
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                         try {
395                                 // This throws an exception under MS.NET and Mono on Windows,
396                                 // open files cannot be deleted. That's fine.
397                                 File.Delete (Path.Combine (Path.GetTempPath (), an));
398                         } catch (Exception) {
399                         }
400
401                         var pa = typeof (TestE).GetProperty ("PropE");
402                         try {
403                                 pa.GetConstantValue ();
404                                 Assert.Fail ("#2");
405                         } catch (InvalidOperationException) {
406                         }
407                 }
408 #endif
409
410                 public class A<T>
411                 {
412                         public string Property {
413                                 get { return typeof (T).FullName; }
414                         }
415                 }
416
417                 public int? nullable_field;
418
419                 public int? NullableProperty {
420                         get { return nullable_field; }
421                         set { nullable_field = value; }
422                 }
423
424                 [Test]
425                 public void NullableTests ()
426                 {
427                         PropertyInfoTest t = new PropertyInfoTest ();
428
429                         PropertyInfo pi = typeof(PropertyInfoTest).GetProperty("NullableProperty");
430
431                         pi.SetValue (t, 100, null);
432                         Assert.AreEqual (100, pi.GetValue (t, null));
433                         pi.SetValue (t, null, null);
434                         Assert.AreEqual (null, pi.GetValue (t, null));
435                 }
436
437                 [Test]
438                 public void Bug77160 ()
439                 {
440                         object instance = new A<string> ();
441                         Type type = instance.GetType ();
442                         PropertyInfo property = type.GetProperty ("Property");
443                         Assert.AreEqual (typeof (string).FullName, property.GetValue (instance, null));
444                 }
445
446                 [Test]
447                 public void ToStringTest ()
448                 {
449                         var pa = typeof (TestC).GetProperty ("Item");
450                         Assert.AreEqual ("Int32 Item [Double[]]", pa.ToString ());
451                 }
452
453                 static bool HasAttribute (object [] attrs, Type attributeType)
454                 {
455                         foreach (object attr in attrs)
456                                 if (attr.GetType () == attributeType)
457                                         return true;
458                         return false;
459                 }
460
461                 static bool HasMethod (MethodInfo [] methods, string name)
462                 {
463                         foreach (MethodInfo method in methods)
464                                 if (method.Name == name)
465                                         return true;
466                         return false;
467                 }
468
469                 private class TestClass
470                 {
471                         private AttributeTargets _targets = AttributeTargets.Assembly;
472
473                         public AttributeTargets Targets {
474                                 get { return _targets; }
475                                 set { _targets = value; }
476                         }
477
478                         public string ReadOnlyProperty {
479                                 get { return string.Empty; }
480                         }
481
482                         private string Private {
483                                 get { return null; }
484                                 set { }
485                         }
486
487                         public string PrivateSetter {
488                                 get { return null; }
489                                 private set { }
490                         }
491                 }
492
493                 [Test] // bug #633671
494                 public void DeclaringTypeOfPropertyFromInheritedTypePointsToBase ()
495                 {
496                         var inherit1 = typeof(InheritsFromClassWithNullableDateTime);
497                         var siblingProperty = inherit1.GetProperty("Property1");
498
499                         Assert.AreEqual (typeof (ClassWithNullableDateTime), siblingProperty.DeclaringType, "#1");
500                         Assert.AreEqual (typeof (InheritsFromClassWithNullableDateTime), siblingProperty.ReflectedType, "#2");
501
502                         //The check is done twice since the bug is related to getting those 2 properties multiple times.
503                         Assert.AreEqual (typeof (ClassWithNullableDateTime), siblingProperty.DeclaringType, "#3");
504                         Assert.AreEqual (typeof (InheritsFromClassWithNullableDateTime), siblingProperty.ReflectedType, "#4");
505                 }
506
507                 class Super { public long A { get; private set; } }
508
509                 class Sub : Super { }
510
511                 [Test]
512                 public void PrivateSetterFromDerivedType ()
513                 {
514                         var prop = typeof (Sub).GetProperty ("A");
515                         Assert.AreEqual (1, prop.GetAccessors (true).Length, "#1");
516                         Assert.IsFalse (prop.CanWrite, "#2");
517                         Assert.IsNull (prop.GetSetMethod (true), "#3");
518                 }
519
520                 public class ClassWithNullableDateTime
521                 {
522                         public DateTime? Property1 { get; set; }
523                 }
524         
525                 public class InheritsFromClassWithNullableDateTime : ClassWithNullableDateTime
526                 {
527                 }
528
529                 public static int ThrowingProperty {
530                         get {
531                                 throw new ObjectDisposedException("TestClass");
532                         }
533                 }
534
535                 [Test]
536                 public void GetException () {
537                         var prop = typeof(PropertyInfoTest).GetProperty("ThrowingProperty");
538                         try {
539                                 prop.GetValue (null, null);
540                                 Assert.Fail ();
541                         } catch (TargetInvocationException ex) {
542                                 Assert.IsTrue (ex.InnerException is ObjectDisposedException);
543                         }
544                 }
545
546                 public class DefaultValueTest
547                 {
548                         public string this[int val, string param = "test"]
549                         {
550                                 get{ return val + param; }
551                         }
552                 }
553
554
555                 [Test]
556                 public void PropertyWithDefaultValue ()
557                 {
558                         var parameters = typeof (DefaultValueTest).GetProperty ("Item").GetIndexParameters ();
559                         var defaultParam = parameters[parameters.Length - 1];
560                         Assert.AreEqual ("param", defaultParam.Name, "#1");
561                         Assert.AreEqual ("test", defaultParam.DefaultValue, "#2");
562                 }
563         }
564 }