c6451207442ccb028504d0bdd2655942b5f15b61
[mono.git] / mcs / class / corlib / Test / System.Reflection / MonoGenericClassTest.cs
1 //
2 // MonoGenericClassTest.cs - NUnit Test Cases for MonoGenericClassTest
3 //
4 // Rodrigo Kumpera <rkumpera@novell.com>
5 //
6 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
7 // Copyright 2011 Xamarin Inc (http://www.xamarin.com).
8 //
9
10 #if !MONOTOUCH && !MOBILE_STATIC
11
12 using System;
13 using System.Collections;
14 using System.Collections.Generic;
15 using System.Collections.ObjectModel;
16 using System.Threading;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.IO;
20 using System.Security;
21 using System.Security.Permissions;
22 using System.Runtime.InteropServices;
23 using NUnit.Framework;
24 using System.Runtime.CompilerServices;
25
26 namespace MonoTests.System.Reflection.Emit
27 {
28         [TestFixture]
29         public class MonoGenericClassTest
30         {
31                 AssemblyBuilder assembly;
32                 ModuleBuilder module;
33                 int typeCount;
34                 static string ASSEMBLY_NAME = "MonoTests.System.Reflection.Emit.MonoGenericClassTest";
35
36                 string MakeName ()
37                 {
38                         return "internal__type"+ typeCount++;
39                 }
40
41                 [SetUp]
42                 public void SetUp ()
43                 {
44                         SetUp (AssemblyBuilderAccess.RunAndSave);
45                 }
46                 
47                 void SetUp (AssemblyBuilderAccess access)
48                 {
49                         AssemblyName assemblyName = new AssemblyName ();
50                         assemblyName.Name = ASSEMBLY_NAME;
51
52                         assembly =
53                                 Thread.GetDomain ().DefineDynamicAssembly (
54                                         assemblyName, access, Path.GetTempPath ());
55
56                         module = assembly.DefineDynamicModule ("module1");
57                         typeCount = 0;
58                 }
59
60
61                 [Test]
62                 public void TestNameMethods ()
63                 {
64                         TypeBuilder tb = module.DefineType ("foo.type");
65                         tb.DefineGenericParameters ("T", "K");
66
67                         Type inst = tb.MakeGenericType (typeof (double), typeof (string));
68
69                         Assert.AreEqual ("type", inst.Name, "#1");
70                         Assert.AreEqual ("foo", inst.Namespace, "#2");
71 #if !MOBILE
72                         Assert.AreEqual ("foo.type[[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]", inst.FullName, "#3");
73                         Assert.AreEqual ("foo.type[[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], MonoTests.System.Reflection.Emit.MonoGenericClassTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", inst.AssemblyQualifiedName, "#4");
74 #elif MOBILE || MOBILE
75                         Assert.AreEqual ("foo.type[[System.Double, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", inst.FullName, "#3");
76                         Assert.AreEqual ("foo.type[[System.Double, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], MonoTests.System.Reflection.Emit.MonoGenericClassTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", inst.AssemblyQualifiedName, "#4");
77                         Assert.AreEqual ("foo.type[System.Double,System.String]", inst.ToString (), "#5");
78 #endif
79                 }
80
81                 static void CheckInst (string prefix, Type inst, int a, int b)
82                 {
83                         var resA = inst.GetMethods (BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
84                         var resB = inst.GetMethods (BindingFlags.Public | BindingFlags.Instance);
85
86                         Assert.AreEqual (a, resA.Length, prefix + 1);
87                         Assert.AreEqual (b, resB.Length, prefix + 2);
88                 }
89
90                 [Test]
91                 public void MethodsThatRaiseNotSupported ()
92                 {
93                         var tb = module.DefineType ("foo.type");
94                         tb.DefineGenericParameters ("T");
95
96                         var ginst = tb.MakeGenericType (typeof (double));
97
98                         try {
99                                 ginst.GetElementType ();
100                                 Assert.Fail ("#1");
101                         } catch (NotSupportedException) {  }
102                         try {
103                                 ginst.GetInterface ("foo", true);
104                                 Assert.Fail ("#2");
105                         } catch (NotSupportedException) {  }
106                         try {
107                                 ginst.GetEvent ("foo", BindingFlags.Public | BindingFlags.Instance);
108                                 Assert.Fail ("#3");
109                         } catch (NotSupportedException) {  }
110                         try {
111                                 ginst.GetField ("foo", BindingFlags.Public | BindingFlags.Instance);
112                                 Assert.Fail ("#4");
113                         } catch (NotSupportedException) {  }
114                         try {
115                                 ginst.GetMembers (BindingFlags.Public | BindingFlags.Instance);
116                                 Assert.Fail ("#5");
117                         } catch (NotSupportedException) {  }
118                         try {
119                                 ginst.GetMethod ("Foo");
120                                 Assert.Fail ("#6");
121                         } catch (NotSupportedException) {  }
122                         try {
123                                 ginst.GetNestedType ("foo", BindingFlags.Public | BindingFlags.Instance);
124                                 Assert.Fail ("#7");
125                         } catch (NotSupportedException) {  }
126                         try {
127                                 ginst.GetProperty ("foo");
128                                 Assert.Fail ("#8");
129                         } catch (NotSupportedException) {  }
130                         try {
131                                 var x = ginst.TypeInitializer;
132                                 Assert.Fail ("#9");
133                         } catch (NotSupportedException) {  }
134                         try {
135                                 var x = ginst.InvokeMember ("foo", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, null, null);
136                                 Assert.Fail ("#10");
137                         } catch (NotSupportedException) {  }
138                         try {
139                                 ginst.IsDefined (typeof (int), true);
140                                 Assert.Fail ("#11");
141                         } catch (NotSupportedException) {  }
142                         try {
143                                 ginst.GetCustomAttributes (true);
144                                 Assert.Fail ("#12");
145                         } catch (NotSupportedException) {  }
146                         try {
147                                 ginst.GetCustomAttributes (typeof (int), true);
148                                 Assert.Fail ("#13");
149                         } catch (NotSupportedException) {  }
150                         try {
151                                 ginst.IsAssignableFrom (ginst);
152                                 Assert.Fail ("#14");
153                         } catch (NotSupportedException) {  }
154                         try {
155                                 ginst.GetNestedTypes (BindingFlags.Public);
156                                 Assert.Fail ("#14");
157                         } catch (NotSupportedException) {  }
158                 }
159
160                 [Test]
161                 public void ClassMustNotBeRegisteredAfterTypeBuilderIsFinished ()
162                 {
163                         TypeBuilder tb = module.DefineType ("foo.type");
164                         tb.DefineGenericParameters ("T");
165
166                         var c = tb.CreateType ();
167
168                         var sreInst = tb.MakeGenericType (typeof (int));
169                         var rtInst = c.MakeGenericType (typeof (int));
170
171                         Assert.AreNotSame (sreInst, rtInst, "#1");
172
173                         /*This must not throw*/
174                         rtInst.IsDefined (typeof (int), true);
175                 }
176
177                 public class Bar<T> {
178                         public class Foo<U> {}
179                 }
180
181                 [Test]
182                 public void DeclaringTypeMustReturnNonInflatedType ()
183                 {
184                         var ut = new TypeDelegator (typeof (int));
185                         var ut2 = typeof(Bar<>.Foo<>);
186                         var t = ut2.MakeGenericType (ut, ut);
187                         Assert.AreSame (typeof (Bar<>), t.DeclaringType, "#1");
188                 }
189
190                 public class Base<T> {}
191                 public class SubClass<K> : Base<K> {}
192
193                 [Test]
194                 public void BaseTypeMustReturnNonInflatedType ()
195                 {
196                         var ut = new TypeDelegator (typeof (int));
197                         var ut2 = typeof(SubClass<>);
198                         var t = ut2.MakeGenericType (ut);
199                         //This is Base<K> where K is SubClass::K
200                         var expected = typeof (Base<>).MakeGenericType (typeof (SubClass<>).GetGenericArguments ()[0]);
201                         Assert.AreSame (expected, t.BaseType, "#1");
202                         
203                 }
204
205                 [Test]
206                 public void GenericClassFromStaleTypeBuilderDoesNotClassInit ()
207                 {
208                         // interface JJJ<T> {
209                         //   abstract void W (x : T)
210                         // }
211                         MethodInfo winfo = null;
212                         TypeBuilder ib = null;
213                         Type ic = null;
214                         Type icreated = null;
215                         {
216                                 ib = module.DefineType ("Foo.JJJ`1",
217                                                          TypeAttributes.Public
218                                                          | TypeAttributes.Interface
219                                                          | TypeAttributes.Abstract);
220                                 String[] gens = { "T" };
221                                 GenericTypeParameterBuilder[] gbs = ib.DefineGenericParameters (gens);
222                                 var gb = gbs[0];
223                                 winfo = ib.DefineMethod ("W",
224                                                          MethodAttributes.Public |
225                                                          MethodAttributes.Abstract |
226                                                          MethodAttributes.Virtual,
227                                                          CallingConventions.HasThis,
228                                                          typeof(void),
229                                          new Type[] { gb });
230                                 icreated = ib.CreateType();
231
232                         }
233
234                         // class SSS : JJJ<char> {
235                         //   bool wasCalled;
236                         //   void JJJ.W (x : T) { wasCalled = true; return; }
237                         // }
238                         TypeBuilder tb = null;
239                         MethodBuilder mb = null;
240                         {
241                                 tb = module.DefineType ("Foo.SSS",
242                                                         TypeAttributes.Public,
243                                                         null,
244                                                         new Type[]{ icreated.MakeGenericType(typeof(char)) });
245                                 var wasCalledField = tb.DefineField ("wasCalled",
246                                                                      typeof(bool),
247                                                                      FieldAttributes.Public);
248                                 mb = tb.DefineMethod ("W_impl",
249                                                       MethodAttributes.Public | MethodAttributes.Virtual,
250                                                       CallingConventions.HasThis,
251                                                       typeof (void),
252                                                       new Type[] { typeof (char) });
253                                 {
254                                         var il = mb.GetILGenerator ();
255                                         il.Emit (OpCodes.Ldarg_0); // this
256                                         il.Emit (OpCodes.Ldc_I4_1);
257                                         il.Emit (OpCodes.Stfld, wasCalledField); // this.wasCalled = true
258                                         il.Emit (OpCodes.Ret);
259                                 }
260                         }
261
262                         ic = ib.MakeGenericType(typeof (char)); // this is a MonoGenericMethod
263                         var mintf = TypeBuilder.GetMethod(ic, winfo);
264                         // the next line causes mono_class_init() to
265                         // be called on JJJ<char> when we try to setup
266                         // the vtable for SSS
267                         tb.DefineMethodOverride(mb, mintf);
268
269                         var result = tb.CreateType();
270
271                         // o = new SSS()
272                         object o = Activator.CreateInstance(result);
273                         Assert.IsNotNull(o, "#1");
274
275                         // ((JJJ<char>)o).W('a');
276                         var m = icreated.MakeGenericType(typeof(char)).GetMethod("W", BindingFlags.Public | BindingFlags.Instance);
277                         Assert.IsNotNull(m, "#2");
278                         m.Invoke(o, new object[] {'a'});
279
280                         var f = result.GetField("wasCalled", BindingFlags.Public | BindingFlags.Instance);
281                         Assert.IsNotNull(f, "#3");
282                         var wasCalledVal = f.GetValue(o);
283                         Assert.IsNotNull(wasCalledVal, "#4");
284                         Assert.AreEqual (wasCalledVal.GetType(), typeof(Boolean), "#5");
285                         Assert.AreEqual (wasCalledVal, true, "#6");
286                 }
287         }
288 }
289
290 #endif