New test.
[mono.git] / mcs / class / System / Test / Microsoft.CSharp / CSharpCodeProviderTest.cs
1 //
2 // Microsoft.CSharp.CSharpCodeProviderTest.cs
3 //
4 // Author:
5 // Gert Driesen (drieseng@users.sourceforge.net)
6 //
7 // (C) 2005 Novell
8 //
9
10 using System;
11 using System.CodeDom;
12 using System.CodeDom.Compiler;
13 using System.Collections.Specialized;
14 using System.Globalization;
15 using System.IO;
16 using System.Reflection;
17 using Microsoft.CSharp;
18 using NUnit.Framework;
19
20 namespace MonoTests.Microsoft.CSharp
21 {
22         [TestFixture]
23         public class CSharpCodeProviderTest
24         {
25                 private string _tempDir;
26                 private CodeDomProvider _codeProvider;
27
28                 private static readonly string _sourceTest1 = "public class Test1 {}";
29                 private static readonly string _sourceTest2 = "public class Test2 {}";
30
31                 [SetUp]
32                 public void SetUp ()
33                 {
34                         _codeProvider = new CSharpCodeProvider ();
35                         _tempDir = CreateTempDirectory ();
36                 }
37
38                 [TearDown]
39                 public void TearDown ()
40                 {
41                         RemoveDirectory (_tempDir);
42                 }
43
44                 [Test]
45                 public void FileExtension ()
46                 {
47                         Assert.AreEqual ("cs", _codeProvider.FileExtension);
48                 }
49
50                 [Test]
51                 public void LanguageOptionsTest ()
52                 {
53                         Assert.AreEqual (LanguageOptions.None, _codeProvider.LanguageOptions);
54                 }
55
56                 [Test]
57                 public void GeneratorSupports ()
58                 {
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");
82 #if NET_2_0
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");
88 #endif
89                 }
90
91                 [Test]
92                 public void CompileFromFile_InMemory ()
93                 {
94                         // create source file
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);
99                                         s.Close ();
100                                 }
101                                 f.Close ();
102                         }
103
104                         CompilerParameters options = new CompilerParameters ();
105                         options.GenerateExecutable = false;
106                         options.GenerateInMemory = true;
107                         options.TempFiles = new TempFileCollection (_tempDir);
108 #if NET_2_0
109                         options.EmbeddedResources.Add (sourceFile);
110 #endif
111
112                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
113                         CompilerResults results = compiler.CompileAssemblyFromFile (options,
114                                 sourceFile);
115
116                         // verify compilation was successful
117                         AssertCompileResults (results, true);
118
119                         Assembly compiledAssembly = results.CompiledAssembly;
120
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");
125                         
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");
130                         
131 #if NET_2_0
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");
143 #endif
144                 }
145
146                 [Test]
147                 public void CompileFromFileBatch_InMemory ()
148                 {
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);
154                                         s.Close ();
155                                 }
156                                 f.Close ();
157                         }
158
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);
163                                         s.Close ();
164                                 }
165                                 f.Close ();
166                         }
167
168                         CompilerParameters options = new CompilerParameters ();
169                         options.GenerateExecutable = false;
170                         options.GenerateInMemory = true;
171                         options.TempFiles = new TempFileCollection (_tempDir);
172 #if NET_2_0
173                         options.EmbeddedResources.Add (sourceFile1);
174                         options.LinkedResources.Add (sourceFile2);
175 #endif
176
177                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
178                         CompilerResults results = compiler.CompileAssemblyFromFileBatch (options,
179                                 new string[] { sourceFile1, sourceFile2 });
180
181                         // verify compilation was successful
182                         AssertCompileResults (results, true);
183
184                         Assembly compiledAssembly = results.CompiledAssembly;
185
186                         Assert.IsNotNull (compiledAssembly, "#1");
187                         Assert.AreEqual (string.Empty, compiledAssembly.Location, "#2");
188                         Assert.IsNull (results.PathToAssembly, "#3");
189
190                         Assert.IsNotNull (compiledAssembly.GetType ("Test1"), "#4");
191                         Assert.IsNotNull (compiledAssembly.GetType ("Test2"), "#5");
192
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");
198
199 #if NET_2_0
200                         string[] resources = compiledAssembly.GetManifestResourceNames();
201                         Assert.IsNotNull (resources, "#9");
202                         Assert.AreEqual (2, resources.Length, "#10");
203
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");
212
213                         Assert.AreEqual ("file2.cs", resources[1], "#B1");
214                         try {
215                                 compiledAssembly.GetFile ("file2.cs");
216                                 Assert.Fail ("#B2");
217                         } catch (FileNotFoundException) {
218                         }
219                         try {
220                                 compiledAssembly.GetManifestResourceStream  ("file2.cs");
221                                 Assert.Fail ("#B3");
222                         } catch (FileNotFoundException) {
223                         }
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");
230 #endif
231                 }
232
233                 [Test]
234                 public void CompileFromSource_InMemory ()
235                 {
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)) {
240                                 fs.Close ();
241                         }
242
243                         CompilerParameters options = new CompilerParameters ();
244                         options.GenerateExecutable = false;
245                         options.GenerateInMemory = true;
246                         options.TempFiles = new TempFileCollection (_tempDir);
247
248                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
249                         CompilerResults results = compiler.CompileAssemblyFromSource (options,
250                                 _sourceTest1);
251
252                         // verify compilation was successful
253                         AssertCompileResults (results, true);
254
255                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
256                         Assert.IsNull (results.PathToAssembly, "#2");
257                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
258
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");
263                 }
264
265                 [Test]
266                 public void CompileFromSourceBatch_InMemory ()
267                 {
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)) {
272                                 fs.Close ();
273                         }
274
275                         CompilerParameters options = new CompilerParameters ();
276                         options.GenerateExecutable = false;
277                         options.GenerateInMemory = true;
278                         options.TempFiles = new TempFileCollection (_tempDir);
279
280                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
281                         CompilerResults results = compiler.CompileAssemblyFromSourceBatch (options,
282                                 new string[] { _sourceTest1, _sourceTest2 });
283
284                         // verify compilation was successful
285                         AssertCompileResults (results, true);
286
287                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
288                         Assert.IsNull (results.PathToAssembly, "#2");
289
290                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
291                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
292
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");
297                 }
298
299                 [Test]
300                 public void CompileFromDom_NotInMemory ()
301                 {
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)) {
306                                 fs.Close ();
307                         }
308
309                         // compile and verify result in separate appdomain to avoid file locks
310                         AppDomain testDomain = CreateTestDomain ();
311                         CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
312
313                         string outputAssembly = null;
314
315                         try {
316                                 outputAssembly = compileTester.CompileAssemblyFromDom (_tempDir);
317                         } finally {
318                                 AppDomain.Unload (testDomain);
319                         }
320
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");
326                 }
327
328                 [Test]
329                 public void CompileFromDomBatch_NotInMemory ()
330                 {
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)) {
335                                 fs.Close ();
336                         }
337
338                         // compile and verify result in separate appdomain to avoid file locks
339                         AppDomain testDomain = CreateTestDomain ();
340                         CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
341
342                         string outputAssembly = null;
343                         try {
344                                 outputAssembly = compileTester.CompileAssemblyFromDomBatch (_tempDir);
345                         } finally {
346                                 AppDomain.Unload (testDomain);
347                         }
348
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");
354                 }
355
356                 [Test]
357                 public void CompileFromDom_InMemory ()
358                 {
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)) {
363                                 fs.Close ();
364                         }
365
366                         CompilerParameters options = new CompilerParameters ();
367                         options.GenerateExecutable = false;
368                         options.GenerateInMemory = true;
369                         options.TempFiles = new TempFileCollection (_tempDir);
370
371                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
372                         CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
373
374                         // verify compilation was successful
375                         AssertCompileResults (results, true);
376
377                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
378                         Assert.IsNull (results.PathToAssembly, "#2");
379
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");
384                 }
385
386                 [Test]
387                 public void CompileFromDomBatch_InMemory ()
388                 {
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)) {
393                                 fs.Close ();
394                         }
395
396                         CompilerParameters options = new CompilerParameters ();
397                         options.GenerateExecutable = false;
398                         options.GenerateInMemory = true;
399                         options.TempFiles = new TempFileCollection (_tempDir);
400
401                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
402                         CompilerResults results = compiler.CompileAssemblyFromDomBatch (options,
403                                 new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
404
405                         // verify compilation was successful
406                         AssertCompileResults (results, true);
407
408                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
409                         Assert.IsNull (results.PathToAssembly, "#2");
410
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");
415                 }
416
417                 private static string CreateTempDirectory ()
418                 {
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
426                         return tempFile;
427                 }
428
429                 private static void RemoveDirectory (string path)
430                 {
431                         try {
432                                 if (Directory.Exists (path)) {
433                                         string[] directoryNames = Directory.GetDirectories (path);
434                                         foreach (string directoryName in directoryNames) {
435                                                 RemoveDirectory (directoryName);
436                                         }
437                                         string[] fileNames = Directory.GetFiles (path);
438                                         foreach (string fileName in fileNames) {
439                                                 File.Delete (fileName);
440                                         }
441                                         Directory.Delete (path, true);
442                                 }
443                         } catch (Exception ex) {
444                                 throw new AssertionException ("Unable to cleanup '" + path + "'.", ex);
445                         }
446                 }
447
448                 private static void AssertCompileResults (CompilerResults results, bool allowWarnings)
449                 {
450                         foreach (CompilerError compilerError in results.Errors) {
451                                 if (allowWarnings && compilerError.IsWarning) {
452                                         continue;
453                                 }
454
455                                 Assert.Fail (compilerError.ToString ());
456                         }
457                 }
458
459                 private static AppDomain CreateTestDomain ()
460                 {
461                         return AppDomain.CreateDomain ("CompileFromDom", AppDomain.CurrentDomain.Evidence,
462                                 AppDomain.CurrentDomain.SetupInformation);
463                 }
464
465                 private static CrossDomainTester CreateCrossDomainTester (AppDomain domain)
466                 {
467                         Type testerType = typeof (CrossDomainTester);
468
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);
473                 }
474
475                 private class CrossDomainTester : MarshalByRefObject
476                 {
477                         public string CompileAssemblyFromDom (string tempDir)
478                         {
479                                 CompilerParameters options = new CompilerParameters ();
480                                 options.GenerateExecutable = false;
481                                 options.GenerateInMemory = false;
482                                 options.TempFiles = new TempFileCollection (tempDir);
483
484                                 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
485                                 ICodeCompiler compiler = codeProvider.CreateCompiler ();
486                                 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
487
488                                 // verify compilation was successful
489                                 AssertCompileResults (results, true);
490
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");
494
495                                 return results.PathToAssembly;
496                         }
497
498                         public string CompileAssemblyFromDomBatch (string tempDir)
499                         {
500                                 CompilerParameters options = new CompilerParameters ();
501                                 options.GenerateExecutable = false;
502                                 options.GenerateInMemory = false;
503                                 options.TempFiles = new TempFileCollection (tempDir);
504
505                                 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
506                                 ICodeCompiler compiler = codeProvider.CreateCompiler ();
507                                 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
508
509                                 // verify compilation was successful
510                                 AssertCompileResults (results, true);
511
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");
515
516                                 return results.PathToAssembly;
517                         }
518                 }
519         }
520 }