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 && !FULL_AOT_RUNTIME 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 MakeName()36 string MakeName () 37 { 38 return "internal__type"+ typeCount++; 39 } 40 41 [SetUp] SetUp()42 public void SetUp () 43 { 44 SetUp (AssemblyBuilderAccess.RunAndSave); 45 } 46 SetUp(AssemblyBuilderAccess access)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] TestNameMethods()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 CheckInst(string prefix, Type inst, int a, int b)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] MethodsThatRaiseNotSupported()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] ClassMustNotBeRegisteredAfterTypeBuilderIsFinished()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] DeclaringTypeMustReturnNonInflatedType()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] BaseTypeMustReturnNonInflatedType()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] GenericClassFromStaleTypeBuilderDoesNotClassInit()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 291