PageRenderTime 40ms CodeModel.GetById 17ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Test/Mono.Cecil.Tests/ImportReflectionTests.cs

http://github.com/jbevain/cecil
C# | 428 lines | 339 code | 89 blank | 0 comment | 6 complexity | 5ece7371b06caf0efeb658fb094b4627 MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.IO;
  4using SR = System.Reflection;
  5using System.Runtime.CompilerServices;
  6
  7using Mono.Cecil.Cil;
  8
  9using NUnit.Framework;
 10
 11namespace Mono.Cecil.Tests {
 12
 13	[TestFixture]
 14	public class ImportReflectionTests : BaseTestFixture {
 15
 16		[Test]
 17		public void ImportString ()
 18		{
 19			var get_string = Compile<Func<string>> ((_, body) => {
 20				var il = body.GetILProcessor ();
 21				il.Emit (OpCodes.Ldstr, "yo dawg!");
 22				il.Emit (OpCodes.Ret);
 23			});
 24
 25			Assert.AreEqual ("yo dawg!", get_string ());
 26		}
 27
 28		[Test]
 29		public void ImportInt ()
 30		{
 31			var add = Compile<Func<int, int, int>> ((_, body) => {
 32				var il = body.GetILProcessor ();
 33				il.Emit (OpCodes.Ldarg_0);
 34				il.Emit (OpCodes.Ldarg_1);
 35				il.Emit (OpCodes.Add);
 36				il.Emit (OpCodes.Ret);
 37			});
 38
 39			Assert.AreEqual (42, add (40, 2));
 40		}
 41
 42		[Test]
 43		public void ImportStringByRef ()
 44		{
 45			var get_string = Compile<Func<string, string>> ((module, body) => {
 46				var type = module.Types [1];
 47
 48				var method_by_ref = new MethodDefinition {
 49					Name = "ModifyString",
 50					IsPrivate = true,
 51					IsStatic = true,
 52				};
 53
 54				type.Methods.Add (method_by_ref);
 55
 56				method_by_ref.MethodReturnType.ReturnType = module.ImportReference (typeof (void));
 57
 58				method_by_ref.Parameters.Add (new ParameterDefinition (module.ImportReference (typeof (string))));
 59				method_by_ref.Parameters.Add (new ParameterDefinition (module.ImportReference (typeof (string).MakeByRefType ())));
 60
 61				var m_il = method_by_ref.Body.GetILProcessor ();
 62				m_il.Emit (OpCodes.Ldarg_1);
 63				m_il.Emit (OpCodes.Ldarg_0);
 64				m_il.Emit (OpCodes.Stind_Ref);
 65				m_il.Emit (OpCodes.Ret);
 66
 67				var v_0 = new VariableDefinition (module.ImportReference (typeof (string)));
 68				body.Variables.Add (v_0);
 69
 70				var il = body.GetILProcessor ();
 71				il.Emit (OpCodes.Ldnull);
 72				il.Emit (OpCodes.Stloc, v_0);
 73				il.Emit (OpCodes.Ldarg_0);
 74				il.Emit (OpCodes.Ldloca, v_0);
 75				il.Emit (OpCodes.Call, method_by_ref);
 76				il.Emit (OpCodes.Ldloc_0);
 77				il.Emit (OpCodes.Ret);
 78			});
 79
 80			Assert.AreEqual ("foo", get_string ("foo"));
 81		}
 82
 83		[Test]
 84		public void ImportStringArray ()
 85		{
 86			var identity = Compile<Func<string [,], string [,]>> ((module, body) => {
 87				var il = body.GetILProcessor ();
 88				il.Emit (OpCodes.Ldarg_0);
 89				il.Emit (OpCodes.Ret);
 90			});
 91
 92			var array = new string [2, 2];
 93
 94			Assert.AreEqual (array, identity (array));
 95		}
 96
 97		[Test]
 98		public void ImportFieldStringEmpty ()
 99		{
100			var get_empty = Compile<Func<string>> ((module, body) => {
101				var il = body.GetILProcessor ();
102				il.Emit (OpCodes.Ldsfld, module.ImportReference (typeof (string).GetField ("Empty")));
103				il.Emit (OpCodes.Ret);
104			});
105
106			Assert.AreEqual ("", get_empty ());
107		}
108
109		[Test]
110		public void ImportStringConcat ()
111		{
112			var concat = Compile<Func<string, string, string>> ((module, body) => {
113				var il = body.GetILProcessor ();
114				il.Emit (OpCodes.Ldarg_0);
115				il.Emit (OpCodes.Ldarg_1);
116				il.Emit (OpCodes.Call, module.ImportReference (typeof (string).GetMethod ("Concat", new [] { typeof (string), typeof (string) })));
117				il.Emit (OpCodes.Ret);
118			});
119
120			Assert.AreEqual ("FooBar", concat ("Foo", "Bar"));
121		}
122
123		[Test]
124		public void GeneratedAssemblyCulture ()
125		{
126			var id = Compile<Func<int, int>> ((module, body) => {
127				var il = body.GetILProcessor ();
128				il.Emit (OpCodes.Ldarg_0);
129				il.Emit (OpCodes.Ret);
130			});
131
132			Assert.AreEqual ("", id.Method.DeclaringType.Assembly.GetName ().CultureInfo.Name);
133		}
134
135		public class Generic<T> {
136			public T Field;
137
138			public T Method (T t)
139			{
140				return t;
141			}
142
143			public TS GenericMethod<TS> (T t, TS s)
144			{
145				return s;
146			}
147
148			public Generic<TS> ComplexGenericMethod<TS> (T t, TS s)
149			{
150				return new Generic<TS> { Field = s };
151			}
152		}
153
154		[Test]
155		public void ImportGenericField ()
156		{
157			if (Platform.OnCoreClr)
158				return;
159
160			var get_field = Compile<Func<Generic<string>, string>> ((module, body) => {
161				var il = body.GetILProcessor ();
162				il.Emit (OpCodes.Ldarg_0);
163				il.Emit (OpCodes.Ldfld, module.ImportReference (typeof (Generic<string>).GetField ("Field")));
164				il.Emit (OpCodes.Ret);
165			});
166
167			var generic = new Generic<string> {
168				Field = "foo",
169			};
170
171			Assert.AreEqual ("foo", get_field (generic));
172		}
173
174		[Test]
175		public void ImportGenericMethod ()
176		{
177			if (Platform.OnCoreClr)
178				return;
179
180			var generic_identity = Compile<Func<Generic<int>, int, int>> ((module, body) => {
181				var il = body.GetILProcessor ();
182				il.Emit (OpCodes.Ldarg_0);
183				il.Emit (OpCodes.Ldarg_1);
184				il.Emit (OpCodes.Callvirt, module.ImportReference (typeof (Generic<int>).GetMethod ("Method")));
185				il.Emit (OpCodes.Ret);
186			});
187
188			Assert.AreEqual (42, generic_identity (new Generic<int> (), 42));
189		}
190
191		[Test]
192		public void ImportGenericMethodSpec ()
193		{
194			if (Platform.OnCoreClr)
195				return;
196
197			var gen_spec_id = Compile<Func<Generic<string>, int, int>> ((module, body) => {
198				var il = body.GetILProcessor ();
199				il.Emit (OpCodes.Ldarg_0);
200				il.Emit (OpCodes.Ldnull);
201				il.Emit (OpCodes.Ldarg_1);
202				il.Emit (OpCodes.Callvirt, module.ImportReference (typeof (Generic<string>).GetMethod ("GenericMethod").MakeGenericMethod (typeof (int))));
203				il.Emit (OpCodes.Ret);
204			});
205
206			Assert.AreEqual (42, gen_spec_id (new Generic<string> (), 42));
207		}
208
209		[Test]
210		public void ImportComplexGenericMethodSpec ()
211		{
212			if (Platform.OnCoreClr)
213				return;
214
215			var gen_spec_id = Compile<Func<Generic<string>, int, int>> ((module, body) => {
216				var il = body.GetILProcessor ();
217				il.Emit (OpCodes.Ldarg_0);
218				il.Emit (OpCodes.Ldnull);
219				il.Emit (OpCodes.Ldarg_1);
220				il.Emit (OpCodes.Callvirt, module.ImportReference (typeof (Generic<string>).GetMethod ("ComplexGenericMethod").MakeGenericMethod (typeof (int))));
221				il.Emit (OpCodes.Ldfld, module.ImportReference (typeof (Generic<int>).GetField ("Field")));
222				il.Emit (OpCodes.Ret);
223			});
224
225			Assert.AreEqual (42, gen_spec_id (new Generic<string> (), 42));
226		}
227
228		public class Foo<TFoo> {
229			public List<TFoo> list;
230		}
231
232		[Test]
233		public void ImportGenericTypeDefOrOpen ()
234		{
235			using (var module = typeof (Foo<>).ToDefinition ().Module) {
236				var foo_def = module.ImportReference (typeof (Foo<>));
237				var foo_open = module.ImportReference (typeof (Foo<>), foo_def);
238
239				Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1", foo_def.FullName);
240				Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1<TFoo>", foo_open.FullName);
241			}
242		}
243
244		[Test]
245		public void ImportGenericTypeFromContext ()
246		{
247			var list_foo = typeof (Foo<>).GetField ("list").FieldType;
248			var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo);
249
250			var foo_def = typeof (Foo<>).ToDefinition ();
251			using (var module = foo_def.Module) {
252				var generic_foo = module.ImportReference (generic_list_foo_open, foo_def);
253
254				Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Generic`1<System.Collections.Generic.List`1<TFoo>>",
255					generic_foo.FullName);
256			}
257		}
258
259		[Test]
260		public void ImportGenericTypeDefFromContext ()
261		{
262			var foo_open = typeof (Foo<>).MakeGenericType (typeof (Foo<>).GetGenericArguments () [0]);
263			var generic_foo_open = typeof (Generic<>).MakeGenericType (foo_open);
264
265			var foo_def = typeof (Foo<>).ToDefinition ();
266			using (var module = foo_def.Module) {
267				var generic_foo = module.ImportReference (generic_foo_open, foo_def);
268
269				Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Generic`1<Mono.Cecil.Tests.ImportReflectionTests/Foo`1<TFoo>>",
270					generic_foo.FullName);
271			}
272		}
273
274		[Test]
275		public void ImportArrayTypeDefFromContext ()
276		{
277			var foo_open = typeof (Foo<>).MakeGenericType (typeof (Foo<>).GetGenericArguments () [0]);
278			var foo_open_array = foo_open.MakeArrayType ();
279
280			var foo_def = typeof (Foo<>).ToDefinition ();
281			using (var module = foo_def.Module) {
282				var array_foo = module.ImportReference (foo_open_array, foo_def);
283
284				Assert.AreEqual ("Mono.Cecil.Tests.ImportReflectionTests/Foo`1<TFoo>[]",
285					array_foo.FullName);
286			}
287		}
288
289		[Test]
290		public void ImportGenericFieldFromContext ()
291		{
292			if (Platform.OnCoreClr)
293				return;
294
295			var list_foo = typeof (Foo<>).GetField ("list").FieldType;
296			var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo);
297			var generic_list_foo_open_field = generic_list_foo_open.GetField ("Field");
298
299			var foo_def = typeof (Foo<>).ToDefinition ();
300			using (var module = foo_def.Module) {
301				var generic_field = module.ImportReference (generic_list_foo_open_field, foo_def);
302
303				Assert.AreEqual ("T Mono.Cecil.Tests.ImportReflectionTests/Generic`1<System.Collections.Generic.List`1<TFoo>>::Field",
304					generic_field.FullName);
305			}
306		}
307
308		[Test]
309		public void ImportGenericMethodFromContext ()
310		{
311			if (Platform.OnCoreClr)
312				return;
313
314			var list_foo = typeof (Foo<>).GetField ("list").FieldType;
315			var generic_list_foo_open = typeof (Generic<>).MakeGenericType (list_foo);
316			var generic_list_foo_open_method = generic_list_foo_open.GetMethod ("Method");
317
318			var foo_def = typeof (Foo<>).ToDefinition ();
319			using (var module = foo_def.Module) {
320				var generic_method = module.ImportReference (generic_list_foo_open_method, foo_def);
321
322				Assert.AreEqual ("T Mono.Cecil.Tests.ImportReflectionTests/Generic`1<System.Collections.Generic.List`1<TFoo>>::Method(T)",
323					generic_method.FullName);
324			}
325		}
326
327		[Test]
328		public void ImportMethodOnOpenGenericType ()
329		{
330			using (var module = typeof (Generic<>).ToDefinition ().Module) {
331				var method = module.ImportReference (typeof (Generic<>).GetMethod ("Method"));
332
333				Assert.AreEqual ("T Mono.Cecil.Tests.ImportReflectionTests/Generic`1<T>::Method(T)", method.FullName);
334			}
335		}
336
337		[Test]
338		public void ImportGenericMethodOnOpenGenericType ()
339		{
340			using (var module = typeof (Generic<>).ToDefinition ().Module) {
341				var generic_method = module.ImportReference (typeof (Generic<>).GetMethod ("GenericMethod"));
342
343				Assert.AreEqual ("TS Mono.Cecil.Tests.ImportReflectionTests/Generic`1<T>::GenericMethod(T,TS)", generic_method.FullName);
344
345				generic_method = module.ImportReference (typeof (Generic<>).GetMethod ("GenericMethod"), generic_method);
346
347				Assert.AreEqual ("TS Mono.Cecil.Tests.ImportReflectionTests/Generic`1<T>::GenericMethod<TS>(T,TS)", generic_method.FullName);
348			}
349		}
350
351		delegate void Emitter (ModuleDefinition module, MethodBody body);
352
353		static TDelegate Compile<TDelegate> (Emitter emitter, [CallerMemberName] string testMethodName = null)
354			where TDelegate : class
355		{
356			var name = "ImportReflection_" + testMethodName;
357
358			var module = CreateTestModule<TDelegate> (name, emitter);
359			var assembly = LoadTestModule (module);
360
361			return CreateRunDelegate<TDelegate> (GetTestCase (name, assembly));
362		}
363
364		static TDelegate CreateRunDelegate<TDelegate> (Type type)
365			where TDelegate : class
366		{
367			return (TDelegate) (object) Delegate.CreateDelegate (typeof (TDelegate), type.GetMethod ("Run"));
368		}
369
370		static Type GetTestCase (string name, SR.Assembly assembly)
371		{
372			return assembly.GetType (name);
373		}
374
375		static SR.Assembly LoadTestModule (ModuleDefinition module)
376		{
377			using (var stream = new MemoryStream ()) {
378				module.Write (stream);
379				File.WriteAllBytes (Path.Combine (Path.Combine (Path.GetTempPath (), "cecil"), module.Name + ".dll"), stream.ToArray ());
380				return SR.Assembly.Load (stream.ToArray ());
381			}
382		}
383
384		static ModuleDefinition CreateTestModule<TDelegate> (string name, Emitter emitter)
385		{
386			var module = CreateModule (name);
387
388			var type = new TypeDefinition (
389				"",
390				name,
391				TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Abstract,
392				module.ImportReference (typeof (object)));
393
394			module.Types.Add (type);
395
396			var method = CreateMethod (type, typeof (TDelegate).GetMethod ("Invoke"));
397
398			emitter (module, method.Body);
399
400			return module;
401		}
402
403		static MethodDefinition CreateMethod (TypeDefinition type, SR.MethodInfo pattern)
404		{
405			var module = type.Module;
406
407			var method = new MethodDefinition {
408				Name = "Run",
409				IsPublic = true,
410				IsStatic = true,
411			};
412
413			type.Methods.Add (method);
414
415			method.MethodReturnType.ReturnType = module.ImportReference (pattern.ReturnType);
416
417			foreach (var parameter_pattern in pattern.GetParameters ())
418				method.Parameters.Add (new ParameterDefinition (module.ImportReference (parameter_pattern.ParameterType)));
419
420			return method;
421		}
422
423		static ModuleDefinition CreateModule (string name)
424		{
425			return ModuleDefinition.CreateModule (name, ModuleKind.Dll);
426		}
427	}
428}