2 // Microsoft.CSharp.CSharpCodeProviderTest.cs
5 // Gert Driesen (drieseng@users.sourceforge.net)
12 using System.CodeDom.Compiler;
13 using System.Globalization;
15 using System.Reflection;
16 using Microsoft.CSharp;
17 using NUnit.Framework;
19 namespace MonoTests.Microsoft.CSharp
22 public class CSharpCodeProviderTest
24 private string _tempDir;
25 private CodeDomProvider _codeProvider;
27 private static readonly string _sourceTest1 = "public class Test1 {}";
28 private static readonly string _sourceTest2 = "public class Test2 {}";
33 _codeProvider = new CSharpCodeProvider ();
34 _tempDir = CreateTempDirectory ();
38 public void TearDown ()
40 RemoveDirectory (_tempDir);
44 public void FileExtension ()
46 Assert.AreEqual ("cs", _codeProvider.FileExtension);
50 public void LanguageOptionsTest ()
52 Assert.AreEqual (LanguageOptions.None, _codeProvider.LanguageOptions);
56 public void GeneratorSupports ()
58 ICodeGenerator codeGenerator = _codeProvider.CreateGenerator ();
59 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEnums), "#1");
60 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ArraysOfArrays), "#2");
61 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.AssemblyAttributes), "#3");
62 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ChainedConstructorArguments), "#4");
63 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ComplexExpressions), "#5");
64 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareDelegates), "#6");
65 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEnums), "#7");
66 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEvents), "#8");
67 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareInterfaces), "#9");
68 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareValueTypes), "#10");
69 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.EntryPointMethod), "#11");
70 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GotoStatements), "#12");
71 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.MultidimensionalArrays), "#13");
72 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.MultipleInterfaceMembers), "#14");
73 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.NestedTypes), "#15");
74 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ParameterAttributes), "#16");
75 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.PublicStaticMembers), "#17");
76 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ReferenceParameters), "#18");
77 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ReturnTypeAttributes), "#19");
78 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.StaticConstructors), "#20");
79 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.TryCatchStatements), "#21");
80 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.Win32Resources), "#22");
82 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareIndexerProperties), "#23");
83 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GenericTypeDeclaration), "#24");
84 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GenericTypeReference), "#25");
85 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.PartialTypes), "#26");
86 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.Resources), "#27");
91 public void CompileFromFile_InMemory ()
94 string sourceFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
95 using (FileStream f = new FileStream (sourceFile, FileMode.Create)) {
96 using (StreamWriter s = new StreamWriter (f)) {
97 s.Write (_sourceTest1);
103 CompilerParameters options = new CompilerParameters ();
104 options.GenerateExecutable = false;
105 options.GenerateInMemory = true;
106 options.TempFiles = new TempFileCollection (_tempDir);
108 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
109 CompilerResults results = compiler.CompileAssemblyFromFile (options,
112 // verify compilation was successful
113 AssertCompileResults (results, true);
115 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
116 Assert.IsNull (results.PathToAssembly, "#2");
117 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
119 // verify we don't cleanup files in temp directory too agressively
120 string[] tempFiles = Directory.GetFiles (_tempDir);
121 Assert.AreEqual (1, tempFiles.Length, "#4");
122 Assert.AreEqual (sourceFile, tempFiles[0], "#5");
127 public void CompileFromFileBatch_InMemory ()
129 // create source file
130 string sourceFile1 = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
131 using (FileStream f = new FileStream (sourceFile1, FileMode.Create)) {
132 using (StreamWriter s = new StreamWriter (f)) {
133 s.Write (_sourceTest1);
139 string sourceFile2 = Path.Combine (_tempDir, "file2." + _codeProvider.FileExtension);
140 using (FileStream f = new FileStream (sourceFile2, FileMode.Create)) {
141 using (StreamWriter s = new StreamWriter (f)) {
142 s.Write (_sourceTest2);
148 CompilerParameters options = new CompilerParameters ();
149 options.GenerateExecutable = false;
150 options.GenerateInMemory = true;
151 options.TempFiles = new TempFileCollection (_tempDir);
153 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
154 CompilerResults results = compiler.CompileAssemblyFromFileBatch (options,
155 new string[] { sourceFile1, sourceFile2 });
157 // verify compilation was successful
158 AssertCompileResults (results, true);
160 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
161 Assert.IsNull (results.PathToAssembly, "#2");
163 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
164 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
166 // verify we don't cleanup files in temp directory too agressively
167 string[] tempFiles = Directory.GetFiles (_tempDir);
168 Assert.AreEqual (2, tempFiles.Length, "#5");
169 Assert.IsTrue (File.Exists (sourceFile1), "#6");
170 Assert.IsTrue (File.Exists (sourceFile2), "#7");
174 public void CompileFromSource_InMemory ()
176 // create a file in temp directory to ensure that compiler is not removing
177 // too much (temporary) files
178 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
179 using (FileStream fs = File.Create (tempFile)) {
183 CompilerParameters options = new CompilerParameters ();
184 options.GenerateExecutable = false;
185 options.GenerateInMemory = true;
186 options.TempFiles = new TempFileCollection (_tempDir);
188 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
189 CompilerResults results = compiler.CompileAssemblyFromSource (options,
192 // verify compilation was successful
193 AssertCompileResults (results, true);
195 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
196 Assert.IsNull (results.PathToAssembly, "#2");
197 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
199 // verify we don't cleanup files in temp directory too agressively
200 string[] tempFiles = Directory.GetFiles (_tempDir);
201 Assert.AreEqual (1, tempFiles.Length, "#4");
202 Assert.AreEqual (tempFile, tempFiles[0], "#5");
206 public void CompileFromSourceBatch_InMemory ()
208 // create a file in temp directory to ensure that compiler is not removing
209 // too much (temporary) files
210 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
211 using (FileStream fs = File.Create (tempFile)) {
215 CompilerParameters options = new CompilerParameters ();
216 options.GenerateExecutable = false;
217 options.GenerateInMemory = true;
218 options.TempFiles = new TempFileCollection (_tempDir);
220 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
221 CompilerResults results = compiler.CompileAssemblyFromSourceBatch (options,
222 new string[] { _sourceTest1, _sourceTest2 });
224 // verify compilation was successful
225 AssertCompileResults (results, true);
227 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
228 Assert.IsNull (results.PathToAssembly, "#2");
230 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
231 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
233 // verify we don't cleanup files in temp directory too agressively
234 string[] tempFiles = Directory.GetFiles (_tempDir);
235 Assert.AreEqual (1, tempFiles.Length, "#5");
236 Assert.AreEqual (tempFile, tempFiles[0], "#6");
240 public void CompileFromDom_NotInMemory ()
242 // create a file in temp directory to ensure that compiler is not removing
243 // too much (temporary) files
244 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
245 using (FileStream fs = File.Create (tempFile)) {
249 // compile and verify result in separate appdomain to avoid file locks
250 AppDomain testDomain = CreateTestDomain ();
251 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
253 string outputAssembly = null;
256 outputAssembly = compileTester.CompileAssemblyFromDom (_tempDir);
258 AppDomain.Unload (testDomain);
261 // there should be two files in temp dir: temp file and output assembly
262 string[] tempFiles = Directory.GetFiles (_tempDir);
263 Assert.AreEqual (2, tempFiles.Length, "#1");
264 Assert.IsTrue (File.Exists (outputAssembly), "#2");
265 Assert.IsTrue (File.Exists (tempFile), "#3");
269 public void CompileFromDomBatch_NotInMemory ()
271 // create a file in temp directory to ensure that compiler is not removing
272 // too much (temporary) files
273 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
274 using (FileStream fs = File.Create (tempFile)) {
278 // compile and verify result in separate appdomain to avoid file locks
279 AppDomain testDomain = CreateTestDomain ();
280 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
282 string outputAssembly = null;
284 outputAssembly = compileTester.CompileAssemblyFromDomBatch (_tempDir);
286 AppDomain.Unload (testDomain);
289 // there should be two files in temp dir: temp file and output assembly
290 string[] tempFiles = Directory.GetFiles (_tempDir);
291 Assert.AreEqual (2, tempFiles.Length, "#1");
292 Assert.IsTrue (File.Exists (outputAssembly), "#2");
293 Assert.IsTrue (File.Exists (tempFile), "#3");
297 public void CompileFromDom_InMemory ()
299 // create a file in temp directory to ensure that compiler is not removing
300 // too much (temporary) files
301 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
302 using (FileStream fs = File.Create (tempFile)) {
306 CompilerParameters options = new CompilerParameters ();
307 options.GenerateExecutable = false;
308 options.GenerateInMemory = true;
309 options.TempFiles = new TempFileCollection (_tempDir);
311 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
312 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
314 // verify compilation was successful
315 AssertCompileResults (results, true);
317 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
318 Assert.IsNull (results.PathToAssembly, "#2");
320 // verify we don't cleanup files in temp directory too agressively
321 string[] tempFiles = Directory.GetFiles (_tempDir);
322 Assert.AreEqual (1, tempFiles.Length, "#3");
323 Assert.AreEqual (tempFile, tempFiles[0], "#4");
327 public void CompileFromDomBatch_InMemory ()
329 // create a file in temp directory to ensure that compiler is not removing
330 // too much (temporary) files
331 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
332 using (FileStream fs = File.Create (tempFile)) {
336 CompilerParameters options = new CompilerParameters ();
337 options.GenerateExecutable = false;
338 options.GenerateInMemory = true;
339 options.TempFiles = new TempFileCollection (_tempDir);
341 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
342 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options,
343 new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
345 // verify compilation was successful
346 AssertCompileResults (results, true);
348 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
349 Assert.IsNull (results.PathToAssembly, "#2");
351 // verify we don't cleanup files in temp directory too agressively
352 string[] tempFiles = Directory.GetFiles (_tempDir);
353 Assert.AreEqual (1, tempFiles.Length, "#3");
354 Assert.AreEqual (tempFile, tempFiles[0], "#4");
357 private static string CreateTempDirectory ()
359 // create a uniquely named zero-byte file
360 string tempFile = Path.GetTempFileName ();
361 // remove the temporary file
362 File.Delete (tempFile);
363 // create a directory named after the unique temporary file
364 Directory.CreateDirectory (tempFile);
365 // return the path to the temporary directory
369 private static void RemoveDirectory (string path)
372 if (Directory.Exists (path)) {
373 string[] directoryNames = Directory.GetDirectories (path);
374 foreach (string directoryName in directoryNames) {
375 RemoveDirectory (directoryName);
377 string[] fileNames = Directory.GetFiles (path);
378 foreach (string fileName in fileNames) {
379 File.Delete (fileName);
381 Directory.Delete (path, true);
383 } catch (Exception ex) {
384 throw new AssertionException ("Unable to cleanup '" + path + "'.", ex);
388 private static void AssertCompileResults (CompilerResults results, bool allowWarnings)
390 foreach (CompilerError compilerError in results.Errors) {
391 if (allowWarnings && compilerError.IsWarning) {
395 Assert.Fail (compilerError.ToString ());
399 private static AppDomain CreateTestDomain ()
401 return AppDomain.CreateDomain ("CompileFromDom", AppDomain.CurrentDomain.Evidence,
402 AppDomain.CurrentDomain.SetupInformation);
405 private static CrossDomainTester CreateCrossDomainTester (AppDomain domain)
407 Type testerType = typeof (CrossDomainTester);
409 return (CrossDomainTester) domain.CreateInstanceAndUnwrap (
410 testerType.Assembly.FullName, testerType.FullName, false,
411 BindingFlags.Public | BindingFlags.Instance, null, new object[0],
412 CultureInfo.InvariantCulture, new object[0], domain.Evidence);
415 private class CrossDomainTester : MarshalByRefObject
417 public string CompileAssemblyFromDom (string tempDir)
419 CompilerParameters options = new CompilerParameters ();
420 options.GenerateExecutable = false;
421 options.GenerateInMemory = false;
422 options.TempFiles = new TempFileCollection (tempDir);
424 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
425 ICodeCompiler compiler = codeProvider.CreateCompiler ();
426 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
428 // verify compilation was successful
429 AssertCompileResults (results, true);
431 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
432 "Location should not be empty string");
433 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
435 return results.PathToAssembly;
438 public string CompileAssemblyFromDomBatch (string tempDir)
440 CompilerParameters options = new CompilerParameters ();
441 options.GenerateExecutable = false;
442 options.GenerateInMemory = false;
443 options.TempFiles = new TempFileCollection (tempDir);
445 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
446 ICodeCompiler compiler = codeProvider.CreateCompiler ();
447 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
449 // verify compilation was successful
450 AssertCompileResults (results, true);
452 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
453 "Location should not be empty string");
454 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
456 return results.PathToAssembly;