2 // Microsoft.VisualBasic.VBCodeProvider.cs
5 // Jochen Wezel (jwezel@compumaster.de)
7 // (C) 2003 Jochen Wezel (CompuMaster GmbH)
10 // 2003-12-10 JW: publishing of this file
15 using System.CodeDom.Compiler;
16 using System.Collections.Specialized;
17 using System.Globalization;
18 using System.Reflection;
19 using System.Diagnostics;
22 using Microsoft.VisualBasic;
23 using NUnit.Framework;
25 namespace MonoTests.Microsoft.VisualBasic
35 // mbas no longer exists
36 [Category ("NotWorking")]
37 public class VBCodeProviderTest
39 private string _tempDir;
40 private CodeDomProvider _codeProvider;
41 private static OsType OS;
42 private static char DSC = Path.DirectorySeparatorChar;
44 private static readonly string _sourceTest1 = "Public Class Test1" +
45 Environment.NewLine + "End Class";
46 private static readonly string _sourceTest2 = "Public Class Test2" +
47 Environment.NewLine + "End Class";
50 public void GetReady ()
54 } else if ('\\' == DSC) {
60 _codeProvider = new VBCodeProvider ();
61 _tempDir = CreateTempDirectory ();
65 public void TearDown ()
67 RemoveDirectory (_tempDir);
71 public void FileExtension ()
73 Assert.AreEqual ("vb", _codeProvider.FileExtension, "#JW10");
77 public void LanguageOptionsTest ()
79 Assert.AreEqual (LanguageOptions.CaseInsensitive, _codeProvider.LanguageOptions, "#JW20");
83 public void GeneratorSupports ()
85 ICodeGenerator codeGenerator = _codeProvider.CreateGenerator ();
86 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEnums), "#1");
87 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ArraysOfArrays), "#2");
88 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.AssemblyAttributes), "#3");
89 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ChainedConstructorArguments), "#4");
90 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ComplexExpressions), "#5");
91 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareDelegates), "#6");
92 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEnums), "#7");
93 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareEvents), "#8");
94 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareInterfaces), "#9");
95 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareValueTypes), "#10");
96 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.EntryPointMethod), "#11");
97 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GotoStatements), "#12");
98 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.MultidimensionalArrays), "#13");
99 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.MultipleInterfaceMembers), "#14");
100 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.NestedTypes), "#15");
101 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ParameterAttributes), "#16");
102 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.PublicStaticMembers), "#17");
103 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ReferenceParameters), "#18");
104 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.ReturnTypeAttributes), "#19");
105 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.StaticConstructors), "#20");
106 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.TryCatchStatements), "#21");
107 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.Win32Resources), "#22");
109 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.DeclareIndexerProperties), "#23");
110 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GenericTypeDeclaration), "#24");
111 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.GenericTypeReference), "#25");
112 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.PartialTypes), "#26");
113 Assert.IsTrue (codeGenerator.Supports (GeneratorSupport.Resources), "#27");
119 // there's not yet an mbas for the 2.0 profile
120 [Category ("NotWorking")]
122 public void CreateCompiler ()
124 // Prepare the compilation
125 ICodeCompiler codeCompiler = _codeProvider.CreateCompiler ();
126 Assert.IsNotNull (codeCompiler, "#JW30 - CreateCompiler");
128 CompilerParameters options = new CompilerParameters ();
129 options.GenerateExecutable = true;
130 options.IncludeDebugInformation = true;
131 options.TreatWarningsAsErrors = true;
133 // process compilation
134 CompilerResults compilerResults = codeCompiler.CompileAssemblyFromSource (options,
135 "public class TestModule" + Environment.NewLine + "public shared sub Main()"
136 + Environment.NewLine + "System.Console.Write(\"Hello world!\")"
137 + Environment.NewLine + "End Sub" + Environment.NewLine + "End Class");
139 // Analyse the compilation success/messages
140 StringCollection MyOutput = compilerResults.Output;
141 string MyOutStr = "";
142 foreach (string MyStr in MyOutput) {
143 MyOutStr += MyStr + Environment.NewLine + Environment.NewLine;
146 if (compilerResults.Errors.Count != 0) {
147 Assert.Fail ("#JW31 - Hello world compilation: " + MyOutStr);
151 Assembly MyAss = compilerResults.CompiledAssembly;
152 } catch (Exception ex) {
153 Assert.Fail ("#JW32 - compilerResults.CompiledAssembly hasn't been an expected object" +
154 Environment.NewLine + ex.Message + Environment.NewLine + ex.StackTrace);
157 // Execute the test app
158 ProcessStartInfo NewProcInfo = new ProcessStartInfo ();
160 NewProcInfo.FileName = compilerResults.CompiledAssembly.Location;
162 NewProcInfo.FileName = "mono";
163 NewProcInfo.Arguments = compilerResults.CompiledAssembly.Location;
165 NewProcInfo.RedirectStandardOutput = true;
166 NewProcInfo.UseShellExecute = false;
167 NewProcInfo.CreateNoWindow = true;
168 string TestAppOutput = "";
170 Process MyProc = Process.Start (NewProcInfo);
171 MyProc.WaitForExit ();
172 TestAppOutput = MyProc.StandardOutput.ReadToEnd ();
175 } catch (Exception ex) {
176 Assert.Fail ("#JW34 - " + ex.Message + Environment.NewLine + ex.StackTrace);
178 Assert.AreEqual ("Hello world!", TestAppOutput, "#JW33 - Application output");
182 File.Delete (NewProcInfo.FileName);
187 public void CreateGenerator ()
189 ICodeGenerator MyVBCodeGen;
190 MyVBCodeGen = _codeProvider.CreateGenerator ();
191 Assert.IsNotNull (MyVBCodeGen, "#JW40 - CreateGenerator");
192 Assert.IsTrue (MyVBCodeGen.Supports (GeneratorSupport.DeclareEnums), "#JW41");
197 // there's not yet an mbas for the 2.0 profile
198 [Category ("NotWorking")]
200 public void CompileFromFile_InMemory ()
202 // create vb source file
203 string sourceFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
204 using (FileStream f = new FileStream (sourceFile, FileMode.Create)) {
205 using (StreamWriter s = new StreamWriter (f)) {
206 s.Write (_sourceTest1);
212 CompilerParameters options = new CompilerParameters ();
213 options.GenerateExecutable = false;
214 options.GenerateInMemory = true;
215 options.TempFiles = new TempFileCollection (_tempDir);
217 options.EmbeddedResources.Add (sourceFile);
220 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
221 CompilerResults results = compiler.CompileAssemblyFromFile (options,
224 // verify compilation was successful
225 AssertCompileResults (results, true);
227 Assembly compiledAssembly = results.CompiledAssembly;
229 Assert.IsNotNull (compiledAssembly, "#1");
230 Assert.AreEqual (string.Empty, compiledAssembly.Location, "#2");
231 Assert.IsNull (results.PathToAssembly, "#3");
232 Assert.IsNotNull (compiledAssembly.GetType ("Test1"), "#4");
234 // verify we don't cleanup files in temp directory too agressively
235 string[] tempFiles = Directory.GetFiles (_tempDir);
236 Assert.AreEqual (1, tempFiles.Length, "#5");
237 Assert.AreEqual (sourceFile, tempFiles[0], "#6");
240 string[] resources = compiledAssembly.GetManifestResourceNames();
241 Assert.IsNotNull (resources, "#7");
242 Assert.AreEqual (1, resources.Length, "#8");
243 Assert.AreEqual ("file.vb", resources[0], "#9");
244 Assert.IsNull (compiledAssembly.GetFile ("file.vb"), "#10");
245 Assert.IsNotNull (compiledAssembly.GetManifestResourceStream ("file.vb"), "#11");
251 // there's not yet an mbas for the 2.0 profile
252 [Category ("NotWorking")]
254 public void CompileFromFileBatch_InMemory ()
256 // create vb source file
257 string sourceFile1 = Path.Combine (_tempDir, "file1." + _codeProvider.FileExtension);
258 using (FileStream f = new FileStream (sourceFile1, FileMode.Create)) {
259 using (StreamWriter s = new StreamWriter (f)) {
260 s.Write (_sourceTest1);
266 string sourceFile2 = Path.Combine (_tempDir, "file2." + _codeProvider.FileExtension);
267 using (FileStream f = new FileStream (sourceFile2, FileMode.Create)) {
268 using (StreamWriter s = new StreamWriter (f)) {
269 s.Write (_sourceTest2);
275 CompilerParameters options = new CompilerParameters ();
276 options.GenerateExecutable = false;
277 options.GenerateInMemory = true;
278 options.TempFiles = new TempFileCollection (_tempDir);
280 options.EmbeddedResources.Add (sourceFile1);
281 options.LinkedResources.Add (sourceFile2);
284 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
285 CompilerResults results = compiler.CompileAssemblyFromFileBatch (options,
286 new string[] { sourceFile1, sourceFile2 });
288 // verify compilation was successful
289 AssertCompileResults (results, true);
291 Assembly compiledAssembly = results.CompiledAssembly;
293 Assert.IsNotNull (compiledAssembly, "#1");
294 Assert.AreEqual (string.Empty, compiledAssembly.Location, "#2");
295 Assert.IsNull (results.PathToAssembly, "#3");
297 Assert.IsNotNull (compiledAssembly.GetType ("Test1"), "#4");
298 Assert.IsNotNull (compiledAssembly.GetType ("Test2"), "#5");
300 // verify we don't cleanup files in temp directory too agressively
301 string[] tempFiles = Directory.GetFiles (_tempDir);
302 Assert.AreEqual (2, tempFiles.Length, "#6");
303 Assert.IsTrue (File.Exists (sourceFile1), "#7");
304 Assert.IsTrue (File.Exists (sourceFile2), "#8");
307 string[] resources = compiledAssembly.GetManifestResourceNames();
308 Assert.IsNotNull (resources, "#9");
309 Assert.AreEqual (2, resources.Length, "#10");
311 Assert.AreEqual ("file1.vb", resources[0], "#A1");
312 Assert.IsNull (compiledAssembly.GetFile ("file1.vb"), "#A2");
313 Assert.IsNotNull (compiledAssembly.GetManifestResourceStream ("file1.vb"), "#A3");
314 ManifestResourceInfo info = compiledAssembly.GetManifestResourceInfo ("file1.vb");
315 Assert.IsNotNull (info, "#A4");
316 Assert.IsNull (info.FileName, "#A5");
317 Assert.IsNull (info.ReferencedAssembly, "#A6");
318 Assert.AreEqual ((ResourceLocation.Embedded | ResourceLocation.ContainedInManifestFile), info.ResourceLocation, "#A7");
320 Assert.AreEqual ("file2.vb", resources[1], "#B1");
322 compiledAssembly.GetFile ("file2.vb");
324 } catch (FileNotFoundException) {
327 compiledAssembly.GetManifestResourceStream ("file2.vb");
329 } catch (FileNotFoundException) {
331 info = compiledAssembly.GetManifestResourceInfo ("file2.vb");
332 Assert.IsNotNull (info, "#B4");
333 Assert.IsNotNull (info.FileName, "#B5");
334 Assert.AreEqual ("file2.vb", info.FileName, "#N6");
335 Assert.IsNull (info.ReferencedAssembly, "#B7");
336 Assert.AreEqual ((ResourceLocation) 0, info.ResourceLocation, "#B8");
342 // there's not yet an mbas for the 2.0 profile
343 [Category ("NotWorking")]
345 public void CompileFromSource_InMemory ()
347 // create a file in temp directory to ensure that compiler is not removing
348 // too much (temporary) files
349 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
350 using (FileStream fs = File.Create (tempFile)) {
354 CompilerParameters options = new CompilerParameters ();
355 options.GenerateExecutable = false;
356 options.GenerateInMemory = true;
357 options.TempFiles = new TempFileCollection (_tempDir);
359 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
360 CompilerResults results = compiler.CompileAssemblyFromSource (options,
363 // verify compilation was successful
364 AssertCompileResults (results, true);
366 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
367 Assert.IsNull (results.PathToAssembly, "#2");
368 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
370 // verify we don't cleanup files in temp directory too agressively
371 string[] tempFiles = Directory.GetFiles (_tempDir);
372 Assert.AreEqual (1, tempFiles.Length, "#4");
373 Assert.AreEqual (tempFile, tempFiles[0], "#5");
378 // there's not yet an mbas for the 2.0 profile
379 [Category ("NotWorking")]
381 public void CompileFromSourceBatch_InMemory ()
383 // create a file in temp directory to ensure that compiler is not removing
384 // too much (temporary) files
385 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
386 using (FileStream fs = File.Create (tempFile)) {
390 CompilerParameters options = new CompilerParameters ();
391 options.GenerateExecutable = false;
392 options.GenerateInMemory = true;
393 options.TempFiles = new TempFileCollection (_tempDir);
395 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
396 CompilerResults results = compiler.CompileAssemblyFromSourceBatch (options,
397 new string[] { _sourceTest1, _sourceTest2 });
399 // verify compilation was successful
400 AssertCompileResults (results, true);
402 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
403 Assert.IsNull (results.PathToAssembly, "#2");
405 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test1"), "#3");
406 Assert.IsNotNull (results.CompiledAssembly.GetType ("Test2"), "#4");
408 // verify we don't cleanup files in temp directory too agressively
409 string[] tempFiles = Directory.GetFiles (_tempDir);
410 Assert.AreEqual (1, tempFiles.Length, "#5");
411 Assert.AreEqual (tempFile, tempFiles[0], "#6");
416 // there's not yet an mbas for the 2.0 profile
417 [Category ("NotWorking")]
419 public void CompileFromDom_NotInMemory ()
421 // create a file in temp directory to ensure that compiler is not removing
422 // too much (temporary) files
423 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
424 using (FileStream fs = File.Create (tempFile)) {
428 // compile and verify result in separate appdomain to avoid file locks
429 AppDomain testDomain = CreateTestDomain ();
430 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
432 string outputAssembly = null;
435 outputAssembly = compileTester.CompileAssemblyFromDom (_tempDir);
437 AppDomain.Unload (testDomain);
440 // there should be two files in temp dir: temp file and output assembly
441 string[] tempFiles = Directory.GetFiles (_tempDir);
442 Assert.AreEqual (2, tempFiles.Length, "#1");
443 Assert.IsTrue (File.Exists (outputAssembly), "#2");
444 Assert.IsTrue (File.Exists (tempFile), "#3");
449 // there's not yet an mbas for the 2.0 profile
450 [Category ("NotWorking")]
452 public void CompileFromDomBatch_NotInMemory ()
454 // create a file in temp directory to ensure that compiler is not removing
455 // too much (temporary) files
456 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
457 using (FileStream fs = File.Create (tempFile)) {
461 // compile and verify result in separate appdomain to avoid file locks
462 AppDomain testDomain = CreateTestDomain ();
463 CrossDomainTester compileTester = CreateCrossDomainTester (testDomain);
465 string outputAssembly = null;
468 outputAssembly = compileTester.CompileAssemblyFromDomBatch (_tempDir);
470 AppDomain.Unload (testDomain);
473 // there should be two files in temp dir: temp file and output assembly
474 string[] tempFiles = Directory.GetFiles (_tempDir);
475 Assert.AreEqual (2, tempFiles.Length, "#1");
476 Assert.IsTrue (File.Exists (outputAssembly), "#2");
477 Assert.IsTrue (File.Exists (tempFile), "#3");
482 // there's not yet an mbas for the 2.0 profile
483 [Category ("NotWorking")]
485 public void CompileFromDom_InMemory ()
487 // create a file in temp directory to ensure that compiler is not removing
488 // too much (temporary) files
489 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
490 using (FileStream fs = File.Create (tempFile)) {
494 CompilerParameters options = new CompilerParameters ();
495 options.GenerateExecutable = false;
496 options.GenerateInMemory = true;
497 options.TempFiles = new TempFileCollection (_tempDir);
499 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
500 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
502 // verify compilation was successful
503 AssertCompileResults (results, true);
505 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
506 Assert.IsNull (results.PathToAssembly, "#2");
508 // verify we don't cleanup files in temp directory too agressively
509 string[] tempFiles = Directory.GetFiles (_tempDir);
510 Assert.AreEqual (1, tempFiles.Length, "#3");
511 Assert.AreEqual (tempFile, tempFiles[0], "#4");
516 // there's not yet an mbas for the 2.0 profile
517 [Category ("NotWorking")]
519 public void CompileFromDomBatch_InMemory ()
521 // create a file in temp directory to ensure that compiler is not removing
522 // too much (temporary) files
523 string tempFile = Path.Combine (_tempDir, "file." + _codeProvider.FileExtension);
524 using (FileStream fs = File.Create (tempFile)) {
528 CompilerParameters options = new CompilerParameters ();
529 options.GenerateExecutable = false;
530 options.GenerateInMemory = true;
531 options.TempFiles = new TempFileCollection (_tempDir);
533 ICodeCompiler compiler = _codeProvider.CreateCompiler ();
534 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options,
535 new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
537 // verify compilation was successful
538 AssertCompileResults (results, true);
540 Assert.AreEqual (string.Empty, results.CompiledAssembly.Location, "#1");
541 Assert.IsNull (results.PathToAssembly, "#2");
543 // verify we don't cleanup files in temp directory too agressively
544 string[] tempFiles = Directory.GetFiles (_tempDir);
545 Assert.AreEqual (1, tempFiles.Length, "#3");
546 Assert.AreEqual (tempFile, tempFiles[0], "#4");
550 public void CreateParser ()
552 //System.CodeDom.Compiler.ICodeParser CreateParser()
556 public void CreateObjRef ()
558 //System.Runtime.Remoting.ObjRef CreateObjRef(System.Type requestedType)
564 return OS == OsType.Windows;
571 return OS == OsType.Unix;
578 return OS == OsType.Mac;
582 private static string CreateTempDirectory ()
584 // create a uniquely named zero-byte file
585 string tempFile = Path.GetTempFileName ();
586 // remove the temporary file
587 File.Delete (tempFile);
588 // create a directory named after the unique temporary file
589 Directory.CreateDirectory (tempFile);
590 // return the path to the temporary directory
594 private static void RemoveDirectory (string path)
597 if (Directory.Exists (path)) {
598 string[] directoryNames = Directory.GetDirectories (path);
599 foreach (string directoryName in directoryNames) {
600 RemoveDirectory (directoryName);
602 string[] fileNames = Directory.GetFiles (path);
603 foreach (string fileName in fileNames) {
604 File.Delete (fileName);
606 Directory.Delete (path, true);
608 } catch (Exception ex) {
609 throw new AssertionException ("Unable to cleanup '" + path + "'.", ex);
613 private static void AssertCompileResults (CompilerResults results, bool allowWarnings)
615 foreach (CompilerError compilerError in results.Errors) {
616 if (allowWarnings && compilerError.IsWarning) {
620 Assert.Fail (compilerError.ToString ());
624 private static AppDomain CreateTestDomain ()
626 return AppDomain.CreateDomain ("CompileFromDom", AppDomain.CurrentDomain.Evidence,
627 AppDomain.CurrentDomain.SetupInformation);
630 private static CrossDomainTester CreateCrossDomainTester (AppDomain domain)
632 Type testerType = typeof (CrossDomainTester);
634 return (CrossDomainTester) domain.CreateInstanceAndUnwrap (
635 testerType.Assembly.FullName, testerType.FullName, false,
636 BindingFlags.Public | BindingFlags.Instance, null, new object[0],
637 CultureInfo.InvariantCulture, new object[0], domain.Evidence);
640 private class CrossDomainTester : MarshalByRefObject
642 public string CompileAssemblyFromDom (string tempDir)
644 CompilerParameters options = new CompilerParameters ();
645 options.GenerateExecutable = false;
646 options.GenerateInMemory = false;
647 options.TempFiles = new TempFileCollection (tempDir);
649 VBCodeProvider codeProvider = new VBCodeProvider ();
650 ICodeCompiler compiler = codeProvider.CreateCompiler ();
651 CompilerResults results = compiler.CompileAssemblyFromDom (options, new CodeCompileUnit ());
653 // verify compilation was successful
654 AssertCompileResults (results, true);
656 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
657 "Location should not be empty string");
658 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
660 return results.PathToAssembly;
663 public string CompileAssemblyFromDomBatch (string tempDir)
665 CompilerParameters options = new CompilerParameters ();
666 options.GenerateExecutable = false;
667 options.GenerateInMemory = false;
668 options.TempFiles = new TempFileCollection (tempDir);
670 VBCodeProvider codeProvider = new VBCodeProvider ();
671 ICodeCompiler compiler = codeProvider.CreateCompiler ();
672 CompilerResults results = compiler.CompileAssemblyFromDomBatch (options, new CodeCompileUnit[] { new CodeCompileUnit (), new CodeCompileUnit () });
674 // verify compilation was successful
675 AssertCompileResults (results, true);
677 Assert.IsTrue (results.CompiledAssembly.Location.Length != 0,
678 "Location should not be empty string");
679 Assert.IsNotNull (results.PathToAssembly, "PathToAssembly should not be null");
681 return results.PathToAssembly;