1 using System;
2 using System.IO;
3 using System.Reflection;
4 using Mono.Cecil.Cil;
5 using NUnit.Framework;
6 
7 using Mono.Cecil.PE;
8 
9 namespace Mono.Cecil.Tests {
10 
11 	public abstract class BaseTestFixture {
12 
IgnoreOnMono()13 		protected static void IgnoreOnMono ()
14 		{
15 			if (Platform.OnMono)
16 				Assert.Ignore ();
17 		}
18 
GetResourcePath(string name, Assembly assembly)19 		public static string GetResourcePath (string name, Assembly assembly)
20 		{
21 			return Path.Combine (FindResourcesDirectory (assembly), name);
22 		}
23 
GetAssemblyResourcePath(string name, Assembly assembly)24 		public static string GetAssemblyResourcePath (string name, Assembly assembly)
25 		{
26 			return GetResourcePath (Path.Combine ("assemblies", name), assembly);
27 		}
28 
GetCSharpResourcePath(string name, Assembly assembly)29 		public static string GetCSharpResourcePath (string name, Assembly assembly)
30 		{
31 			return GetResourcePath (Path.Combine ("cs", name), assembly);
32 		}
33 
GetILResourcePath(string name, Assembly assembly)34 		public static string GetILResourcePath (string name, Assembly assembly)
35 		{
36 			return GetResourcePath (Path.Combine ("il", name), assembly);
37 		}
38 
GetResourceModule(string name)39 		public ModuleDefinition GetResourceModule (string name)
40 		{
41 			return ModuleDefinition.ReadModule (GetAssemblyResourcePath (name, GetType ().Assembly));
42 		}
43 
GetResourceModule(string name, ReaderParameters parameters)44 		public ModuleDefinition GetResourceModule (string name, ReaderParameters parameters)
45 		{
46 			return ModuleDefinition.ReadModule (GetAssemblyResourcePath (name, GetType ().Assembly), parameters);
47 		}
48 
GetResourceModule(string name, ReadingMode mode)49 		public ModuleDefinition GetResourceModule (string name, ReadingMode mode)
50 		{
51 			return ModuleDefinition.ReadModule (GetAssemblyResourcePath (name, GetType ().Assembly), new ReaderParameters (mode));
52 		}
53 
GetResourceImage(string name)54 		internal Image GetResourceImage (string name)
55 		{
56 			var file = new FileStream (GetAssemblyResourcePath (name, GetType ().Assembly), FileMode.Open, FileAccess.Read);
57 			return ImageReader.ReadImage (Disposable.Owned (file as Stream), file.Name);
58 		}
59 
GetCurrentModule()60 		public ModuleDefinition GetCurrentModule ()
61 		{
62 			return ModuleDefinition.ReadModule (GetType ().Module.FullyQualifiedName);
63 		}
64 
GetCurrentModule(ReaderParameters parameters)65 		public ModuleDefinition GetCurrentModule (ReaderParameters parameters)
66 		{
67 			return ModuleDefinition.ReadModule (GetType ().Module.FullyQualifiedName, parameters);
68 		}
69 
FindResourcesDirectory(Assembly assembly)70 		public static string FindResourcesDirectory (Assembly assembly)
71 		{
72 			var path = Path.GetDirectoryName (new Uri (assembly.CodeBase).LocalPath);
73 			while (!Directory.Exists (Path.Combine (path, "Resources"))) {
74 				var old = path;
75 				path = Path.GetDirectoryName (path);
76 				Assert.AreNotEqual (old, path);
77 			}
78 
79 			return Path.Combine (path, "Resources");
80 		}
81 
AssertCode(string expected, MethodDefinition method)82 		public static void AssertCode (string expected, MethodDefinition method)
83 		{
84 			Assert.IsTrue (method.HasBody);
85 			Assert.IsNotNull (method.Body);
86 
87 			Assert.AreEqual (Normalize (expected), Normalize (Formatter.FormatMethodBody (method)));
88 		}
89 
Normalize(string str)90 		public static string Normalize (string str)
91 		{
92 			return str.Trim ().Replace ("\r\n", "\n");
93 		}
94 
TestModule(string file, Action<ModuleDefinition> test, bool verify = true, bool readOnly = false, Type symbolReaderProvider = null, Type symbolWriterProvider = null, IAssemblyResolver assemblyResolver = null, bool applyWindowsRuntimeProjections = false)95 		public static void TestModule (string file, Action<ModuleDefinition> test, bool verify = true, bool readOnly = false, Type symbolReaderProvider = null, Type symbolWriterProvider = null, IAssemblyResolver assemblyResolver = null, bool applyWindowsRuntimeProjections = false)
96 		{
97 			Run (new ModuleTestCase (file, test, verify, readOnly, symbolReaderProvider, symbolWriterProvider, assemblyResolver, applyWindowsRuntimeProjections));
98 		}
99 
TestCSharp(string file, Action<ModuleDefinition> test, bool verify = true, bool readOnly = false, Type symbolReaderProvider = null, Type symbolWriterProvider = null, IAssemblyResolver assemblyResolver = null, bool applyWindowsRuntimeProjections = false)100 		public static void TestCSharp (string file, Action<ModuleDefinition> test, bool verify = true, bool readOnly = false, Type symbolReaderProvider = null, Type symbolWriterProvider = null, IAssemblyResolver assemblyResolver = null, bool applyWindowsRuntimeProjections = false)
101 		{
102 			Run (new CSharpTestCase (file, test, verify, readOnly, symbolReaderProvider, symbolWriterProvider, assemblyResolver, applyWindowsRuntimeProjections));
103 		}
104 
TestIL(string file, Action<ModuleDefinition> test, bool verify = true, bool readOnly = false, Type symbolReaderProvider = null, Type symbolWriterProvider = null, IAssemblyResolver assemblyResolver = null, bool applyWindowsRuntimeProjections = false)105 		public static void TestIL (string file, Action<ModuleDefinition> test, bool verify = true, bool readOnly = false, Type symbolReaderProvider = null, Type symbolWriterProvider = null, IAssemblyResolver assemblyResolver = null, bool applyWindowsRuntimeProjections = false)
106 		{
107 			Run (new ILTestCase (file, test, verify, readOnly, symbolReaderProvider, symbolWriterProvider, assemblyResolver, applyWindowsRuntimeProjections));
108 		}
109 
Run(TestCase testCase)110 		static void Run (TestCase testCase)
111 		{
112 			using (var runner = new TestRunner (testCase, TestCaseType.ReadDeferred))
113 				runner.RunTest ();
114 
115 			using (var runner = new TestRunner (testCase, TestCaseType.ReadImmediate))
116 				runner.RunTest ();
117 
118 			if (testCase.ReadOnly)
119 				return;
120 
121 #if !READ_ONLY
122 			using (var runner = new TestRunner (testCase, TestCaseType.WriteFromDeferred))
123 				runner.RunTest ();
124 
125 			using (var runner = new TestRunner (testCase, TestCaseType.WriteFromImmediate))
126 				runner.RunTest ();
127 #endif
128 		}
129 	}
130 
131 	abstract class TestCase {
132 
133 		public readonly bool Verify;
134 		public readonly bool ReadOnly;
135 		public readonly Type SymbolReaderProvider;
136 		public readonly Type SymbolWriterProvider;
137 		public readonly IAssemblyResolver AssemblyResolver;
138 		public readonly Action<ModuleDefinition> Test;
139 		public readonly bool ApplyWindowsRuntimeProjections;
140 
141 		public abstract string ModuleLocation { get; }
142 
143 		protected Assembly Assembly { get { return Test.Method.Module.Assembly; } }
144 
TestCase(Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)145 		protected TestCase (Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)
146 		{
147 			Test = test;
148 			Verify = verify;
149 			ReadOnly = readOnly;
150 			SymbolReaderProvider = symbolReaderProvider;
151 			SymbolWriterProvider = symbolWriterProvider;
152 			AssemblyResolver = assemblyResolver;
153 			ApplyWindowsRuntimeProjections = applyWindowsRuntimeProjections;
154 		}
155 	}
156 
157 	class ModuleTestCase : TestCase {
158 
159 		public readonly string Module;
160 
ModuleTestCase(string module, Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)161 		public ModuleTestCase (string module, Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)
162 			: base (test, verify, readOnly, symbolReaderProvider, symbolWriterProvider, assemblyResolver, applyWindowsRuntimeProjections)
163 		{
164 			Module = module;
165 		}
166 
167 		public override string ModuleLocation
168 		{
169 			get { return BaseTestFixture.GetAssemblyResourcePath (Module, Assembly); }
170 		}
171 	}
172 
173 	class CSharpTestCase : TestCase {
174 
175 		public readonly string File;
176 
CSharpTestCase(string file, Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)177 		public CSharpTestCase (string file, Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)
178 			: base (test, verify, readOnly, symbolReaderProvider, symbolWriterProvider, assemblyResolver, applyWindowsRuntimeProjections)
179 		{
180 			File = file;
181 		}
182 
183 		public override string ModuleLocation
184 		{
185 			get
186 			{
187 				return CompilationService.CompileResource (BaseTestFixture.GetCSharpResourcePath (File, Assembly));
188 			}
189 		}
190 	}
191 
192 	class ILTestCase : TestCase {
193 
194 		public readonly string File;
195 
ILTestCase(string file, Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)196 		public ILTestCase (string file, Action<ModuleDefinition> test, bool verify, bool readOnly, Type symbolReaderProvider, Type symbolWriterProvider, IAssemblyResolver assemblyResolver, bool applyWindowsRuntimeProjections)
197 			: base (test, verify, readOnly, symbolReaderProvider, symbolWriterProvider, assemblyResolver, applyWindowsRuntimeProjections)
198 		{
199 			File = file;
200 		}
201 
202 		public override string ModuleLocation
203 		{
204 			get
205 			{
206 				return CompilationService.CompileResource (BaseTestFixture.GetILResourcePath (File, Assembly)); ;
207 			}
208 		}
209 	}
210 
211 	class TestRunner : IDisposable {
212 
213 		readonly TestCase test_case;
214 		readonly TestCaseType type;
215 
216 		ModuleDefinition test_module;
217 		DefaultAssemblyResolver test_resolver;
218 
TestRunner(TestCase testCase, TestCaseType type)219 		public TestRunner (TestCase testCase, TestCaseType type)
220 		{
221 			this.test_case = testCase;
222 			this.type = type;
223 		}
224 
GetModule()225 		ModuleDefinition GetModule ()
226 		{
227 			var location = test_case.ModuleLocation;
228 
229 			var parameters = new ReaderParameters {
230 				SymbolReaderProvider = GetSymbolReaderProvider (),
231 				AssemblyResolver = GetAssemblyResolver (),
232 				ApplyWindowsRuntimeProjections = test_case.ApplyWindowsRuntimeProjections
233 			};
234 
235 			switch (type) {
236 			case TestCaseType.ReadImmediate:
237 				parameters.ReadingMode = ReadingMode.Immediate;
238 				return ModuleDefinition.ReadModule (location, parameters);
239 			case TestCaseType.ReadDeferred:
240 				parameters.ReadingMode = ReadingMode.Deferred;
241 				return ModuleDefinition.ReadModule (location, parameters);
242 #if !READ_ONLY
243 			case TestCaseType.WriteFromImmediate:
244 				parameters.ReadingMode = ReadingMode.Immediate;
245 				return RoundTrip (location, parameters, "cecil-irt");
246 			case TestCaseType.WriteFromDeferred:
247 				parameters.ReadingMode = ReadingMode.Deferred;
248 				return RoundTrip (location, parameters, "cecil-drt");
249 #endif
250 			default:
251 				return null;
252 			}
253 		}
254 
GetSymbolReaderProvider()255 		ISymbolReaderProvider GetSymbolReaderProvider ()
256 		{
257 			if (test_case.SymbolReaderProvider == null)
258 				return null;
259 
260 			return (ISymbolReaderProvider) Activator.CreateInstance (test_case.SymbolReaderProvider);
261 		}
262 
263 #if !READ_ONLY
GetSymbolWriterProvider()264 		ISymbolWriterProvider GetSymbolWriterProvider ()
265 		{
266 			if (test_case.SymbolReaderProvider == null)
267 				return null;
268 
269 			return (ISymbolWriterProvider) Activator.CreateInstance (test_case.SymbolWriterProvider);
270 		}
271 #endif
272 
GetAssemblyResolver()273 		IAssemblyResolver GetAssemblyResolver ()
274 		{
275 			if (test_case.AssemblyResolver != null)
276 				return test_case.AssemblyResolver;
277 
278 			test_resolver = new DefaultAssemblyResolver ();
279 			var directory = Path.GetDirectoryName (test_case.ModuleLocation);
280 			test_resolver.AddSearchDirectory (directory);
281 			return test_resolver;
282 		}
283 
284 #if !READ_ONLY
RoundTrip(string location, ReaderParameters reader_parameters, string folder)285 		ModuleDefinition RoundTrip (string location, ReaderParameters reader_parameters, string folder)
286 		{
287 			var rt_folder = Path.Combine (Path.GetTempPath (), folder);
288 			if (!Directory.Exists (rt_folder))
289 				Directory.CreateDirectory (rt_folder);
290 			var rt_module = Path.Combine (rt_folder, Path.GetFileName (location));
291 
292 			using (var module = ModuleDefinition.ReadModule (location, reader_parameters)) {
293 				var writer_parameters = new WriterParameters {
294 					SymbolWriterProvider = GetSymbolWriterProvider (),
295 				};
296 
297 				test_case.Test (module);
298 
299 				module.Write (rt_module, writer_parameters);
300 			}
301 
302 			if (test_case.Verify)
303 				CompilationService.Verify (rt_module);
304 
305 			return ModuleDefinition.ReadModule (rt_module, reader_parameters);
306 		}
307 #endif
RunTest()308 		public void RunTest ()
309 		{
310 			var module = GetModule ();
311 			if (module == null)
312 				return;
313 
314 			test_module = module;
315 			test_case.Test (module);
316 		}
317 
Dispose()318 		public void Dispose ()
319 		{
320 			if (test_module != null)
321 				test_module.Dispose ();
322 
323 			if (test_resolver != null)
324 				test_resolver.Dispose ();
325 		}
326 	}
327 
328 	enum TestCaseType {
329 		ReadImmediate,
330 		ReadDeferred,
331 #if !READ_ONLY
332 		WriteFromImmediate,
333 		WriteFromDeferred,
334 #endif
335 	}
336 }
337