public void CompilingProcessTests_SignedAssembliesMustBeSigned() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace ExampleProject { public class Calculator { public int Subtract(int first, int second) { return first - second; } } }"); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = new ProjectAnalyzerResult(null, null) { Properties = new Dictionary <string, string>() { { "AssemblyTitle", "AssemblyName" }, }, Resources = new List <ResourceDescription>(), SignAssembly = true, AssemblyOriginatorKeyFile = Path.GetFullPath(Path.Combine("TestResources", "StrongNameKeyFile.snk")) }, TestProjectAnalyzerResult = new ProjectAnalyzerResult(null, null) { Properties = new Dictionary <string, string>() { { "AssemblyTitle", "AssemblyName" }, }, Resources = new List <ResourceDescription>() } }, AssemblyReferences = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, }; var rollbackProcessMock = new Mock <IRollbackProcess>(MockBehavior.Strict); var target = new CompilingProcess(input, rollbackProcessMock.Object); using (var ms = new MemoryStream()) { var result = target.Compile(new Collection <SyntaxTree>() { syntaxTree }, ms, false); result.Success.ShouldBe(true); var key = Assembly.Load(ms.ToArray()).GetName().GetPublicKey(); key.Length.ShouldBe(160, "Assembly was not signed"); ms.Length.ShouldBeGreaterThan(100, "No value was written to the MemoryStream by the compiler"); } }
public void CompilingProcessTests_MustIncludeVersionInfo() { var syntaxTree = CSharpSyntaxTree.ParseText(@"using System; namespace ExampleProject { public class Calculator { public int Subtract(int first, int second) { return first - second; } } }"); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = new ProjectAnalyzerResult(null, null) { Properties = new Dictionary <string, string>() { { "AssemblyTitle", "TargetFileName" }, { "TargetFileName", "TargetFileName.dll" }, }, Resources = new List <ResourceDescription>() }, TestProjectAnalyzerResults = new List <ProjectAnalyzerResult> { new ProjectAnalyzerResult(null, null) { Properties = new Dictionary <string, string>() { { "AssemblyTitle", "TargetFileName" }, }, Resources = new List <ResourceDescription>() } } }, AssemblyReferences = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) } }; var rollbackProcessMock = new Mock <IRollbackProcess>(MockBehavior.Strict); var target = new CompilingProcess(input, rollbackProcessMock.Object); using (var ms = new MemoryStream()) { var result = target.Compile(new Collection <SyntaxTree>() { syntaxTree }, ms, null, false); result.Success.ShouldBe(true); Assembly.Load(ms.ToArray()).GetName().Version.ToString().ShouldBe("0.0.0.0"); } }
public void CompilingProcessTests_ProperlyFailsWhenSigningKeyIsNotFound() { var syntaxTree = CSharpSyntaxTree.ParseText(@" namespace ExampleProject { public class Calculator { public int Subtract(int first, int second) { return first - second; } } }"); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = new ProjectAnalyzerResult(null, null) { ProjectFilePath = "project.csproj", Properties = new Dictionary <string, string>() { { "AssemblyTitle", "TargetFileName" }, { "TargetFileName", "TargetFileName.dll" }, { "SignAssembly", "true" }, { "AssemblyOriginatorKeyFile", Path.GetFullPath(Path.Combine("TestResources", "DoesNotExists.snk")) } }, Resources = new List <ResourceDescription>(), }, TestProjectAnalyzerResults = new List <ProjectAnalyzerResult> { new ProjectAnalyzerResult(null, null) { Properties = new Dictionary <string, string>() { { "AssemblyTitle", "TargetFileName" }, }, Resources = new List <ResourceDescription>() } } }, AssemblyReferences = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, }; var rollbackProcessMock = new Mock <IRollbackProcess>(MockBehavior.Strict); var target = new CompilingProcess(input, rollbackProcessMock.Object); using (var ms = new MemoryStream()) { Should.Throw <StrykerCompilationException>(() => target.Compile(new Collection <SyntaxTree>() { syntaxTree }, ms, null, false)); } }
public void CompilingProcessTests_ShouldCallRollbackProcess_OnCompileError() { var syntaxTree = CSharpSyntaxTree.ParseText(@"using System; namespace ExampleProject { public class Calculator { public int Subtract(string first, string second) { return first - second; } } }"); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "TargetDir", "" }, { "AssemblyName", "AssemblyName" }, { "TargetFileName", "TargetFileName.dll" }, }).Object, TestProjectAnalyzerResults = new List <IAnalyzerResult> { TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "AssemblyName", "TargetFileName" }, }).Object } }, AssemblyReferences = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) } }; var rollbackProcessMock = new Mock <IRollbackProcess>(MockBehavior.Strict); rollbackProcessMock.Setup(x => x.Start(It.IsAny <CSharpCompilation>(), It.IsAny <ImmutableArray <Diagnostic> >(), It.IsAny <bool>(), false)) .Returns((CSharpCompilation compilation, ImmutableArray <Diagnostic> diagnostics, bool devMode, bool _) => new RollbackProcessResult() { Compilation = compilation }); var target = new CompilingProcess(input, rollbackProcessMock.Object); using (var ms = new MemoryStream()) { Should.Throw <StrykerCompilationException>(() => target.Compile(new Collection <SyntaxTree>() { syntaxTree }, ms, null, false)); } rollbackProcessMock.Verify(x => x.Start(It.IsAny <CSharpCompilation>(), It.IsAny <ImmutableArray <Diagnostic> >(), false, false), Times.AtLeast(2)); }
public void CompilingProcessTests_ShouldOnlyRollbackErrors() { var syntaxTree = CSharpSyntaxTree.ParseText(@"using System; namespace ExampleProject { public class Calculator { public int Subtract(int first, int second) { return first - second; } } }"); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = new ProjectAnalyzerResult(null, null) { Properties = new Dictionary <string, string>() { { "AssemblyTitle", "TargetFileName" }, { "TargetFileName", "TargetFileName.dll" }, }, Resources = new List <ResourceDescription>() }, TestProjectAnalyzerResults = new List <ProjectAnalyzerResult> { new ProjectAnalyzerResult(null, null) { Properties = new Dictionary <string, string>() { { "AssemblyTitle", "TargetFileName" }, }, Resources = new List <ResourceDescription>() } } }, AssemblyReferences = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) } }; var rollbackProcessMock = new Mock <IRollbackProcess>(MockBehavior.Strict); var target = new CompilingProcess(input, rollbackProcessMock.Object); using (var ms = new MemoryStream()) { target.Compile(new Collection <SyntaxTree>() { syntaxTree }, ms, null, false); ms.Length.ShouldBeGreaterThan(100, "No value was written to the MemoryStream by the compiler"); } }
private void CompileMutations() { using var ms = new MemoryStream(); using var msForSymbols = _options.DevMode ? new MemoryStream() : null; // compile the mutated syntax trees var compileResult = _compilingProcess.Compile(_projectInfo.CompilationSyntaxTrees, ms, msForSymbols, _options.DevMode); foreach (var testProject in _input.ProjectInfo.TestProjectAnalyzerResults) { var injectionPath = _input.ProjectInfo.GetInjectionFilePath(testProject); if (!_fileSystem.Directory.Exists(Path.GetDirectoryName(injectionPath))) { _fileSystem.Directory.CreateDirectory(Path.GetDirectoryName(injectionPath)); } // inject the mutated Assembly into the test project using var fs = _fileSystem.File.Create(injectionPath); ms.Position = 0; ms.CopyTo(fs); if (msForSymbols != null) { // inject the debug symbols into the test project using var symbolDestination = _fileSystem.File.Create(Path.Combine(Path.GetDirectoryName(injectionPath), _input.ProjectInfo.ProjectUnderTestAnalyzerResult.GetSymbolFileName())); msForSymbols.Position = 0; msForSymbols.CopyTo(symbolDestination); } _logger.LogDebug("Injected the mutated assembly file into {0}", injectionPath); } // if a rollback took place, mark the rolled back mutants as status:BuildError if (compileResult.RollbackResult?.RollbackedIds.Any() ?? false) { foreach (var mutant in _projectInfo.Mutants .Where(x => compileResult.RollbackResult.RollbackedIds.Contains(x.Id))) { // Ignore compilation errors if the mutation is skipped anyways. if (mutant.ResultStatus == MutantStatus.Ignored) { continue; } mutant.ResultStatus = MutantStatus.CompileError; mutant.ResultStatusReason = "Mutant caused compile errors"; } } }
public void CompilingProcessTests_ShouldCallRollbackProcess_OnCompileError() { var syntaxTree = CSharpSyntaxTree.ParseText(@"using System; namespace ExampleProject { public class Calculator { public int Subtract(string first, string second) { return first - second; } } }"); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAssemblyName = "The assembly name" }, AssemblyReferences = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) } }; var rollbackProcessMock = new Mock <IRollbackProcess>(MockBehavior.Strict); rollbackProcessMock.Setup(x => x.Start(It.IsAny <CSharpCompilation>(), It.IsAny <ImmutableArray <Diagnostic> >(), It.IsAny <bool>())) .Returns((CSharpCompilation compilation, ImmutableArray <Diagnostic> diagnostics, bool devMode) => new RollbackProcessResult() { Compilation = compilation }); var target = new CompilingProcess(input, rollbackProcessMock.Object); using (var ms = new MemoryStream()) { Should.Throw <ApplicationException>(() => target.Compile(new Collection <SyntaxTree>() { syntaxTree }, ms, false)); } rollbackProcessMock.Verify(x => x.Start(It.IsAny <CSharpCompilation>(), It.IsAny <ImmutableArray <Diagnostic> >(), It.IsAny <bool>()), Times.Exactly(2)); }
public void CompilingProcessTests_ShouldCompile() { var syntaxTree = CSharpSyntaxTree.ParseText(@"using System; namespace ExampleProject { public class Calculator { public int Subtract(int first, int second) { return first - second; } } }"); var input = new MutationTestInput() { ProjectInfo = new Core.Initialisation.ProjectInfo() { ProjectUnderTestAssemblyName = "The assembly name" }, AssemblyReferences = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) } }; var rollbackProcessMock = new Mock <IRollbackProcess>(MockBehavior.Strict); var target = new CompilingProcess(input, rollbackProcessMock.Object); using (var ms = new MemoryStream()) { target.Compile(new Collection <SyntaxTree>() { syntaxTree }, ms, false); ms.Length.ShouldBeGreaterThan(100, "No value was written to the MemoryStream by the compiler"); } }
public void Mutate(StrykerOptions options) { var mutatedSyntaxTrees = new List <SyntaxTree>(); // add helper Logger.LogDebug("Injecting helpers into assembly."); mutatedSyntaxTrees.AddRange(CodeInjection.MutantHelpers); foreach (var file in Input.ProjectInfo.ProjectContents.GetAllFiles()) { // Get the syntax tree for the source file var syntaxTree = CSharpSyntaxTree.ParseText(file.SourceCode, path: file.FullPath, options: new CSharpParseOptions(LanguageVersion.Latest)); if (!file.IsExcluded) { // Mutate the syntax tree var mutatedSyntaxTree = Orchestrator.Mutate(syntaxTree.GetRoot()); // Add the mutated syntax tree for compilation mutatedSyntaxTrees.Add(mutatedSyntaxTree.SyntaxTree); // Store the generated mutants in the file file.Mutants = Orchestrator.GetLatestMutantBatch(); } else { // Add the original syntax tree for future compilation mutatedSyntaxTrees.Add(syntaxTree); // There aren't any mutants generated so a new list of mutants is sufficient file.Mutants = new List <Mutant>(); Logger.LogDebug("Excluded file {0}, no mutants created", file.FullPath); } } Logger.LogDebug("{0} mutants created", Input.ProjectInfo.ProjectContents.Mutants.Count()); using (var ms = new MemoryStream()) { // compile the mutated syntax trees var compileResult = CompilingProcess.Compile(mutatedSyntaxTrees, ms, options.DevMode); var injectionPath = Input.ProjectInfo.GetInjectionPath(); if (!FileSystem.Directory.Exists(Path.GetDirectoryName(injectionPath)) && !FileSystem.File.Exists(injectionPath)) { FileSystem.Directory.CreateDirectory(Path.GetDirectoryName(injectionPath)); } // inject the mutated Assembly into the test project using (var fs = FileSystem.File.Create(injectionPath)) { ms.Position = 0; ms.CopyTo(fs); } Logger.LogDebug("Injected the mutated assembly file into {0}", injectionPath); // if a rollback took place, mark the rollbacked mutants as status:BuildError if (compileResult.RollbackResult?.RollbackedIds.Any() ?? false) { foreach (var mutant in Input.ProjectInfo.ProjectContents.Mutants .Where(x => compileResult.RollbackResult.RollbackedIds.Contains(x.Id))) { mutant.ResultStatus = MutantStatus.CompileError; } } var numberOfBuildErrors = compileResult.RollbackResult?.RollbackedIds.Count() ?? 0; if (numberOfBuildErrors > 0) { Logger.LogInformation("{0} mutants could not compile and got status {1}", numberOfBuildErrors, MutantStatus.CompileError.ToString()); } if (options.ExcludedMutations.Count() != 0) { var mutantsToSkip = Input.ProjectInfo.ProjectContents.Mutants .Where(x => options.ExcludedMutations.Contains(x.Mutation.Type)).ToList(); foreach (var mutant in mutantsToSkip) { mutant.ResultStatus = MutantStatus.Skipped; } Logger.LogInformation("{0} mutants got status {1}", mutantsToSkip.Count(), MutantStatus.Skipped.ToString()); } } Logger.LogInformation("{0} mutants ready for test", Input.ProjectInfo.ProjectContents.TotalMutants.Count()); Reporter.OnMutantsCreated(Input.ProjectInfo.ProjectContents); }
public void ShouldRollbackIssueInExpression() { var syntaxTree = CSharpSyntaxTree.ParseText(@" using System; using System.Collections.Generic; using System.Linq; namespace ExampleProject { public class Test { public void SomeLinq() { var list = new List<List<double>>(); int[] listProjected = list.Select(l => l.Count()).ToArray(); } } }"); var mutator = new CsharpMutantOrchestrator(options: new StrykerOptions(mutationLevel: MutationLevel.Complete.ToString(), devMode: true)); var helpers = new List <SyntaxTree>(); foreach (var(name, code) in CodeInjection.MutantHelpers) { helpers.Add(CSharpSyntaxTree.ParseText(code, path: name, encoding: Encoding.UTF32)); } var mutant = mutator.Mutate(syntaxTree.GetRoot()); helpers.Add(mutant.SyntaxTree); var references = new List <PortableExecutableReference>() { MetadataReference.CreateFromFile(typeof(object).Assembly.Location), MetadataReference.CreateFromFile(typeof(List <string>).Assembly.Location), MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location), MetadataReference.CreateFromFile(typeof(PipeStream).Assembly.Location), }; Assembly.GetEntryAssembly().GetReferencedAssemblies().ToList().ForEach(a => references.Add(MetadataReference.CreateFromFile(Assembly.Load(a).Location))); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "TargetDir", "" }, { "AssemblyName", "AssemblyName" }, { "TargetFileName", "TargetFileName.dll" }, { "SignAssembly", "true" }, { "AssemblyOriginatorKeyFile", Path.GetFullPath(Path.Combine("TestResources", "StrongNameKeyFile.snk")) } }, projectFilePath: "TestResources").Object, TestProjectAnalyzerResults = new List <IAnalyzerResult> { TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "AssemblyName", "AssemblyName" }, }).Object } }, AssemblyReferences = references }; var rollbackProcess = new RollbackProcess(); var target = new CompilingProcess(input, rollbackProcess); using (var ms = new MemoryStream()) { var result = target.Compile(helpers, ms, null, true); result.RollbackResult.RollbackedIds.Count().ShouldBe(1); } }