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