584 строки
24 KiB
C#
584 строки
24 KiB
C#
using System;
|
|
using System.CodeDom;
|
|
using System.CodeDom.Compiler;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
|
|
using Xunit;
|
|
|
|
namespace Microsoft.CodeDom.Providers.DotNetCompilerPlatformTest {
|
|
|
|
public class CommonCodeDomProviderTests {
|
|
|
|
private const int Failed = 1;
|
|
private const int Success = 0;
|
|
|
|
public void AssemblyVersion(CodeDomProvider provider)
|
|
{
|
|
var ver = provider.GetType().Assembly.GetName().Version;
|
|
|
|
Assert.Equal(4, ver.Major);
|
|
Assert.Equal(1, ver.Minor);
|
|
}
|
|
|
|
public void FileExtension(CodeDomProvider provider, string extension) {
|
|
Assert.Equal(extension, provider.FileExtension);
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_Parse_Error(CodeDomProvider provider) {
|
|
var result = provider.CompileAssemblyFromSource(
|
|
new CompilerParameters(),
|
|
// a ; is missing at the end of the return statement
|
|
"public class FooClass { public string Execute() { return \"output\" /*;*/ }}"
|
|
);
|
|
|
|
Assert.Equal(Failed, result.NativeCompilerReturnValue);
|
|
Assert.True(result.Errors.HasErrors);
|
|
Assert.Single(result.Errors);
|
|
Assert.Equal("CS1002", result.Errors[0].ErrorNumber);
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_WarningAsError(CodeDomProvider provider, string sourceCode, string errorNumber) {
|
|
var param = new CompilerParameters();
|
|
param.GenerateInMemory = true;
|
|
param.WarningLevel = 4;
|
|
param.TreatWarningsAsErrors = true;
|
|
param.CompilerOptions = "/warnaserror+";
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
sourceCode
|
|
);
|
|
|
|
Assert.Equal(Failed, result.NativeCompilerReturnValue);
|
|
Assert.True(result.Errors.HasErrors);
|
|
Assert.Equal(errorNumber, result.Errors[0].ErrorNumber);
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_ReferenceAssembly_AssemblyNameOnly(CodeDomProvider provider) {
|
|
var assemblyNames = new string[] { "mscorlib.dll" };
|
|
var param = new CompilerParameters(assemblyNames);
|
|
param.GenerateInMemory = true;
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
// the variable a is declared but not used
|
|
"public class FooClass { public string Execute() { return \"output\"; }}"
|
|
);
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
var type = result.CompiledAssembly.GetType("FooClass");
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
|
|
Assert.Null(result.PathToAssembly);
|
|
Assert.Equal(@"output", output);
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_ReferenceAssembly_NameCannotBeResolved(CodeDomProvider provider) {
|
|
// the referenced assembly below does not exist
|
|
string assemblyName = "mscorlib1.dll";
|
|
var assemblyNames = new string[] { assemblyName };
|
|
var param = new CompilerParameters(assemblyNames);
|
|
param.GenerateInMemory = true;
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
// the variable a is declared but not used
|
|
"public class FooClass { public string Execute() { int a; return \"output\"; }}"
|
|
);
|
|
|
|
// Assert.Null(result.PathToAssembly);
|
|
Assert.Equal(Failed, result.NativeCompilerReturnValue);
|
|
|
|
bool referenceErrorInOutput = false;
|
|
foreach (var line in result.Output) {
|
|
if (line.Contains("error") && line.Contains(assemblyName)) {
|
|
referenceErrorInOutput = true;
|
|
}
|
|
}
|
|
|
|
Assert.True(referenceErrorInOutput);
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_ReferenceAssembly_LocalReference(CodeDomProvider provider) {
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
Environment.CurrentDirectory = Path.GetTempPath();
|
|
var param1 = new CompilerParameters();
|
|
var result1 = provider.CompileAssemblyFromSource(
|
|
param1,
|
|
"public class FooClass1 { public static string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Success, result1.NativeCompilerReturnValue);
|
|
Assert.NotNull(result1.PathToAssembly);
|
|
tempFiles.Add(result1.PathToAssembly);
|
|
Assert.Equal(".dll", Path.GetExtension(result1.PathToAssembly));
|
|
|
|
string referenceName = Path.GetFileName(result1.PathToAssembly);
|
|
var asm1 = GetAssemblyByName(result1.PathToAssembly);
|
|
var type1 = asm1.GetType("FooClass1");
|
|
var obj1 = Activator.CreateInstance(type1);
|
|
var output1 = type1.GetMethod("Execute").Invoke(obj1, new object[] { });
|
|
|
|
Assert.Equal(@"output", output1);
|
|
|
|
var param2 = new CompilerParameters(new string[] { referenceName });
|
|
param2.GenerateExecutable = true;
|
|
var result2 = provider.CompileAssemblyFromSource(
|
|
param2,
|
|
"public class FooClass2 { public static void Main() { System.Console.Write(FooClass1.Execute());}}"
|
|
);
|
|
Assert.NotNull(result2.PathToAssembly);
|
|
tempFiles.Add(result2.PathToAssembly);
|
|
Assert.Equal(Success, result2.NativeCompilerReturnValue);
|
|
AppDomain newAppDomain = null;
|
|
try {
|
|
newAppDomain = System.AppDomain.CreateDomain("NewApplicationDomain");
|
|
newAppDomain.ExecuteAssembly(result2.PathToAssembly);
|
|
}
|
|
finally {
|
|
if (newAppDomain != null) {
|
|
AppDomain.Unload(newAppDomain);
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_ReferenceAssembly_PathWithComma(CodeDomProvider provider) {
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
Environment.CurrentDirectory = Path.GetTempPath();
|
|
var param1 = new CompilerParameters() {
|
|
OutputAssembly = string.Format("With,Comma{0}.dll", DateTime.UtcNow.Ticks.ToString())
|
|
};
|
|
|
|
var result1 = provider.CompileAssemblyFromSource(
|
|
param1,
|
|
"public class FooClass1 { public static string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Success, result1.NativeCompilerReturnValue);
|
|
Assert.NotNull(result1.PathToAssembly);
|
|
tempFiles.Add(result1.PathToAssembly);
|
|
Assert.Equal(".dll", Path.GetExtension(result1.PathToAssembly));
|
|
|
|
string referenceName = Path.GetFileName(result1.PathToAssembly);
|
|
var asm1 = GetAssemblyByName(result1.PathToAssembly);
|
|
var type1 = asm1.GetType("FooClass1");
|
|
var obj1 = Activator.CreateInstance(type1);
|
|
var output1 = type1.GetMethod("Execute").Invoke(obj1, new object[] { });
|
|
Assert.Equal(@"output", output1);
|
|
|
|
var param2 = new CompilerParameters(new string[] { referenceName });
|
|
param2.GenerateExecutable = true;
|
|
var result2 = provider.CompileAssemblyFromSource(
|
|
param2,
|
|
"public class FooClass2 { public static void Main() { System.Console.Write(FooClass1.Execute());}}"
|
|
);
|
|
|
|
Assert.Equal(Success, result2.NativeCompilerReturnValue);
|
|
Assert.NotNull(result2.PathToAssembly);
|
|
tempFiles.Add(result2.PathToAssembly);
|
|
AppDomain newAppDomain = null;
|
|
try {
|
|
newAppDomain = System.AppDomain.CreateDomain("NewApplicationDomain");
|
|
newAppDomain.ExecuteAssembly(result2.PathToAssembly);
|
|
}
|
|
finally {
|
|
if (newAppDomain != null) {
|
|
AppDomain.Unload(newAppDomain);
|
|
}
|
|
}
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_GenerateInMemory_True(CodeDomProvider provider) {
|
|
var result = provider.CompileAssemblyFromSource(
|
|
new CompilerParameters() {
|
|
GenerateInMemory = true
|
|
},
|
|
"using System.Runtime; public class FooClass { public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
var type = result.CompiledAssembly.GetType("FooClass");
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
|
|
Assert.Null(result.PathToAssembly);
|
|
Assert.Equal(@"output", output);
|
|
}
|
|
|
|
public void CompileAssemblyFromSource_GenerateInMemory_False(CodeDomProvider provider, string sourceCode) {
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
CompilerParameters param = new CompilerParameters();
|
|
param.OutputAssembly = Path.GetTempFileName() + ".dll";
|
|
tempFiles.Add(param.OutputAssembly);
|
|
param.GenerateInMemory = false;
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
sourceCode
|
|
);
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
Assert.NotNull(result.PathToAssembly);
|
|
|
|
// Read assembly into memory:
|
|
Assembly asm = GetAssemblyByName(result.PathToAssembly);
|
|
|
|
var type = asm.GetType("FooClass");
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
|
|
|
|
Assert.Equal(@"output", output);
|
|
Assert.Equal(param.OutputAssembly, result.PathToAssembly);
|
|
|
|
Assert.True(File.Exists(param.OutputAssembly));
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_InvalidOutputPath(CodeDomProvider provider) {
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
CompilerParameters param = new CompilerParameters();
|
|
param.OutputAssembly = Path.Combine(Path.GetTempPath(), @"inva\l*d?path,someName,public");
|
|
tempFiles.Add(param.OutputAssembly);
|
|
param.GenerateInMemory = false;
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
"public class FooClass { public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
// Assert.Null(result.PathToAssembly);
|
|
Assert.Equal(Failed, result.NativeCompilerReturnValue);
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_GenerateExecutable_True(CodeDomProvider provider) {
|
|
Environment.CurrentDirectory = Path.GetTempPath();
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
var param = new CompilerParameters() {
|
|
GenerateExecutable = true,
|
|
MainClass = "FooClass"
|
|
};
|
|
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
"public class FooClass { public static void Main(){} public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
Assert.NotNull(result.PathToAssembly);
|
|
tempFiles.Add(result.PathToAssembly);
|
|
Assembly asm = GetAssemblyByName(result.PathToAssembly);
|
|
|
|
var type = asm.GetType("FooClass");
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
|
|
|
|
Assert.Equal(".exe", Path.GetExtension(result.PathToAssembly));
|
|
Assert.Equal(@"output", output);
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_GenerateExecutable_True_Failed(CodeDomProvider provider) {
|
|
Environment.CurrentDirectory = Path.GetTempPath();
|
|
var param = new CompilerParameters() {
|
|
GenerateInMemory = false,
|
|
GenerateExecutable = true,
|
|
IncludeDebugInformation = true,
|
|
};
|
|
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
// The source does not contain Main() method.
|
|
"public class FooClass {public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Failed, result.NativeCompilerReturnValue);
|
|
// Assert.Null(result.PathToAssembly);
|
|
Assert.Equal("CS5001"/*miss main entry*/, result.Errors[0].ErrorNumber);
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_CreateOutputFileFailed(CodeDomProvider provider) {
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
CompilerParameters param = new CompilerParameters();
|
|
param.OutputAssembly = Path.GetTempFileName();
|
|
tempFiles.Add(param.OutputAssembly);
|
|
using (var conflictFile = File.Open(param.OutputAssembly, FileMode.Open)) {
|
|
param.GenerateInMemory = false;
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
"public class FooClass { public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Failed, result.NativeCompilerReturnValue);
|
|
// The InProc provider does not give error while the old provider
|
|
// does. We probably should fix the behavior of InProc provider.
|
|
// Assert.False(result.Errors.HasErrors);
|
|
bool filenameInOutput = false;
|
|
foreach (var line in result.Output) {
|
|
if (line.Contains(Path.GetFileName(param.OutputAssembly))) {
|
|
filenameInOutput = true;
|
|
}
|
|
}
|
|
|
|
Assert.True(filenameInOutput);
|
|
}
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_CreatePDBFileFailed(CodeDomProvider provider) {
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
CompilerParameters param = new CompilerParameters();
|
|
param.OutputAssembly = Path.GetTempFileName();
|
|
tempFiles.Add(param.OutputAssembly);
|
|
param.IncludeDebugInformation = true;
|
|
string pdbFilename = Path.ChangeExtension(param.OutputAssembly, ".pdb");
|
|
tempFiles.Add(pdbFilename);
|
|
using (var conflictFile = File.Create(pdbFilename)) {
|
|
param.GenerateInMemory = false;
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
"public class FooClass { public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Failed, result.NativeCompilerReturnValue);
|
|
// The InProc provider does not give error while the old provider
|
|
// does. We probably should fix the behavior of InProc provider.
|
|
// Assert.False(result.Errors.HasErrors);
|
|
bool filenameInOutput = false;
|
|
foreach (var line in result.Output) {
|
|
if (line.Contains(Path.GetFileName(pdbFilename))) {
|
|
filenameInOutput = true;
|
|
}
|
|
}
|
|
|
|
Assert.True(filenameInOutput);
|
|
}
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_IncludeDebugInformation_True(CodeDomProvider provider) {
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
CompilerParameters param = new CompilerParameters();
|
|
param.OutputAssembly = Path.GetTempFileName();
|
|
tempFiles.Add(param.OutputAssembly);
|
|
param.IncludeDebugInformation = true;
|
|
param.GenerateInMemory = false;
|
|
string pdbFileName = Path.ChangeExtension(param.OutputAssembly, ".pdb");
|
|
tempFiles.Add(pdbFileName);
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
"public class FooClass { public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
|
|
// In Debug mode, visual studio would try to load the pdb file.
|
|
// Delete the file before it's held by VS.
|
|
Assert.True(File.Exists(pdbFileName));
|
|
File.Delete(pdbFileName);
|
|
|
|
// Read assembly into memory:
|
|
Assembly asm = GetAssemblyByName(param.OutputAssembly);
|
|
var type = asm.GetType("FooClass");
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
|
|
|
|
Assert.Equal(@"output", output);
|
|
Assert.Equal(param.OutputAssembly, result.PathToAssembly);
|
|
Assert.True(File.Exists(param.OutputAssembly));
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromSource_IncludeDebugInformation_False(CodeDomProvider provider) {
|
|
|
|
List<string> tempFiles = new List<string>();
|
|
try {
|
|
CompilerParameters param = new CompilerParameters();
|
|
param.OutputAssembly = Path.GetTempFileName();
|
|
tempFiles.Add(param.OutputAssembly);
|
|
param.IncludeDebugInformation = false;
|
|
param.GenerateInMemory = false;
|
|
string pdbFileName = Path.ChangeExtension(param.OutputAssembly, ".pdb");
|
|
var result = provider.CompileAssemblyFromSource(
|
|
param,
|
|
"public class FooClass { public string Execute() { return \"output\";}}"
|
|
);
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
|
|
// Read assembly into memory:
|
|
Assembly asm = GetAssemblyByName(param.OutputAssembly);
|
|
var type = asm.GetType("FooClass");
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
|
|
|
|
Assert.Equal(@"output", output);
|
|
Assert.Equal(param.OutputAssembly, result.PathToAssembly);
|
|
Assert.True(File.Exists(param.OutputAssembly));
|
|
Assert.False(File.Exists(pdbFileName));
|
|
}
|
|
finally {
|
|
DeleteFiles(tempFiles);
|
|
}
|
|
|
|
}
|
|
|
|
public void CompileAssemblyFromDom(CodeDomProvider provider) {
|
|
string spaceName = "TestNameSpace";
|
|
string className = "FooClass";
|
|
string methodName = "Execute";
|
|
|
|
CodeCompileUnit compileUnit = new CodeCompileUnit();
|
|
CodeNamespace testNameSpace = new CodeNamespace(spaceName);
|
|
compileUnit.Namespaces.Add(testNameSpace);
|
|
|
|
// Declare a new type called fooClass.
|
|
CodeTypeDeclaration fooClass = new CodeTypeDeclaration(className);
|
|
fooClass.Attributes = MemberAttributes.Public;
|
|
|
|
// Add the new type to the namespace type collection.
|
|
testNameSpace.Types.Add(fooClass);
|
|
|
|
CodeMemberMethod method = new CodeMemberMethod();
|
|
method.Name = methodName;
|
|
method.Attributes = MemberAttributes.Public;
|
|
method.ReturnType = new CodeTypeReference(typeof(System.String));
|
|
|
|
CodeMethodReturnStatement returnStatement = new CodeMethodReturnStatement();
|
|
returnStatement.Expression = new CodePrimitiveExpression("output");
|
|
method.Statements.Add(returnStatement);
|
|
|
|
fooClass.Members.Add(method);
|
|
var result = provider.CompileAssemblyFromDom(
|
|
new CompilerParameters() {
|
|
GenerateInMemory = true
|
|
},
|
|
compileUnit
|
|
);
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
var type = result.CompiledAssembly.GetType(string.Format("{0}.{1}", spaceName, className));
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod(methodName).Invoke(obj, new object[] { });
|
|
Assert.Equal("output", output);
|
|
}
|
|
|
|
|
|
public void CompileAssemblyFromFile(CodeDomProvider provider)
|
|
{
|
|
CompileAssemblyFromFile_CheckArgs(provider, null, false);
|
|
}
|
|
|
|
public void CompileAssemblyFromFile_CheckArgs(CodeDomProvider provider, string argStringToFind, bool expected) {
|
|
var sourcePath = Path.Combine(Path.GetTempPath(), "foobarSourcefile.cs");
|
|
try {
|
|
using (var sourceStream = File.Create(sourcePath)) {
|
|
var content = "public class FooClass { public string Execute() { return \"output\";}}";
|
|
// If we're checking cmd args, we actually want to fail compilation so we can examine output.
|
|
if (argStringToFind != null)
|
|
content = "nonsense that doesn't compile.";
|
|
var bytes = Encoding.ASCII.GetBytes(content);
|
|
sourceStream.Write(bytes, 0, bytes.Length);
|
|
}
|
|
|
|
var result = provider.CompileAssemblyFromFile(
|
|
new CompilerParameters() {
|
|
GenerateInMemory = true
|
|
},
|
|
sourcePath
|
|
);
|
|
|
|
if (argStringToFind != null)
|
|
{
|
|
Assert.NotEqual(Success, result.NativeCompilerReturnValue);
|
|
Assert.Equal(expected, result.Output[0].Contains(argStringToFind));
|
|
return;
|
|
}
|
|
|
|
Assert.Equal(Success, result.NativeCompilerReturnValue);
|
|
var type = result.CompiledAssembly.GetType("FooClass");
|
|
var obj = Activator.CreateInstance(type);
|
|
var output = type.GetMethod("Execute").Invoke(obj, new object[] { });
|
|
Assert.Equal(@"output", output);
|
|
}
|
|
finally {
|
|
File.Delete(sourcePath);
|
|
}
|
|
|
|
}
|
|
|
|
private static Assembly GetAssemblyByName(string name) {
|
|
byte[] assemblyBuff = File.ReadAllBytes(name);
|
|
Assembly asm = Assembly.Load(assemblyBuff);
|
|
return asm;
|
|
}
|
|
|
|
private static void DeleteFiles(List<string> tempFiles) {
|
|
Exception error = null;
|
|
foreach (var file in tempFiles) {
|
|
try {
|
|
File.Delete(file);
|
|
}
|
|
catch (IOException e) {
|
|
error = e;
|
|
}
|
|
catch (UnauthorizedAccessException e) {
|
|
error = e;
|
|
}
|
|
catch {
|
|
|
|
}
|
|
}
|
|
|
|
if (error != null) {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
}
|