1 //
2 // EnumBuiderTest - NUnit Test Cases for the EnumBuider class
3 //
4 // Keerti Narayan (keertiln@rediffmail.com)
5 // Gert Driesen (drieseng@users.sourceforge.net)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 //
9 //
10 
11 using System;
12 using System.IO;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Collections;
16 using System.Threading;
17 
18 using NUnit.Framework;
19 
20 namespace MonoTests.System.Reflection.Emit
21 {
22 	[TestFixture]
23 	public class EnumBuilderTest
24 	{
25 		private static string _assemblyName = "MonoTests.System.Reflection.Emit.EnumBuilder";
26 		private static string _moduleName = "EmittedModule";
27 		private static string _enumNamespace = "MyNameSpace";
28 		private static string _enumName = "MyEnum";
29 		private static Type _enumType = typeof (Int32);
30 		private static string _fieldName = "MyField";
31 		private static object _fieldValue = 1;
32 
33 		[Test]
TestEnumBuilder()34 		public void TestEnumBuilder ()
35 		{
36 			EnumBuilder enumBuilder = GenerateEnum ();
37 			VerifyType (enumBuilder);
38 
39 			Assert.IsNotNull (enumBuilder.TypeToken, "#1");
40 			Assert.IsNotNull (enumBuilder.UnderlyingField, "#2");
41 			Assert.IsNull (enumBuilder.DeclaringType, "#3");
42 			Assert.IsNull (enumBuilder.ReflectedType, "#4");
43 			Assert.AreEqual (_enumType, enumBuilder.UnderlyingSystemType, "#5");
44 			Assert.IsFalse (enumBuilder.IsSerializable);
45 		}
46 
47 		[Test]
48 		[Category ("NotWorking")]
TestHasElementTypeEnumBuilderIncomplete()49 		public void TestHasElementTypeEnumBuilderIncomplete ()
50 		{
51 			EnumBuilder enumBuilder = GenerateEnum ();
52 			bool hasElementType = enumBuilder.HasElementType;
53 			Assert.IsFalse (hasElementType);
54 		}
55 
56 		[Test]
TestHasElementTypeEnumBuilderComplete()57 		public void TestHasElementTypeEnumBuilderComplete ()
58 		{
59 			EnumBuilder enumBuilder = GenerateEnum ();
60 			enumBuilder.CreateType ();
61 			bool hasElementType = enumBuilder.HasElementType;
62 			Assert.IsFalse (hasElementType);
63 		}
64 
65 		[Test]
66 		[ExpectedException (typeof (InvalidOperationException))]
TestDefineLiteralTypeComplete()67 		public void TestDefineLiteralTypeComplete ()
68 		{
69 			EnumBuilder enumBuilder = GenerateEnum ();
70 			Type enumType = enumBuilder.CreateType ();
71 			// you should not be able to define literal after type
72 			// has been created
73 			enumBuilder.DefineLiteral (_fieldName, _fieldValue);
74 		}
75 
76 		[Test]
TestDefineLiteralTypeIncomplete()77 		public void TestDefineLiteralTypeIncomplete ()
78 		{
79 			EnumBuilder enumBuilder = GenerateEnum ();
80 			FieldBuilder fieldBuilder = enumBuilder.DefineLiteral (_fieldName, _fieldValue);
81 			Type enumType = enumBuilder.CreateType ();
82 
83 			Assert.IsTrue (fieldBuilder.IsPublic, "#1");
84 			Assert.IsTrue (fieldBuilder.IsStatic, "#2");
85 			Assert.IsTrue (fieldBuilder.IsLiteral, "#3");
86 			Assert.AreEqual (_fieldName, fieldBuilder.Name, "#4");
87 			Assert.IsFalse (enumType == fieldBuilder.DeclaringType, "#5");
88 			Assert.IsFalse (enumBuilder == fieldBuilder.DeclaringType, "#6");
89 			Assert.AreEqual (enumType.FullName, fieldBuilder.DeclaringType.FullName, "#7");
90 			Assert.IsFalse (enumType == fieldBuilder.FieldType, "#8");
91 			Assert.AreEqual (enumBuilder, fieldBuilder.FieldType, "#9");
92 		}
93 
94 		[Test]
TestEnumType()95 		public void TestEnumType ()
96 		{
97 			AssemblyBuilder assemblyBuilder = GenerateAssembly ();
98 
99 			ModuleBuilder modBuilder = GenerateModule (assemblyBuilder);
100 			EnumBuilder enumBuilder = GenerateEnum (modBuilder);
101 			enumBuilder.CreateType ();
102 
103 			Type enumType = assemblyBuilder.GetType (_enumNamespace + "." + _enumName, true);
104 
105 			VerifyType (enumType);
106 		}
107 
108 		[Test]
109 		[ExpectedException (typeof (NotSupportedException))]
TestEnumBuilderGUIDIncomplete()110 		public void TestEnumBuilderGUIDIncomplete ()
111 		{
112 			EnumBuilder enumBuilder = GenerateEnum ();
113 			Guid guid = enumBuilder.GUID;
114 		}
115 
116 		[Test]
117 		[Category ("NotWorking")] // Bug:71299
TestEnumBuilderGUIDComplete()118 		public void TestEnumBuilderGUIDComplete ()
119 		{
120 			EnumBuilder enumBuilder = GenerateEnum ();
121 			enumBuilder.CreateType ();
122 			Assert.IsTrue (enumBuilder.GUID != Guid.Empty);
123 		}
124 
125 		[Test]
TestEnumTypeGUID()126 		public void TestEnumTypeGUID ()
127 		{
128 			AssemblyBuilder assemblyBuilder = GenerateAssembly ();
129 			ModuleBuilder modBuilder = GenerateModule (assemblyBuilder);
130 			EnumBuilder enumBuilder = GenerateEnum (modBuilder);
131 			enumBuilder.CreateType ();
132 
133 			Type enumType = assemblyBuilder.GetType (_enumNamespace + "." + _enumName, true);
134 
135 			// Tested in above test: Assert (enumType.GUID != Guid.Empty);
136 			Assert.IsNull (enumType.DeclaringType);
137 		}
138 
139 		[Test]
TestFieldProperties()140 		public void TestFieldProperties ()
141 		{
142 			AssemblyBuilder assemblyBuilder = GenerateAssembly ();
143 			ModuleBuilder modBuilder = GenerateModule (assemblyBuilder);
144 			EnumBuilder enumBuilder = GenerateEnum (modBuilder);
145 			FieldBuilder fieldBuilder = GenerateField (enumBuilder);
146 			enumBuilder.CreateType ();
147 
148 			Type enumType = assemblyBuilder.GetType (_enumNamespace + "." + _enumName, true);
149 			FieldInfo fi = enumType.GetField (_fieldName);
150 			Object o = fi.GetValue (enumType);
151 
152 			Assert.IsTrue (fi.IsLiteral, "#1");
153 			Assert.IsTrue (fi.IsPublic, "#2");
154 			Assert.IsTrue (fi.IsStatic, "#3");
155 			Assert.AreEqual (enumBuilder, fieldBuilder.FieldType, "#4");
156 			Assert.IsFalse (enumType == fieldBuilder.FieldType, "#5");
157 			Assert.AreEqual (enumType.FullName, fieldBuilder.FieldType.FullName, "#6");
158 			Assert.IsFalse (_enumType == fieldBuilder.FieldType, "#7");
159 
160 			object fieldValue = fi.GetValue (enumType);
161 			Assert.IsFalse (_fieldValue == fieldValue, "#8");
162 			Assert.IsTrue (fieldValue.GetType ().IsEnum, "#9");
163 			Assert.AreEqual (enumType, fieldValue.GetType (), "#10");
164 			Assert.AreEqual (_fieldValue, (int) fieldValue, "#11");
165 		}
166 
167 		[Test]
TestFindInterfaces()168 		public void TestFindInterfaces ()
169 		{
170 			EnumBuilder enumBuilder = GenerateEnum ();
171 
172 			Type [] interfaces = enumBuilder.FindInterfaces (
173 				new TypeFilter (MyInterfaceFilter),
174 				"System.Collections.IEnumerable");
175 			Assert.AreEqual (0, interfaces.Length);
176 		}
177 
178 		[Test]
179 		[ExpectedException (typeof (NotSupportedException))]
TestFindMembersIncomplete()180 		public void TestFindMembersIncomplete ()
181 		{
182 			EnumBuilder enumBuilder = GenerateEnum ();
183 			GenerateField (enumBuilder);
184 
185 			MemberInfo [] members = enumBuilder.FindMembers (
186 				MemberTypes.All, BindingFlags.Static |
187 				BindingFlags.Public, new MemberFilter (MemberNameFilter),
188 				_fieldName);
189 		}
190 
191 		[Test]
GetEnumUnderlyingType()192 		public void GetEnumUnderlyingType ()
193 		{
194 			var @enum = GenerateEnum ();
195 
196 			Assert.AreEqual (_enumType, @enum.GetEnumUnderlyingType ());
197 		}
198 
199 		[Test]
TestFindMembersComplete()200 		public void TestFindMembersComplete ()
201 		{
202 			EnumBuilder enumBuilder = GenerateEnum ();
203 			GenerateField (enumBuilder);
204 			enumBuilder.CreateType ();
205 
206 			MemberInfo [] members = enumBuilder.FindMembers (
207 				MemberTypes.Field, BindingFlags.Static |
208 				BindingFlags.Public, new MemberFilter (MemberNameFilter),
209 				_fieldName);
210 			Assert.AreEqual (1, members.Length, "#1");
211 
212 			members = enumBuilder.FindMembers (
213 				MemberTypes.Field, BindingFlags.Static |
214 				BindingFlags.Public, new MemberFilter (MemberNameFilter),
215 				"doesntmatter");
216 			Assert.AreEqual (0, members.Length, "#2");
217 		}
218 
219 		[Test]
220 		[ExpectedException (typeof (NotSupportedException))]
TestGetConstructorIncomplete()221 		public void TestGetConstructorIncomplete ()
222 		{
223 			EnumBuilder enumBuilder = GenerateEnum ();
224 			enumBuilder.GetConstructor (BindingFlags.Public, null,
225 				CallingConventions.Any, Type.EmptyTypes, new ParameterModifier [0]);
226 		}
227 
228 		[Test]
TestGetConstructorComplete()229 		public void TestGetConstructorComplete ()
230 		{
231 			EnumBuilder enumBuilder = GenerateEnum ();
232 			enumBuilder.CreateType ();
233 			ConstructorInfo ctor = enumBuilder.GetConstructor (
234 				BindingFlags.Public, null, CallingConventions.Any,
235 				Type.EmptyTypes, new ParameterModifier [0]);
236 			Assert.IsNull (ctor);
237 		}
238 
239 		[Test]
240 		[ExpectedException (typeof (ArgumentNullException))]
TestGetConstructorNullTypes()241 		public void TestGetConstructorNullTypes ()
242 		{
243 			EnumBuilder enumBuilder = GenerateEnum ();
244 			enumBuilder.CreateType ();
245 			ConstructorInfo ctor = enumBuilder.GetConstructor (
246 				BindingFlags.Public, null, CallingConventions.Any,
247 				null, new ParameterModifier [0]);
248 		}
249 
250 		[Test]
251 		[Category ("NotWorking")]
252 		[ExpectedException (typeof (ArgumentNullException))]
TestGetConstructorNullElementType()253 		public void TestGetConstructorNullElementType ()
254 		{
255 			EnumBuilder enumBuilder = GenerateEnum ();
256 			enumBuilder.CreateType ();
257 			ConstructorInfo ctor = enumBuilder.GetConstructor (
258 				BindingFlags.Public, null, CallingConventions.Any,
259 				new Type [] { null }, new ParameterModifier [0]);
260 		}
261 
262 		[Test]
263 		[ExpectedException (typeof (NotSupportedException))]
264 		[Category ("NotWorking")]
TestGetConstructorsIncomplete()265 		public void TestGetConstructorsIncomplete ()
266 		{
267 			EnumBuilder enumBuilder = GenerateEnum ();
268 
269 			ConstructorInfo [] ctors = enumBuilder.GetConstructors (
270 				BindingFlags.Instance | BindingFlags.Public);
271 			Assert.AreEqual (0, ctors.Length);
272 		}
273 
274 		[Test]
TestGetConstructorsComplete()275 		public void TestGetConstructorsComplete ()
276 		{
277 			EnumBuilder enumBuilder = GenerateEnum ();
278 			enumBuilder.CreateType ();
279 
280 			ConstructorInfo [] ctors = enumBuilder.GetConstructors (
281 				BindingFlags.Instance | BindingFlags.Public);
282 			Assert.AreEqual (0, ctors.Length);
283 		}
284 
285 		[Test]
TestIsValue__SpecialName()286 		public void TestIsValue__SpecialName ()
287 		{
288 			EnumBuilder enumBuilder = GenerateEnum ();
289 			Type enumType = enumBuilder.CreateType ();
290 			FieldInfo value = enumType.GetField ("value__", BindingFlags.Instance | BindingFlags.NonPublic);
291 			Assert.AreEqual (FieldAttributes.RTSpecialName, value.Attributes & FieldAttributes.RTSpecialName);
292 		}
293 
294 		[Test]
TestCreateTypeIncompleteEnumStaticField()295 		public void TestCreateTypeIncompleteEnumStaticField ()
296 		{
297 			ModuleBuilder modBuilder = GenerateModule ();
298 			EnumBuilder enumBuilder = GenerateEnum (modBuilder);
299 			GenerateField (enumBuilder);
300 
301 			var tb = modBuilder.DefineType ("T", TypeAttributes.Public);
302 
303 			tb.DefineDefaultConstructor (MethodAttributes.Public);
304 			tb.DefineField ("e", enumBuilder, FieldAttributes.Static | FieldAttributes.Public);
305 
306 			var t = tb.CreateType ();
307 			Assert.IsNotNull (t);
308 			bool caught = false;
309 			try {
310 				object x = Activator.CreateInstance (t);
311 			} catch (TypeLoadException exn) {
312 				Assert.AreEqual (t.Name, exn.TypeName);
313 				caught = true;
314 			}
315 			if (!caught)
316 				Assert.Fail ("Expected CreateInstance of a broken type to throw TLE");
317 		}
318 
319 		[Test]
TestEnumBuilderTokenUsable()320 		public void TestEnumBuilderTokenUsable () {
321 			// Regression test for https://bugzilla.xamarin.com/show_bug.cgi?id=58361
322 			// Create an EnumBuilder and use it in an ILGenerator that consumes its token.
323 			var modBuilder = GenerateModule ();
324 			EnumBuilder enumBuilder = GenerateEnum (modBuilder);
325 
326 			var tb = modBuilder.DefineType ("Foo", TypeAttributes.Public);
327 
328 			var cb = tb.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
329 						       Type.EmptyTypes);
330 
331 			var ilg = cb.GetILGenerator ();
332 
333 			ilg.Emit (OpCodes.Ldtoken, enumBuilder);
334 			ilg.Emit (OpCodes.Pop);
335 			ilg.Emit (OpCodes.Ret);
336 
337 			var t = tb.CreateType ();
338 			enumBuilder.CreateType ();
339 
340 			var ci = t.GetConstructor (Type.EmptyTypes);
341 			var x = ci.Invoke (null);
342 			Assert.IsNotNull (x);
343 		}
344 
345 		[Test]
TestEnumBuilderTokenUsableCrossAssembly()346 		public void TestEnumBuilderTokenUsableCrossAssembly () {
347 			// Regression test for https://bugzilla.xamarin.com/show_bug.cgi?id=58361
348 			// Create an EnumBuilder and use it in an ILGenerator that consumes its token in a different assembly.
349 			var modBuilder = GenerateModule ();
350 			var modBuilder2 = GenerateModule ();
351 			EnumBuilder enumBuilder = GenerateEnum (modBuilder2);
352 
353 			// N.B. "tb" is in modBuilder but enumBuilder is in modBuilder2
354 			var tb = modBuilder.DefineType ("Foo", TypeAttributes.Public);
355 
356 			var cb = tb.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
357 						       Type.EmptyTypes);
358 
359 			var ilg = cb.GetILGenerator ();
360 
361 			ilg.Emit (OpCodes.Ldtoken, enumBuilder);
362 			ilg.Emit (OpCodes.Pop);
363 			ilg.Emit (OpCodes.Ret);
364 
365 			var t = tb.CreateType ();
366 			enumBuilder.CreateType ();
367 
368 			var ci = t.GetConstructor (Type.EmptyTypes);
369 			var x = ci.Invoke (null);
370 			Assert.IsNotNull (x);
371 		}
372 
373 
VerifyType(Type type)374 		private static void VerifyType (Type type)
375 		{
376 			Assert.IsNotNull (type.Assembly, "#V1");
377 			Assert.IsNotNull (type.AssemblyQualifiedName, "#V2");
378 			Assert.IsNotNull (type.BaseType, "#V3");
379 			Assert.IsNotNull (type.FullName, "#V4");
380 			Assert.IsNotNull (type.Module, "#V5");
381 			Assert.IsNotNull (type.Name, "#V6");
382 			Assert.IsNotNull (type.Namespace, "#V7");
383 			Assert.IsNotNull (type.UnderlyingSystemType, "#V8");
384 
385 			Assert.AreEqual (_enumNamespace, type.Namespace, "#V10");
386 			Assert.AreEqual (_enumName, type.Name, "#V11");
387 			Assert.AreEqual (typeof (Enum), type.BaseType, "#V12");
388 			Assert.AreEqual (MemberTypes.TypeInfo, type.MemberType, "#V13");
389 			Assert.AreEqual (typeof (int), Enum.GetUnderlyingType (type), "#V14");
390 
391 			Assert.IsFalse (type.IsArray, "#V15");
392 			Assert.IsFalse (type.IsAutoClass, "#V16");
393 			Assert.IsTrue (type.IsAutoLayout, "#V17");
394 			Assert.IsFalse (type.IsByRef, "#V18");
395 			Assert.IsFalse (type.IsClass, "#V19");
396 			Assert.IsFalse (type.IsCOMObject, "#V20");
397 			Assert.IsFalse (type.IsContextful, "#V21");
398 			Assert.IsTrue (type.IsEnum, "#V22");
399 			Assert.IsFalse (type.IsExplicitLayout, "#V23");
400 			Assert.IsFalse (type.IsImport, "#V24");
401 			Assert.IsFalse (type.IsInterface, "#V25");
402 			Assert.IsFalse (type.IsLayoutSequential, "#V26");
403 			Assert.IsFalse (type.IsMarshalByRef, "#V27");
404 			Assert.IsFalse (type.IsNestedAssembly, "#V28");
405 			Assert.IsFalse (type.IsNestedFamily, "#V29");
406 			Assert.IsFalse (type.IsNestedPublic, "#V30");
407 			Assert.IsFalse (type.IsNestedPrivate, "#V31");
408 			Assert.IsFalse (type.IsNotPublic, "#V32");
409 			Assert.IsFalse (type.IsPrimitive, "#V33");
410 			Assert.IsFalse (type.IsPointer, "#V34");
411 			Assert.IsTrue (type.IsPublic, "#V35");
412 			Assert.IsTrue (type.IsSealed, "#V36");
413 			Assert.IsFalse (type.IsUnicodeClass, "#V37");
414 			Assert.IsFalse (type.IsSpecialName, "#V38");
415 			Assert.IsTrue (type.IsValueType, "#V39");
416 		}
417 
MyInterfaceFilter(Type t, object filterCriteria)418 		public static bool MyInterfaceFilter (Type t, object filterCriteria)
419 		{
420 			if (t.ToString () == filterCriteria.ToString ())
421 				return true;
422 			else
423 				return false;
424 		}
425 
MemberNameFilter(MemberInfo m, object filterCriteria)426 		public static bool MemberNameFilter (MemberInfo m, object filterCriteria)
427 		{
428 			if (m.Name == filterCriteria.ToString ())
429 				return true;
430 			else
431 				return false;
432 		}
433 
GetAssemblyName()434 		private static AssemblyName GetAssemblyName ()
435 		{
436 			AssemblyName assemblyName = new AssemblyName ();
437 			assemblyName.Name = _assemblyName;
438 			return assemblyName;
439 		}
440 
GenerateAssembly()441 		private static AssemblyBuilder GenerateAssembly ()
442 		{
443 			return AppDomain.CurrentDomain.DefineDynamicAssembly (
444 				GetAssemblyName (), AssemblyBuilderAccess.RunAndSave);
445 		}
446 
GenerateModule()447 		private static ModuleBuilder GenerateModule ()
448 		{
449 			AssemblyBuilder assemblyBuilder = GenerateAssembly ();
450 			return assemblyBuilder.DefineDynamicModule (_moduleName);
451 		}
452 
GenerateModule(AssemblyBuilder assemblyBuilder)453 		private static ModuleBuilder GenerateModule (AssemblyBuilder assemblyBuilder)
454 		{
455 			return assemblyBuilder.DefineDynamicModule (_moduleName);
456 		}
457 
GenerateEnum()458 		private static EnumBuilder GenerateEnum ()
459 		{
460 			ModuleBuilder modBuilder = GenerateModule ();
461 			return modBuilder.DefineEnum (_enumNamespace + "."
462 				+ _enumName, TypeAttributes.Public, _enumType);
463 		}
464 
GenerateEnum(ModuleBuilder modBuilder)465 		private static EnumBuilder GenerateEnum (ModuleBuilder modBuilder)
466 		{
467 			return modBuilder.DefineEnum (_enumNamespace + "."
468 				+ _enumName, TypeAttributes.Public, _enumType);
469 		}
470 
GenerateField()471 		private static FieldBuilder GenerateField ()
472 		{
473 			EnumBuilder enumBuilder = GenerateEnum ();
474 			return enumBuilder.DefineLiteral (_fieldName, _fieldValue);
475 		}
476 
GenerateField(EnumBuilder enumBuilder)477 		private static FieldBuilder GenerateField (EnumBuilder enumBuilder)
478 		{
479 			return enumBuilder.DefineLiteral (_fieldName, _fieldValue);
480 		}
481 	}
482 }
483