2 // Microsoft.VisualBasic.VBCodeProvider.cs
\r
5 // Jochen Wezel (jwezel@compumaster.de)
\r
7 // (C) 2003 Jochen Wezel (CompuMaster GmbH)
\r
9 // Last modifications:
\r
10 // 2003-12-10 JW: publishing of this file
\r
14 using System.CodeDom;
\r
15 using System.CodeDom.Compiler;
\r
16 using System.ComponentModel;
\r
17 using System.Collections.Specialized;
\r
18 using System.Globalization;
\r
19 using System.Reflection;
\r
20 using System.Diagnostics;
\r
22 using Microsoft.VisualBasic;
\r
23 using NUnit.Framework;
\r
25 namespace MonoTests.Microsoft.VisualBasic
\r
35 public class VBCodeProviderTest
\r
37 private string _tempDir;
\r
38 private CodeDomProvider _codeProvider;
\r
39 private static OsType OS;
\r
40 private static char DSC = Path.DirectorySeparatorChar;
\r
42 private static readonly string _sourceTest1 = "Public Class Test1" +
\r
43 Environment.NewLine + "End Class";
\r
44 private static readonly string _sourceTest2 = "Public Class Test2" +
\r
45 Environment.NewLine + "End Class";
\r
48 public void GetReady ()
\r
52 } else if ('\\' == DSC) {
\r
53 OS = OsType.Windows;
\r
58 _codeProvider = new VBCodeProvider ();
\r
59 _tempDir = CreateTempDirectory ();
\r
63 public void TearDown ()
\r
65 RemoveDirectory (_tempDir);
\r
69 public void FileExtension ()
\r
71 Assert.AreEqual ("vb", _codeProvider.FileExtension, "#JW10");
\r
75 public void LanguageOptionsTest ()
\r
77 Assert.AreEqual (LanguageOptions.CaseInsensitive, _codeProvider.LanguageOptions, "#JW20");
\r
81 public void CreateCompiler ()
\r
83 // Prepare the compilation
\r
84 ICodeCompiler codeCompiler = _codeProvider.CreateCompiler ();
\r
85 Assert.IsNotNull (codeCompiler, "#JW30 - CreateCompiler");
\r
87 CompilerParameters options = new CompilerParameters ();
\r
88 options.GenerateExecutable = true;
\r
89 options.IncludeDebugInformation = true;
\r
90 options.TreatWarningsAsErrors = true;
\r
92 // process compilation
\r
93 CompilerResults compilerResults = codeCompiler.CompileAssemblyFromSource (options,
\r
94 "public class TestModule" + Environment.NewLine + "public shared sub Main()"
\r
95 + Environment.NewLine + "System.Console.Write(\"Hello world!\")"
\r
96 + Environment.NewLine + "End Sub" + Environment.NewLine + "End Class");
\r
98 // Analyse the compilation success/messages
\r
99 StringCollection MyOutput = compilerResults.Output;
\r
100 string MyOutStr = "";
\r
101 foreach (string MyStr in MyOutput) {
\r
102 MyOutStr += MyStr + Environment.NewLine + Environment.NewLine;
\r
105 if (compilerResults.Errors.Count != 0) {
\r
106 Assert.Fail ("#JW31 - Hello world compilation: " + MyOutStr);
\r
110 Assembly MyAss = compilerResults.CompiledAssembly;
\r
111 } catch (Exception ex) {
\r
112 Assert.Fail ("#JW32 - compilerResults.CompiledAssembly hasn't been an expected object" +
\r
113 Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace);
\r
116 // Execute the test app
\r
117 ProcessStartInfo NewProcInfo = new ProcessStartInfo ();
\r
119 NewProcInfo.FileName = compilerResults.CompiledAssembly.Location;
\r
121 NewProcInfo.FileName = "mono";
\r
122 NewProcInfo.Arguments = compilerResults.CompiledAssembly.Location;
\r
124 NewProcInfo.RedirectStandardOutput = true;
\r
125 NewProcInfo.UseShellExecute = false;
\r
126 NewProcInfo.CreateNoWindow = true;
\r
127 string TestAppOutput = "";
\r
129 Process MyProc = Process.Start (NewProcInfo);
\r
130 MyProc.WaitForExit ();
\r
131 TestAppOutput = MyProc.StandardOutput.ReadToEnd ();
\r
134 } catch (Exception ex) {
\r
135 Assert.Fail ("#JW34 - " + ex.Message + Environment.NewLine + ex.StackTrace);
\r
137 Assert.AreEqual ("Hello world!", TestAppOutput, "#JW33 - Application output");
\r
141 File.Delete (NewProcInfo.FileName);
\r
146 public void CreateGenerator ()
\r
148 ICodeGenerator MyVBCodeGen;
\r
149 MyVBCodeGen = _codeProvider.CreateGenerator ();
\r
150 Assert.IsNotNull (MyVBCodeGen, "#JW40 - CreateGenerator");
\r
151 Assert.IsTrue (MyVBCodeGen.Supports (GeneratorSupport.DeclareEnums), "#JW41");
\r
155 public void CompileFromFile_InMemory ()
\r
157 // create vb source file
\r
158 string sourceFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
159 using (FileStream f = new FileStream (sourceFile, FileMode.Create)) {
\r
160 using (StreamWriter s = new StreamWriter (f)) {
\r
161 s.Write (_sourceTest1);
\r
167 CompilerParameters options = new CompilerParameters ();
\r
168 options.GenerateExecutable = false;
\r
169 options.GenerateInMemory = true;
\r
170 options.TempFiles = new TempFileCollection (_tempDir);
\r
172 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
\r
173 CompilerResults results = compiler.CompileAssemblyFromFile (options,
\r
176 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
\r
177 Assert.IsNull (results.PathToAssembly, "#2");
\r
178 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
\r
180 // verify we don't cleanup files in temp directory too agressively
\r
181 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
183 foreach (string file in tempFiles) {
\r
184 if (file != sourceFile) {
\r
185 Assert.Fail ("TEMPFILE: " + file);
\r
189 Assert.AreEqual (1, tempFiles.Length, "#4");
\r
190 Assert.AreEqual (sourceFile, tempFiles[0], "#5");
\r
195 public void CompileFromFileBatch_InMemory ()
\r
197 // create vb source file
\r
198 string sourceFile1 = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
199 using (FileStream f = new FileStream (sourceFile1, FileMode.Create)) {
\r
200 using (StreamWriter s = new StreamWriter (f)) {
\r
201 s.Write (_sourceTest1);
\r
207 string sourceFile2 = Path.Combine (_tempDir, "file2." + _codeProvider.FileExtension);
\r
208 using (FileStream f = new FileStream (sourceFile2, FileMode.Create)) {
\r
209 using (StreamWriter s = new StreamWriter (f)) {
\r
210 s.Write (_sourceTest2);
\r
216 CompilerParameters options = new CompilerParameters ();
\r
217 options.GenerateExecutable = false;
\r
218 options.GenerateInMemory = true;
\r
219 options.TempFiles = new TempFileCollection (_tempDir);
\r
221 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
\r
222 CompilerResults results = compiler.CompileAssemblyFromFileBatch (options,
\r
223 new string[] { sourceFile1, sourceFile2 });
\r
225 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
\r
226 Assert.IsNull (results.PathToAssembly, "#2");
\r
228 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
\r
229 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
\r
231 // verify we don't cleanup files in temp directory too agressively
\r
232 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
233 Assert.AreEqual (2, tempFiles.Length, "#5");
\r
234 Assert.IsTrue (File.Exists (sourceFile1), "#6");
\r
235 Assert.IsTrue (File.Exists (sourceFile2), "#7");
\r
239 public void CompileFromSource_InMemory ()
\r
241 // create a file in temp directory to ensure that compiler is not removing
\r
242 // too much (temporary) files
\r
243 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
244 using (FileStream fs = File.Create (tempFile)) {
\r
248 CompilerParameters options = new CompilerParameters ();
\r
249 options.GenerateExecutable = false;
\r
250 options.GenerateInMemory = true;
\r
251 options.TempFiles = new TempFileCollection (_tempDir);
\r
253 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
\r
254 CompilerResults results = compiler.CompileAssemblyFromSource (options,
\r
257 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
\r
258 Assert.IsNull (results.PathToAssembly, "#2");
\r
259 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
\r
261 // verify we don't cleanup files in temp directory too agressively
\r
262 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
263 Assert.AreEqual (1, tempFiles.Length, "#4");
\r
264 Assert.AreEqual (tempFile, tempFiles[0], "#5");
\r
268 public void CompileFromSourceBatch_InMemory ()
\r
270 // create a file in temp directory to ensure that compiler is not removing
\r
271 // too much (temporary) files
\r
272 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
273 using (FileStream fs = File.Create (tempFile)) {
\r
277 CompilerParameters options = new CompilerParameters ();
\r
278 options.GenerateExecutable = false;
\r
279 options.GenerateInMemory = true;
\r
280 options.TempFiles = new TempFileCollection (_tempDir);
\r
282 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
\r
283 CompilerResults results = compiler.CompileAssemblyFromSourceBatch (options,
\r
284 new string[] { _sourceTest1, _sourceTest2 });
\r
286 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
\r
287 Assert.IsNull (results.PathToAssembly, "#2");
\r
289 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
\r
290 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
\r
292 // verify we don't cleanup files in temp directory too agressively
\r
293 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
294 Assert.AreEqual (1, tempFiles.Length, "#5");
\r
295 Assert.AreEqual (tempFile, tempFiles[0], "#6");
\r
299 public void CompileFromDom_NotInMemory ()
\r
301 // create a file in temp directory to ensure that compiler is not removing
\r
302 // too much (temporary) files
\r
303 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
304 using (FileStream fs = File.Create (tempFile)) {
\r
308 // compile and verify result in separate appdomain to avoid file locks
\r
309 AppDomain testDomain = CreateTestDomain ();
\r
310 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
\r
312 string outputAssembly = null;
\r
315 outputAssembly = compileTester.CompileAssemblyFromDom (_tempDir);
\r
317 AppDomain.Unload (testDomain);
\r
320 // there should be two files in temp dir: temp file and output assembly
\r
321 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
322 Assert.AreEqual (2, tempFiles.Length, "#1");
\r
323 Assert.IsTrue (File.Exists (outputAssembly), "#2");
\r
324 Assert.IsTrue (File.Exists (tempFile), "#3");
\r
328 public void CompileFromDomBatch_NotInMemory ()
\r
330 // create a file in temp directory to ensure that compiler is not removing
\r
331 // too much (temporary) files
\r
332 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
333 using (FileStream fs = File.Create (tempFile)) {
\r
337 // compile and verify result in separate appdomain to avoid file locks
\r
338 AppDomain testDomain = CreateTestDomain ();
\r
339 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
\r
341 string outputAssembly = null;
\r
344 outputAssembly = compileTester.CompileAssemblyFromDomBatch (_tempDir);
\r
346 AppDomain.Unload (testDomain);
\r
349 // there should be two files in temp dir: temp file and output assembly
\r
350 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
351 Assert.AreEqual (2, tempFiles.Length, "#1");
\r
352 Assert.IsTrue (File.Exists (outputAssembly), "#2");
\r
353 Assert.IsTrue (File.Exists (tempFile), "#3");
\r
357 public void CompileFromDom_InMemory ()
\r
359 // create a file in temp directory to ensure that compiler is not removing
\r
360 // too much (temporary) files
\r
361 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
362 using (FileStream fs = File.Create (tempFile)) {
\r
366 CompilerParameters options = new CompilerParameters ();
\r
367 options.GenerateExecutable = false;
\r
368 options.GenerateInMemory = true;
\r
369 options.TempFiles = new TempFileCollection (_tempDir);
\r
371 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
\r
372 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
\r
374 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
\r
375 Assert.IsNull (results.PathToAssembly, "#2");
\r
377 // verify we don't cleanup files in temp directory too agressively
\r
378 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
379 Assert.AreEqual (1, tempFiles.Length, "#3");
\r
380 Assert.AreEqual (tempFile, tempFiles[0], "#4");
\r
384 public void CompileFromDomBatch_InMemory ()
\r
386 // create a file in temp directory to ensure that compiler is not removing
\r
387 // too much (temporary) files
\r
388 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
\r
389 using (FileStream fs = File.Create (tempFile)) {
\r
393 CompilerParameters options = new CompilerParameters ();
\r
394 options.GenerateExecutable = false;
\r
395 options.GenerateInMemory = true;
\r
396 options.TempFiles = new TempFileCollection (_tempDir);
\r
398 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
\r
399 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options,
\r
400 new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
\r
402 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
\r
403 Assert.IsNull (results.PathToAssembly, "#2");
\r
405 // verify we don't cleanup files in temp directory too agressively
\r
406 string[] tempFiles = Directory.GetFiles (_tempDir);
\r
407 Assert.AreEqual (1, tempFiles.Length, "#3");
\r
408 Assert.AreEqual (tempFile, tempFiles[0], "#4");
\r
412 public void CreateParser ()
\r
414 //System.CodeDom.Compiler.ICodeParser CreateParser()
\r
418 public void CreateObjRef ()
\r
420 //System.Runtime.Remoting.ObjRef CreateObjRef(System.Type requestedType)
\r
426 return OS == OsType.Windows;
\r
433 return OS == OsType.Unix;
\r
440 return OS == OsType.Mac;
\r
444 private static string CreateTempDirectory ()
\r
446 // create a uniquely named zero-byte file
\r
447 string tempFile = Path.GetTempFileName ();
\r
448 // remove the temporary file
\r
449 File.Delete (tempFile);
\r
450 // create a directory named after the unique temporary file
\r
451 Directory.CreateDirectory (tempFile);
\r
452 // return the path to the temporary directory
\r
456 private static void RemoveDirectory (string path)
\r
459 if (Directory.Exists (path)) {
\r
460 string[] directoryNames = Directory.GetDirectories (path);
\r
461 foreach (string directoryName in directoryNames) {
\r
462 RemoveDirectory (directoryName);
\r
464 string[] fileNames = Directory.GetFiles (path);
\r
465 foreach (string fileName in fileNames) {
\r
466 File.Delete (fileName);
\r
468 Directory.Delete (path, true);
\r
470 } catch (Exception ex) {
\r
471 throw new AssertionException ("Unable to cleanup '" + path + "'.", ex);
\r
475 private static AppDomain CreateTestDomain ()
\r
477 return AppDomain.CreateDomain ("CompileFromDom", AppDomain.CurrentDomain.Evidence,
\r
478 AppDomain.CurrentDomain.SetupInformation);
\r
481 private static CrossDomainTester CreateCrossDomainTester (AppDomain domain)
\r
483 Type testerType = typeof (CrossDomainTester);
\r
485 return (CrossDomainTester) domain.CreateInstanceAndUnwrap (
\r
486 testerType.Assembly.FullName, testerType.FullName, false,
\r
487 BindingFlags.Public | BindingFlags.Instance, null, new object[0],
\r
488 CultureInfo.InvariantCulture, new object[0], domain.Evidence);
\r
491 private class CrossDomainTester : MarshalByRefObject
\r
493 public string CompileAssemblyFromDom (string tempDir)
\r
495 CompilerParameters options = new CompilerParameters ();
\r
496 options.GenerateExecutable = false;
\r
497 options.GenerateInMemory = false;
\r
498 options.TempFiles = new TempFileCollection (tempDir);
\r
500 VBCodeProvider codeProvider = new VBCodeProvider ();
\r
501 ICodeCompiler compiler = codeProvider.CreateCompiler ();
\r
502 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
\r
504 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
\r
505 "Location should not be empty string");
\r
506 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
\r
508 return results.PathToAssembly;
\r
511 public string CompileAssemblyFromDomBatch (string tempDir)
\r
513 CompilerParameters options = new CompilerParameters ();
\r
514 options.GenerateExecutable = false;
\r
515 options.GenerateInMemory = false;
\r
516 options.TempFiles = new TempFileCollection (tempDir);
\r
518 VBCodeProvider codeProvider = new VBCodeProvider ();
\r
519 ICodeCompiler compiler = codeProvider.CreateCompiler ();
\r
520 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
\r
522 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
\r
523 "Location should not be empty string");
\r
524 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
\r
526 return results.PathToAssembly;
\r