2 // Microsoft.CSharp.CSharpCodeProviderTest.cs
5 // Gert Driesen (drieseng@users.sourceforge.net)
12 using System.CodeDom.Compiler;
13 using System.Collections.Specialized;
14 using System.Globalization;
16 using System.Reflection;
17 using Microsoft.CSharp;
18 using NUnit.Framework;
20 namespace MonoTests.Microsoft.CSharp
23 public class CSharpCodeProviderTest
25 private string _tempDir;
26 private CodeDomProvider _codeProvider;
28 private static readonly string _sourceTest1 = "public class Test1 {}";
29 private static readonly string _sourceTest2 = "public class Test2 {}";
34 _codeProvider = new CSharpCodeProvider ();
35 _tempDir = CreateTempDirectory ();
39 public void TearDown ()
41 RemoveDirectory (_tempDir);
45 public void FileExtension ()
47 Assert.AreEqual ("cs", _codeProvider.FileExtension);
51 public void LanguageOptionsTest ()
53 Assert.AreEqual (LanguageOptions.None, _codeProvider.LanguageOptions);
57 public void GeneratorSupports ()
59 ICodeGenerator codeGenerator = _codeProvider.CreateGenerator ();
60 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEnums), "#1");
61 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ArraysOfArrays), "#2");
62 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.AssemblyAttributes), "#3");
63 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ChainedConstructorArguments), "#4");
64 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ComplexExpressions), "#5");
65 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareDelegates), "#6");
66 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEnums), "#7");
67 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEvents), "#8");
68 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareInterfaces), "#9");
69 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareValueTypes), "#10");
70 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.EntryPointMethod), "#11");
71 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GotoStatements), "#12");
72 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.MultidimensionalArrays), "#13");
73 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.MultipleInterfaceMembers), "#14");
74 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.NestedTypes), "#15");
75 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ParameterAttributes), "#16");
76 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.PublicStaticMembers), "#17");
77 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ReferenceParameters), "#18");
78 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ReturnTypeAttributes), "#19");
79 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.StaticConstructors), "#20");
80 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.TryCatchStatements), "#21");
81 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.Win32Resources), "#22");
83 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareIndexerProperties), "#23");
84 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GenericTypeDeclaration), "#24");
85 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GenericTypeReference), "#25");
86 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.PartialTypes), "#26");
87 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.Resources), "#27");
92 public void CompileFromFile_InMemory ()
95 string sourceFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
96 using (FileStream f = new FileStream (sourceFile, FileMode.Create)) {
97 using (StreamWriter s = new StreamWriter (f)) {
98 s.Write (_sourceTest1);
104 CompilerParameters options = new CompilerParameters ();
105 options.GenerateExecutable = false;
106 options.GenerateInMemory = true;
107 options.TempFiles = new TempFileCollection (_tempDir);
109 options.EmbeddedResources.Add (sourceFile);
112 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
113 CompilerResults results = compiler.CompileAssemblyFromFile (options,
116 // verify compilation was successful
117 AssertCompileResults (results, true);
119 Assembly compiledAssembly = results.CompiledAssembly;
121 Assert.IsNotNull (compiledAssembly, "#1");
122 Assert.AreEqual (string.Empty, compiledAssembly.Location, "#2");
123 Assert.IsNull (results.PathToAssembly, "#3");
124 Assert.IsNotNull (compiledAssembly.GetType ("Test1"), "#4");
126 // verify we don't cleanup files in temp directory too agressively
127 string[] tempFiles = Directory.GetFiles (_tempDir);
128 Assert.AreEqual (1, tempFiles.Length, "#5");
129 Assert.AreEqual (sourceFile, tempFiles[0], "#6");
132 string[] resources = compiledAssembly.GetManifestResourceNames();
133 Assert.IsNotNull (resources, "#7");
134 Assert.AreEqual (1, resources.Length, "#8");
135 Assert.AreEqual ("file.cs", resources[0], "#9");
136 Assert.IsNull (compiledAssembly.GetFile ("file.cs"), "#10");
137 Assert.IsNotNull (compiledAssembly.GetManifestResourceStream ("file.cs"), "#11");
138 ManifestResourceInfo info = compiledAssembly.GetManifestResourceInfo ("file.cs");
139 Assert.IsNotNull (info, "#12");
140 Assert.IsNull (info.FileName, "#13");
141 Assert.IsNull (info.ReferencedAssembly, "#14");
142 Assert.AreEqual ((ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile), info.ResourceLocation, "#15");
147 public void CompileFromFileBatch_InMemory ()
149 // create source file
150 string sourceFile1 = Path.Combine (_tempDir, "file1." + _codeProvider.FileExtension);
151 using (FileStream f = new FileStream (sourceFile1, FileMode.Create)) {
152 using (StreamWriter s = new StreamWriter (f)) {
153 s.Write (_sourceTest1);
159 string sourceFile2 = Path.Combine (_tempDir, "file2." + _codeProvider.FileExtension);
160 using (FileStream f = new FileStream (sourceFile2, FileMode.Create)) {
161 using (StreamWriter s = new StreamWriter (f)) {
162 s.Write (_sourceTest2);
168 CompilerParameters options = new CompilerParameters ();
169 options.GenerateExecutable = false;
170 options.GenerateInMemory = true;
171 options.TempFiles = new TempFileCollection (_tempDir);
173 options.EmbeddedResources.Add (sourceFile1);
174 options.LinkedResources.Add (sourceFile2);
177 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
178 CompilerResults results = compiler.CompileAssemblyFromFileBatch (options,
179 new string[] { sourceFile1, sourceFile2 });
181 // verify compilation was successful
182 AssertCompileResults (results, true);
184 Assembly compiledAssembly = results.CompiledAssembly;
186 Assert.IsNotNull (compiledAssembly, "#1");
187 Assert.AreEqual (string.Empty, compiledAssembly.Location, "#2");
188 Assert.IsNull (results.PathToAssembly, "#3");
190 Assert.IsNotNull (compiledAssembly.GetType ("Test1"), "#4");
191 Assert.IsNotNull (compiledAssembly.GetType ("Test2"), "#5");
193 // verify we don't cleanup files in temp directory too agressively
194 string[] tempFiles = Directory.GetFiles (_tempDir);
195 Assert.AreEqual (2, tempFiles.Length, "#6");
196 Assert.IsTrue (File.Exists (sourceFile1), "#7");
197 Assert.IsTrue (File.Exists (sourceFile2), "#8");
200 string[] resources = compiledAssembly.GetManifestResourceNames();
201 Assert.IsNotNull (resources, "#9");
202 Assert.AreEqual (2, resources.Length, "#10");
204 Assert.AreEqual ("file1.cs", resources[0], "#A1");
205 Assert.IsNull (compiledAssembly.GetFile ("file1.cs"), "#A2");
206 Assert.IsNotNull (compiledAssembly.GetManifestResourceStream ("file1.cs"), "#A3");
207 ManifestResourceInfo info = compiledAssembly.GetManifestResourceInfo ("file1.cs");
208 Assert.IsNotNull (info, "#A4");
209 Assert.IsNull (info.FileName, "#A5");
210 Assert.IsNull (info.ReferencedAssembly, "#A6");
211 Assert.AreEqual ((ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile), info.ResourceLocation, "#A7");
213 Assert.AreEqual ("file2.cs", resources[1], "#B1");
215 compiledAssembly.GetFile ("file2.cs");
217 } catch (FileNotFoundException) {
220 compiledAssembly.GetManifestResourceStream ("file2.cs");
222 } catch (FileNotFoundException) {
224 info = compiledAssembly.GetManifestResourceInfo ("file2.cs");
225 Assert.IsNotNull (info, "#B4");
226 Assert.IsNotNull (info.FileName, "#B5");
227 Assert.AreEqual ("file2.cs", info.FileName, "#B6");
228 Assert.IsNull (info.ReferencedAssembly, "#B7");
229 Assert.AreEqual ((ResourceLocation) 0, info.ResourceLocation, "#B8");
234 public void CompileFromSource_InMemory ()
236 // create a file in temp directory to ensure that compiler is not removing
237 // too much (temporary) files
238 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
239 using (FileStream fs = File.Create (tempFile)) {
243 CompilerParameters options = new CompilerParameters ();
244 options.GenerateExecutable = false;
245 options.GenerateInMemory = true;
246 options.TempFiles = new TempFileCollection (_tempDir);
248 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
249 CompilerResults results = compiler.CompileAssemblyFromSource (options,
252 // verify compilation was successful
253 AssertCompileResults (results, true);
255 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
256 Assert.IsNull (results.PathToAssembly, "#2");
257 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
259 // verify we don't cleanup files in temp directory too agressively
260 string[] tempFiles = Directory.GetFiles (_tempDir);
261 Assert.AreEqual (1, tempFiles.Length, "#4");
262 Assert.AreEqual (tempFile, tempFiles[0], "#5");
266 public void CompileFromSourceBatch_InMemory ()
268 // create a file in temp directory to ensure that compiler is not removing
269 // too much (temporary) files
270 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
271 using (FileStream fs = File.Create (tempFile)) {
275 CompilerParameters options = new CompilerParameters ();
276 options.GenerateExecutable = false;
277 options.GenerateInMemory = true;
278 options.TempFiles = new TempFileCollection (_tempDir);
280 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
281 CompilerResults results = compiler.CompileAssemblyFromSourceBatch (options,
282 new string[] { _sourceTest1, _sourceTest2 });
284 // verify compilation was successful
285 AssertCompileResults (results, true);
287 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
288 Assert.IsNull (results.PathToAssembly, "#2");
290 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
291 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
293 // verify we don't cleanup files in temp directory too agressively
294 string[] tempFiles = Directory.GetFiles (_tempDir);
295 Assert.AreEqual (1, tempFiles.Length, "#5");
296 Assert.AreEqual (tempFile, tempFiles[0], "#6");
300 public void CompileFromDom_NotInMemory ()
302 // create a file in temp directory to ensure that compiler is not removing
303 // too much (temporary) files
304 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
305 using (FileStream fs = File.Create (tempFile)) {
309 // compile and verify result in separate appdomain to avoid file locks
310 AppDomain testDomain = CreateTestDomain ();
311 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
313 string outputAssembly = null;
316 outputAssembly = compileTester.CompileAssemblyFromDom (_tempDir);
318 AppDomain.Unload (testDomain);
321 // there should be two files in temp dir: temp file and output assembly
322 string[] tempFiles = Directory.GetFiles (_tempDir);
323 Assert.AreEqual (2, tempFiles.Length, "#1");
324 Assert.IsTrue (File.Exists (outputAssembly), "#2");
325 Assert.IsTrue (File.Exists (tempFile), "#3");
329 public void CompileFromDomBatch_NotInMemory ()
331 // create a file in temp directory to ensure that compiler is not removing
332 // too much (temporary) files
333 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
334 using (FileStream fs = File.Create (tempFile)) {
338 // compile and verify result in separate appdomain to avoid file locks
339 AppDomain testDomain = CreateTestDomain ();
340 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
342 string outputAssembly = null;
344 outputAssembly = compileTester.CompileAssemblyFromDomBatch (_tempDir);
346 AppDomain.Unload (testDomain);
349 // there should be two files in temp dir: temp file and output assembly
350 string[] tempFiles = Directory.GetFiles (_tempDir);
351 Assert.AreEqual (2, tempFiles.Length, "#1");
352 Assert.IsTrue (File.Exists (outputAssembly), "#2");
353 Assert.IsTrue (File.Exists (tempFile), "#3");
357 public void CompileFromDom_InMemory ()
359 // create a file in temp directory to ensure that compiler is not removing
360 // too much (temporary) files
361 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
362 using (FileStream fs = File.Create (tempFile)) {
366 CompilerParameters options = new CompilerParameters ();
367 options.GenerateExecutable = false;
368 options.GenerateInMemory = true;
369 options.TempFiles = new TempFileCollection (_tempDir);
371 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
372 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
374 // verify compilation was successful
375 AssertCompileResults (results, true);
377 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
378 Assert.IsNull (results.PathToAssembly, "#2");
380 // verify we don't cleanup files in temp directory too agressively
381 string[] tempFiles = Directory.GetFiles (_tempDir);
382 Assert.AreEqual (1, tempFiles.Length, "#3");
383 Assert.AreEqual (tempFile, tempFiles[0], "#4");
387 public void CompileFromDomBatch_InMemory ()
389 // create a file in temp directory to ensure that compiler is not removing
390 // too much (temporary) files
391 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
392 using (FileStream fs = File.Create (tempFile)) {
396 CompilerParameters options = new CompilerParameters ();
397 options.GenerateExecutable = false;
398 options.GenerateInMemory = true;
399 options.TempFiles = new TempFileCollection (_tempDir);
401 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
402 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options,
403 new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
405 // verify compilation was successful
406 AssertCompileResults (results, true);
408 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
409 Assert.IsNull (results.PathToAssembly, "#2");
411 // verify we don't cleanup files in temp directory too agressively
412 string[] tempFiles = Directory.GetFiles (_tempDir);
413 Assert.AreEqual (1, tempFiles.Length, "#3");
414 Assert.AreEqual (tempFile, tempFiles[0], "#4");
417 private static string CreateTempDirectory ()
419 // create a uniquely named zero-byte file
420 string tempFile = Path.GetTempFileName ();
421 // remove the temporary file
422 File.Delete (tempFile);
423 // create a directory named after the unique temporary file
424 Directory.CreateDirectory (tempFile);
425 // return the path to the temporary directory
429 private static void RemoveDirectory (string path)
432 if (Directory.Exists (path)) {
433 string[] directoryNames = Directory.GetDirectories (path);
434 foreach (string directoryName in directoryNames) {
435 RemoveDirectory (directoryName);
437 string[] fileNames = Directory.GetFiles (path);
438 foreach (string fileName in fileNames) {
439 File.Delete (fileName);
441 Directory.Delete (path, true);
443 } catch (Exception ex) {
444 throw new AssertionException ("Unable to cleanup '" + path + "'.", ex);
448 private static void AssertCompileResults (CompilerResults results, bool allowWarnings)
450 foreach (CompilerError compilerError in results.Errors) {
451 if (allowWarnings && compilerError.IsWarning) {
455 Assert.Fail (compilerError.ToString ());
459 private static AppDomain CreateTestDomain ()
461 return AppDomain.CreateDomain ("CompileFromDom", AppDomain.CurrentDomain.Evidence,
462 AppDomain.CurrentDomain.SetupInformation);
465 private static CrossDomainTester CreateCrossDomainTester (AppDomain domain)
467 Type testerType = typeof (CrossDomainTester);
469 return (CrossDomainTester) domain.CreateInstanceAndUnwrap (
470 testerType.Assembly.FullName, testerType.FullName, false,
471 BindingFlags.Public | BindingFlags.Instance, null, new object[0],
472 CultureInfo.InvariantCulture, new object[0], domain.Evidence);
475 private class CrossDomainTester : MarshalByRefObject
477 public string CompileAssemblyFromDom (string tempDir)
479 CompilerParameters options = new CompilerParameters ();
480 options.GenerateExecutable = false;
481 options.GenerateInMemory = false;
482 options.TempFiles = new TempFileCollection (tempDir);
484 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
485 ICodeCompiler compiler = codeProvider.CreateCompiler ();
486 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
488 // verify compilation was successful
489 AssertCompileResults (results, true);
491 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
492 "Location should not be empty string");
493 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
495 return results.PathToAssembly;
498 public string CompileAssemblyFromDomBatch (string tempDir)
500 CompilerParameters options = new CompilerParameters ();
501 options.GenerateExecutable = false;
502 options.GenerateInMemory = false;
503 options.TempFiles = new TempFileCollection (tempDir);
505 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
506 ICodeCompiler compiler = codeProvider.CreateCompiler ();
507 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
509 // verify compilation was successful
510 AssertCompileResults (results, true);
512 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
513 "Location should not be empty string");
514 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
516 return results.PathToAssembly;