* roottypes.cs: Rename from tree.cs.
[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.Globalization;
14 using System.IO;
15 using System.Reflection;
16 using Microsoft.CSharp;
17 using NUnit.Framework;
18
19 namespace MonoTests.Microsoft.CSharp
20 {
21         [TestFixture]
22         public class CSharpCodeProviderTest
23         {
24                 private string _tempDir;
25                 private CodeDomProvider _codeProvider;
26
27                 private static readonly string _sourceTest1 = "public class Test1 {}";
28                 private static readonly string _sourceTest2 = "public class Test2 {}";
29
30                 [SetUp]
31                 public void SetUp ()
32                 {
33                         _codeProvider = new CSharpCodeProvider ();
34                         _tempDir = CreateTempDirectory ();
35                 }
36
37                 [TearDown]
38                 public void TearDown ()
39                 {
40                         RemoveDirectory (_tempDir);
41                 }
42
43                 [Test]
44                 public void FileExtension ()
45                 {
46                         Assert.AreEqual ("cs", _codeProvider.FileExtension);
47                 }
48
49                 [Test]
50                 public void LanguageOptionsTest ()
51                 {
52                         Assert.AreEqual (LanguageOptions.None, _codeProvider.LanguageOptions);
53                 }
54
55                 [Test]
56                 public void GeneratorSupports ()
57                 {
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");
81 #if NET_2_0
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");
87 #endif
88                 }
89
90                 [Test]
91                 public void CompileFromFile_InMemory ()
92                 {
93                         // create source file
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);
98                                         s.Close ();
99                                 }
100                                 f.Close ();
101                         }
102
103                         CompilerParameters options = new CompilerParameters ();
104                         options.GenerateExecutable = false;
105                         options.GenerateInMemory = true;
106                         options.TempFiles = new TempFileCollection (_tempDir);
107
108                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
109                         CompilerResults results = compiler.CompileAssemblyFromFile (options,
110                                 sourceFile);
111
112                         // verify compilation was successful
113                         AssertCompileResults (results, true);
114
115                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
116                         Assert.IsNull (results.PathToAssembly, "#2");
117                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
118
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");
123
124                 }
125
126                 [Test]
127                 public void CompileFromFileBatch_InMemory ()
128                 {
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);
134                                         s.Close ();
135                                 }
136                                 f.Close ();
137                         }
138
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);
143                                         s.Close ();
144                                 }
145                                 f.Close ();
146                         }
147
148                         CompilerParameters options = new CompilerParameters ();
149                         options.GenerateExecutable = false;
150                         options.GenerateInMemory = true;
151                         options.TempFiles = new TempFileCollection (_tempDir);
152
153                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
154                         CompilerResults results = compiler.CompileAssemblyFromFileBatch (options,
155                                 new string[] { sourceFile1, sourceFile2 });
156
157                         // verify compilation was successful
158                         AssertCompileResults (results, true);
159
160                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
161                         Assert.IsNull (results.PathToAssembly, "#2");
162
163                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
164                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
165
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");
171                 }
172
173                 [Test]
174                 public void CompileFromSource_InMemory ()
175                 {
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)) {
180                                 fs.Close ();
181                         }
182
183                         CompilerParameters options = new CompilerParameters ();
184                         options.GenerateExecutable = false;
185                         options.GenerateInMemory = true;
186                         options.TempFiles = new TempFileCollection (_tempDir);
187
188                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
189                         CompilerResults results = compiler.CompileAssemblyFromSource (options,
190                                 _sourceTest1);
191
192                         // verify compilation was successful
193                         AssertCompileResults (results, true);
194
195                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
196                         Assert.IsNull (results.PathToAssembly, "#2");
197                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
198
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");
203                 }
204
205                 [Test]
206                 public void CompileFromSourceBatch_InMemory ()
207                 {
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)) {
212                                 fs.Close ();
213                         }
214
215                         CompilerParameters options = new CompilerParameters ();
216                         options.GenerateExecutable = false;
217                         options.GenerateInMemory = true;
218                         options.TempFiles = new TempFileCollection (_tempDir);
219
220                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
221                         CompilerResults results = compiler.CompileAssemblyFromSourceBatch (options,
222                                 new string[] { _sourceTest1, _sourceTest2 });
223
224                         // verify compilation was successful
225                         AssertCompileResults (results, true);
226
227                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
228                         Assert.IsNull (results.PathToAssembly, "#2");
229
230                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
231                         Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
232
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");
237                 }
238
239                 [Test]
240                 public void CompileFromDom_NotInMemory ()
241                 {
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)) {
246                                 fs.Close ();
247                         }
248
249                         // compile and verify result in separate appdomain to avoid file locks
250                         AppDomain testDomain = CreateTestDomain ();
251                         CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
252
253                         string outputAssembly = null;
254
255                         try {
256                                 outputAssembly = compileTester.CompileAssemblyFromDom (_tempDir);
257                         } finally {
258                                 AppDomain.Unload (testDomain);
259                         }
260
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");
266                 }
267
268                 [Test]
269                 public void CompileFromDomBatch_NotInMemory ()
270                 {
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)) {
275                                 fs.Close ();
276                         }
277
278                         // compile and verify result in separate appdomain to avoid file locks
279                         AppDomain testDomain = CreateTestDomain ();
280                         CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
281
282                         string outputAssembly = null;
283                         try {
284                                 outputAssembly = compileTester.CompileAssemblyFromDomBatch (_tempDir);
285                         } finally {
286                                 AppDomain.Unload (testDomain);
287                         }
288
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");
294                 }
295
296                 [Test]
297                 public void CompileFromDom_InMemory ()
298                 {
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)) {
303                                 fs.Close ();
304                         }
305
306                         CompilerParameters options = new CompilerParameters ();
307                         options.GenerateExecutable = false;
308                         options.GenerateInMemory = true;
309                         options.TempFiles = new TempFileCollection (_tempDir);
310
311                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
312                         CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
313
314                         // verify compilation was successful
315                         AssertCompileResults (results, true);
316
317                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
318                         Assert.IsNull (results.PathToAssembly, "#2");
319
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");
324                 }
325
326                 [Test]
327                 public void CompileFromDomBatch_InMemory ()
328                 {
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)) {
333                                 fs.Close ();
334                         }
335
336                         CompilerParameters options = new CompilerParameters ();
337                         options.GenerateExecutable = false;
338                         options.GenerateInMemory = true;
339                         options.TempFiles = new TempFileCollection (_tempDir);
340
341                         ICodeCompiler compiler = _codeProvider.CreateCompiler ();
342                         CompilerResults results = compiler.CompileAssemblyFromDomBatch (options,
343                                 new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
344
345                         // verify compilation was successful
346                         AssertCompileResults (results, true);
347
348                         Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
349                         Assert.IsNull (results.PathToAssembly, "#2");
350
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");
355                 }
356
357                 private static string CreateTempDirectory ()
358                 {
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
366                         return tempFile;
367                 }
368
369                 private static void RemoveDirectory (string path)
370                 {
371                         try {
372                                 if (Directory.Exists (path)) {
373                                         string[] directoryNames = Directory.GetDirectories (path);
374                                         foreach (string directoryName in directoryNames) {
375                                                 RemoveDirectory (directoryName);
376                                         }
377                                         string[] fileNames = Directory.GetFiles (path);
378                                         foreach (string fileName in fileNames) {
379                                                 File.Delete (fileName);
380                                         }
381                                         Directory.Delete (path, true);
382                                 }
383                         } catch (Exception ex) {
384                                 throw new AssertionException ("Unable to cleanup '" + path + "'.", ex);
385                         }
386                 }
387
388                 private static void AssertCompileResults (CompilerResults results, bool allowWarnings)
389                 {
390                         foreach (CompilerError compilerError in results.Errors) {
391                                 if (allowWarnings && compilerError.IsWarning) {
392                                         continue;
393                                 }
394
395                                 Assert.Fail (compilerError.ToString ());
396                         }
397                 }
398
399                 private static AppDomain CreateTestDomain ()
400                 {
401                         return AppDomain.CreateDomain ("CompileFromDom", AppDomain.CurrentDomain.Evidence,
402                                 AppDomain.CurrentDomain.SetupInformation);
403                 }
404
405                 private static CrossDomainTester CreateCrossDomainTester (AppDomain domain)
406                 {
407                         Type testerType = typeof (CrossDomainTester);
408
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);
413                 }
414
415                 private class CrossDomainTester : MarshalByRefObject
416                 {
417                         public string CompileAssemblyFromDom (string tempDir)
418                         {
419                                 CompilerParameters options = new CompilerParameters ();
420                                 options.GenerateExecutable = false;
421                                 options.GenerateInMemory = false;
422                                 options.TempFiles = new TempFileCollection (tempDir);
423
424                                 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
425                                 ICodeCompiler compiler = codeProvider.CreateCompiler ();
426                                 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
427
428                                 // verify compilation was successful
429                                 AssertCompileResults (results, true);
430
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");
434
435                                 return results.PathToAssembly;
436                         }
437
438                         public string CompileAssemblyFromDomBatch (string tempDir)
439                         {
440                                 CompilerParameters options = new CompilerParameters ();
441                                 options.GenerateExecutable = false;
442                                 options.GenerateInMemory = false;
443                                 options.TempFiles = new TempFileCollection (tempDir);
444
445                                 CSharpCodeProvider codeProvider = new CSharpCodeProvider ();
446                                 ICodeCompiler compiler = codeProvider.CreateCompiler ();
447                                 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
448
449                                 // verify compilation was successful
450                                 AssertCompileResults (results, true);
451
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");
455
456                                 return results.PathToAssembly;
457                         }
458                 }
459         }
460 }