public void ShouldGet50MutationScore() { var file = new CsharpFileLeaf() { RelativePath = "RootFolder/SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived }, new Mutant() { ResultStatus = MutantStatus.Killed }, } }; file.GetMutationScore().ShouldBe(0.5); var thresholdsDanger = new Thresholds { High = 80, Low = 60, Break = 0 }; file.CheckHealth(thresholdsDanger).ShouldBe(Health.Danger); var thresholdsWarning = new Thresholds { High = 80, Low = 50, Break = 0 }; file.CheckHealth(thresholdsWarning).ShouldBe(Health.Warning); var thresholdsGood = new Thresholds { High = 50, Low = 49, Break = 0 }; file.CheckHealth(thresholdsGood).ShouldBe(Health.Good); }
public void ShouldGet100MutationScore() { var file = new CsharpFileLeaf() { RelativePath = "RootFolder/SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Killed }, } }; file.GetMutationScore().ShouldBe(1); file.CheckHealth(new Threshold(high: 100, low: 50, @break: 0)).ShouldBe(Health.Good); }
public void ShouldNotFilterMutantsWhereCoveringTestsContainsChangedTestFile() { // Arrange string testProjectPath = "C:/MyTests"; var options = new StrykerOptions(); var baselineProvider = new Mock <IBaselineProvider>(); var diffProvider = new Mock <IDiffProvider>(MockBehavior.Loose); var branchProvider = new Mock <IGitInfoProvider>(); // If a file inside the test project is changed, a test has been changed string myTest = Path.Combine(testProjectPath, "myTest.cs");; diffProvider.Setup(x => x.ScanDiff()).Returns(new DiffResult() { ChangedSourceFiles = new Collection <string>() { myTest }, ChangedTestFiles = new Collection <string>() { myTest } }); var target = new DiffMutantFilter(options, diffProvider.Object, baselineProvider.Object, branchProvider.Object); // check the diff result for a file not inside the test project var file = new CsharpFileLeaf { FullPath = Path.Combine("C:/NotMyTests", "myfile.cs") }; var mutant = new Mutant(); mutant.CoveringTests.Add(new TestDescription(Guid.NewGuid().ToString(), "name", myTest)); // Act var filterResult = target.FilterMutants(new List <Mutant>() { mutant }, file.ToReadOnly(), options); // Assert filterResult.ShouldContain(mutant); }
public void ShouldNotUpdateMutantsWithBaselineIfFileNotInBaseline() { // Arrange var branchProvider = new Mock<IGitInfoProvider>(); var baselineProvider = new Mock<IBaselineProvider>(); var baselineMutantHelper = new Mock<IBaselineMutantHelper>(); var options = new StrykerOptions { WithBaseline = true, ProjectVersion = "version" }; var file = new CsharpFileLeaf { RelativePath = "foo.cs" }; var mutants = new List<Mutant> { new Mutant() }; var jsonMutants = new HashSet<JsonMutant> { new JsonMutant() }; // Setup Mocks var jsonFileComponents = new Dictionary<string, SourceFile>(); var baseline = new MockJsonReport(null, jsonFileComponents); baselineProvider.Setup(mock => mock.Load(It.IsAny<string>())).Returns(Task.FromResult((JsonReport)baseline)); // Act var target = new BaselineMutantFilter(options, baselineProvider.Object, branchProvider.Object, baselineMutantHelper.Object); var results = target.FilterMutants(mutants, file, options); // Assert results.ShouldHaveSingleItem(); }
public void ShouldGet0MutationScore() { var file = new CsharpFileLeaf() { RelativePath = "RootFolder/SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived }, } }; file.GetMutationScore().ShouldBe(0); file.CheckHealth(new Threshold(high: 80, low: 1, @break: 0)).ShouldBe(Health.Danger); file.CheckHealth(new Threshold(high: 80, low: 0, @break: 0)).ShouldBe(Health.Warning); }
public void BroadcastReporter_ShouldInvokeSameMethodWithSameObject_OnMutantTested() { var reporterMock = new Mock <IReporter>(MockBehavior.Strict); reporterMock.Setup(x => x.OnMutantTested(It.IsAny <Mutant>())); var exampleInputComponent = new CsharpFileLeaf(); var exampleMutant = new Mutant(); var reporters = new Collection <IReporter>() { reporterMock.Object }; var target = new BroadcastReporter(reporters); target.OnMutantTested(exampleMutant); reporterMock.Verify(x => x.OnMutantTested(exampleMutant), Times.Once); }
/// <summary> /// Recursively scans the given directory for files to mutate /// Deprecated method, should not be maintained /// </summary> private CsharpFolderComposite FindInputFiles(string path, string projectUnderTestDir, CSharpParseOptions cSharpParseOptions) { var folderComposite = new CsharpFolderComposite { FullPath = Path.GetFullPath(path), RelativePath = Path.GetRelativePath(projectUnderTestDir, Path.GetFullPath(path)) }; foreach (var folder in FileSystem.Directory.EnumerateDirectories(folderComposite.FullPath).Where(x => !_foldersToExclude.Contains(Path.GetFileName(x)))) { folderComposite.Add(FindInputFiles(folder, projectUnderTestDir, cSharpParseOptions)); } foreach (var file in FileSystem.Directory.GetFiles(folderComposite.FullPath, "*.cs", SearchOption.TopDirectoryOnly).Where(f => !f.EndsWith(".xaml.cs"))) { // Roslyn cannot compile xaml.cs files generated by xamarin. // Since the files are generated they should not be mutated anyway, so skip these files. var fileLeaf = new CsharpFileLeaf() { SourceCode = FileSystem.File.ReadAllText(file), FullPath = file, RelativePath = Path.GetRelativePath(projectUnderTestDir, file) }; // Get the syntax tree for the source file var syntaxTree = CSharpSyntaxTree.ParseText(fileLeaf.SourceCode, path: fileLeaf.FullPath, options: cSharpParseOptions); // don't mutate auto generated code if (syntaxTree.IsGenerated()) { _logger.LogDebug("Skipping auto-generated code file: {fileName}", fileLeaf.FullPath); folderComposite.AddCompilationSyntaxTree(syntaxTree); // Add the syntaxTree to the list of compilationSyntaxTrees continue; // Don't add the file to the folderComposite as we're not reporting on the file } fileLeaf.SyntaxTree = syntaxTree; folderComposite.Add(fileLeaf); } return(folderComposite); }
public void FilterMutants_should_filter_included_and_excluded_files( string[] patterns, string filePath, int spanStart, int spanEnd, bool shouldKeepFile) { // Arrange var options = new StrykerOptions() { Mutate = patterns.Select(FilePattern.Parse) }; var file = new CsharpFileLeaf { RelativePath = filePath, FullPath = Path.Combine("C:/test/", filePath) }; // Create token with the correct text span var syntaxToken = SyntaxFactory.Identifier( new SyntaxTriviaList(Enumerable.Range(0, spanStart).Select(x => SyntaxFactory.Space)), new string('a', spanEnd - spanStart), SyntaxTriviaList.Empty); var mutant = new Mutant { Mutation = new Mutation { OriginalNode = SyntaxFactory.IdentifierName(syntaxToken) } }; var sut = new FilePatternMutantFilter(options); // Act var result = sut.FilterMutants(new[] { mutant }, file, null); // Assert result.Contains(mutant).ShouldBe(shouldKeepFile); }
public void ShouldCallMutantOrchestratorAndReporter() { var inputFile = new CsharpFileLeaf() { SourceCode = SourceFile, SyntaxTree = CSharpSyntaxTree.ParseText(SourceFile) }; var folder = new CsharpFolderComposite(); folder.Add(inputFile); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "TargetDir", "/bin/Debug/netcoreapp2.1" }, { "TargetFileName", "TestName.dll" }, { "AssemblyName", "AssemblyName" }, { "Language", "C#" } }).Object, TestProjectAnalyzerResults = new List <IAnalyzerResult> { TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "TargetDir", "/bin/Debug/netcoreapp2.1" }, { "TargetFileName", "TestName.dll" }, { "AssemblyName", "AssemblyName" }, { "Language", "C#" } }).Object }, ProjectContents = folder }, AssemblyReferences = _assemblies }; var fileSystem = new MockFileSystem(new Dictionary <string, MockFileData> { { Path.Combine(FilesystemRoot, "ExampleProject", "Recursive.cs"), new MockFileData(SourceFile) }, { Path.Combine(FilesystemRoot, "ExampleProject.Test", "bin", "Debug", "netcoreapp2.0", "ExampleProject.dll"), new MockFileData("Bytecode") }, { Path.Combine(FilesystemRoot, "ExampleProject.Test", "obj", "Release", "netcoreapp2.0", "ExampleProject.dll"), new MockFileData("Bytecode") } }); var mutantToBeSkipped = new Mutant() { Mutation = new Mutation() }; var mockMutants = new Collection <Mutant>() { new Mutant() { Mutation = new Mutation() }, mutantToBeSkipped }; // create mocks var orchestratorMock = new Mock <MutantOrchestrator <SyntaxNode> >(MockBehavior.Strict); var reporterMock = new Mock <IReporter>(MockBehavior.Strict); var mutationTestExecutorMock = new Mock <IMutationTestExecutor>(MockBehavior.Strict); var coverageAnalyzerMock = new Mock <ICoverageAnalyser>(MockBehavior.Strict); // setup mocks orchestratorMock.Setup(x => x.GetLatestMutantBatch()).Returns(mockMutants); orchestratorMock.Setup(x => x.Mutate(It.IsAny <SyntaxNode>())).Returns(CSharpSyntaxTree.ParseText(SourceFile).GetRoot()); orchestratorMock.SetupAllProperties(); var options = new StrykerOptions(devMode: true, excludedMutations: new string[] { }, fileSystem: new MockFileSystem()); var target = new MutationTestProcess(input, reporterMock.Object, mutationTestExecutorMock.Object, orchestratorMock.Object, fileSystem, new BroadcastMutantFilter(Enumerable.Empty <IMutantFilter>()), coverageAnalyzerMock.Object, options); // start mutation process target.Mutate(); target.FilterMutants(); // verify the right methods were called orchestratorMock.Verify(x => x.Mutate(It.IsAny <SyntaxNode>()), Times.Once); }
public void FilterMutantsShouldCallMutantFilters() { var inputFile = new CsharpFileLeaf() { SourceCode = SourceFile, SyntaxTree = CSharpSyntaxTree.ParseText(SourceFile) }; var folder = new CsharpFolderComposite(); folder.Add(inputFile); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectUnderTestAnalyzerResult = TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "TargetDir", "/bin/Debug/netcoreapp2.1" }, { "TargetFileName", "TestName.dll" }, { "AssemblyName", "AssemblyName" }, { "Language", "C#" } }).Object, TestProjectAnalyzerResults = new List <IAnalyzerResult> { TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "TargetDir", "/bin/Debug/netcoreapp2.1" }, { "TargetFileName", "TestName.dll" }, { "AssemblyName", "AssemblyName" }, { "Language", "C#" } }).Object }, ProjectContents = folder }, AssemblyReferences = _assemblies }; var fileSystem = new MockFileSystem(new Dictionary <string, MockFileData> { { Path.Combine(FilesystemRoot, "ExampleProject", "Recursive.cs"), new MockFileData(SourceFile) }, { Path.Combine(FilesystemRoot, "ExampleProject.Test", "bin", "Debug", "netcoreapp2.0", "ExampleProject.dll"), new MockFileData("Bytecode") }, { Path.Combine(FilesystemRoot, "ExampleProject.Test", "obj", "Release", "netcoreapp2.0", "ExampleProject.dll"), new MockFileData("Bytecode") } }); var mutantToBeSkipped = new Mutant() { Mutation = new Mutation() }; var compileErrorMutant = new Mutant() { Mutation = new Mutation(), ResultStatus = MutantStatus.CompileError }; var mockMutants = new Collection <Mutant>() { new Mutant() { Mutation = new Mutation() }, mutantToBeSkipped, compileErrorMutant }; // create mocks var orchestratorMock = new Mock <MutantOrchestrator <SyntaxNode> >(MockBehavior.Strict); var reporterMock = new Mock <IReporter>(MockBehavior.Strict); var mutationTestExecutorMock = new Mock <IMutationTestExecutor>(MockBehavior.Strict); var mutantFilterMock = new Mock <IMutantFilter>(MockBehavior.Strict); var coverageAnalyzerMock = new Mock <ICoverageAnalyser>(MockBehavior.Strict); // setup mocks reporterMock.Setup(x => x.OnMutantsCreated(It.IsAny <ReadOnlyProjectComponent>())); orchestratorMock.Setup(x => x.GetLatestMutantBatch()).Returns(mockMutants); orchestratorMock.Setup(x => x.Mutate(It.IsAny <SyntaxNode>())).Returns(CSharpSyntaxTree.ParseText(SourceFile).GetRoot()); orchestratorMock.SetupAllProperties(); mutantFilterMock.SetupGet(x => x.DisplayName).Returns("Mock filter"); IEnumerable <Mutant> mutantsPassedToFilter = null; mutantFilterMock.Setup(x => x.FilterMutants(It.IsAny <IEnumerable <Mutant> >(), It.IsAny <ReadOnlyFileLeaf>(), It.IsAny <IStrykerOptions>())) .Callback <IEnumerable <Mutant>, ReadOnlyFileLeaf, IStrykerOptions>((mutants, _, __) => mutantsPassedToFilter = mutants) .Returns((IEnumerable <Mutant> mutants, ReadOnlyFileLeaf file, IStrykerOptions o) => mutants.Take(1)); var options = new StrykerOptions(devMode: true, excludedMutations: new string[] { }, fileSystem: new MockFileSystem()); var target = new MutationTestProcess(input, reporterMock.Object, mutationTestExecutorMock.Object, orchestratorMock.Object, fileSystem, new BroadcastMutantFilter(new[] { mutantFilterMock.Object }), coverageAnalyzerMock.Object, options); // start mutation process target.Mutate(); target.FilterMutants(); // verify that compiler error mutants are not passed to filter mutantsPassedToFilter.ShouldNotContain(compileErrorMutant); // verify that filtered mutants are skipped inputFile.Mutants.ShouldContain(mutantToBeSkipped); mutantToBeSkipped.ResultStatus.ShouldBe(MutantStatus.Ignored); }
private CsharpFolderComposite FindProjectFilesUsingBuildalyzer(IAnalyzerResult analyzerResult, IStrykerOptions options) { var inputFiles = new CsharpFolderComposite(); var projectUnderTestDir = Path.GetDirectoryName(analyzerResult.ProjectFilePath); var projectRoot = Path.GetDirectoryName(projectUnderTestDir); var generatedAssemblyInfo = analyzerResult.AssemblyAttributeFileName(); var rootFolderComposite = new CsharpFolderComposite() { Name = string.Empty, FullPath = projectRoot, RelativePath = string.Empty, RelativePathToProjectFile = Path.GetRelativePath(projectUnderTestDir, projectUnderTestDir) }; var cache = new Dictionary <string, CsharpFolderComposite> { [string.Empty] = rootFolderComposite }; // Save cache in a singleton so we can use it in other parts of the project FolderCompositeCache <CsharpFolderComposite> .Instance.Cache = cache; inputFiles.Add(rootFolderComposite); CSharpParseOptions cSharpParseOptions = BuildCsharpParseOptions(analyzerResult, options); InjectMutantHelpers(rootFolderComposite, cSharpParseOptions); foreach (var sourceFile in analyzerResult.SourceFiles) { // Skip xamarin UI generated files if (sourceFile.EndsWith(".xaml.cs")) { continue; } var relativePath = Path.GetRelativePath(projectUnderTestDir, sourceFile); var folderComposite = GetOrBuildFolderComposite(cache, Path.GetDirectoryName(relativePath), projectUnderTestDir, projectRoot, inputFiles); var fileName = Path.GetFileName(sourceFile); var file = new CsharpFileLeaf() { SourceCode = _fileSystem.File.ReadAllText(sourceFile), Name = _fileSystem.Path.GetFileName(sourceFile), RelativePath = _fileSystem.Path.Combine(folderComposite.RelativePath, fileName), FullPath = sourceFile, RelativePathToProjectFile = Path.GetRelativePath(projectUnderTestDir, sourceFile) }; // Get the syntax tree for the source file var syntaxTree = CSharpSyntaxTree.ParseText(file.SourceCode, path: file.FullPath, encoding: Encoding.UTF32, options: cSharpParseOptions); // don't mutate auto generated code if (syntaxTree.IsGenerated()) { // we found the generated assemblyinfo file if (_fileSystem.Path.GetFileName(sourceFile).ToLowerInvariant() == generatedAssemblyInfo) { // add the mutated text syntaxTree = InjectMutationLabel(syntaxTree); } _logger.LogDebug("Skipping auto-generated code file: {fileName}", file.Name); folderComposite.AddCompilationSyntaxTree(syntaxTree); // Add the syntaxTree to the list of compilationSyntaxTrees continue; // Don't add the file to the folderComposite as we're not reporting on the file } file.SyntaxTree = syntaxTree; folderComposite.Add(file); } return(inputFiles); }
public void FilterMutants_WhenMultipleMatchingMutants_ResultIsSetToNotRun() { // Arrange var branchProvider = new Mock<IGitInfoProvider>(); var baselineProvider = new Mock<IBaselineProvider>(); var baselineMutantHelper = new Mock<IBaselineMutantHelper>(); var options = new StrykerOptions() { WithBaseline = true, ProjectVersion = "version", }; var file = new CsharpFileLeaf { RelativePath = "foo.cs" }; var mutants = new List<Mutant> { new Mutant { ResultStatus = MutantStatus.NotRun }, new Mutant { ResultStatus = MutantStatus.NotRun } }; var jsonMutants = new HashSet<JsonMutant> { new JsonMutant { Status = "Killed" } }; // Setup Mocks var jsonReportFileComponent = new MockJsonReportFileComponent("", "", jsonMutants); var jsonFileComponents = new Dictionary<string, SourceFile> { ["foo.cs"] = jsonReportFileComponent }; var baseline = new MockJsonReport(null, jsonFileComponents); baselineProvider.Setup(mock => mock.Load(It.IsAny<string>())) .Returns(Task.FromResult(baseline as JsonReport)); baselineMutantHelper.Setup(mock => mock.GetMutantSourceCode(It.IsAny<string>(), It.IsAny<JsonMutant>())).Returns("var foo = \"bar\";"); baselineMutantHelper.Setup(mock => mock.GetMutantMatchingSourceCode( It.IsAny<IEnumerable<Mutant>>(), It.Is<JsonMutant>(m => m == jsonMutants.First()), It.Is<string>(source => source == "var foo = \"bar\";"))).Returns(mutants).Verifiable(); // Act var target = new BaselineMutantFilter(options, baselineProvider.Object, branchProvider.Object, baselineMutantHelper.Object); var results = target.FilterMutants(mutants, file, options); // Assert foreach(var result in results) { result.ResultStatus.ShouldBe(MutantStatus.NotRun); result.ResultStatusReason.ShouldBe("Result based on previous run was inconclusive"); } results.Count().ShouldBe(2); baselineMutantHelper.Verify(); }
private static IEnumerable <Mutant> MutateAndCompileSource(string sourceFile) { var filesystemRoot = Path.GetPathRoot(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); var inputFile = new CsharpFileLeaf() { SourceCode = sourceFile, SyntaxTree = CSharpSyntaxTree.ParseText(sourceFile) }; var folder = new CsharpFolderComposite(); folder.Add(inputFile); foreach (var(name, code) in CodeInjection.MutantHelpers) { folder.AddCompilationSyntaxTree(CSharpSyntaxTree.ParseText(code, path: name, encoding: Encoding.UTF32)); } var fileSystem = new MockFileSystem(new Dictionary <string, MockFileData> { { Path.Combine(filesystemRoot, "ExampleProject", "Calculator.cs"), new MockFileData(sourceFile) }, { Path.Combine(filesystemRoot, "ExampleProject.Test", "bin", "Debug", "netcoreapp2.0", "ExampleProject.dll"), new MockFileData("Bytecode") }, { Path.Combine(filesystemRoot, "ExampleProject.Test", "obj", "Release", "netcoreapp2.0", "ExampleProject.dll"), new MockFileData("Bytecode") } }); var input = new MutationTestInput { ProjectInfo = new ProjectInfo(fileSystem) { ProjectUnderTestAnalyzerResult = TestHelper.SetupProjectAnalyzerResult( properties: new Dictionary <string, string>() { { "TargetDir", "Project" }, { "AssemblyName", "AssemblyName" }, { "TargetFileName", "TargetFileName.dll" }, }).Object, TestProjectAnalyzerResults = new List <IAnalyzerResult> { TestHelper.SetupProjectAnalyzerResult(properties: new Dictionary <string, string>() { { "AssemblyName", "TargetFileName" }, { "TargetDir", "Test" }, { "TargetFileName", "TestTargetFileName.dll" }, }).Object }, ProjectContents = folder }, AssemblyReferences = new List <PortableExecutableReference> { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }, TestRunner = new Mock <ITestRunner>(MockBehavior.Default).Object }; var options = new StrykerOptions { MutationLevel = MutationLevel.Complete, OptimizationMode = OptimizationModes.CoverageBasedTest, }; var process = new CsharpMutationProcess(input, fileSystem, options); process.Mutate(); var projectContentsMutants = input.ProjectInfo.ProjectContents.Mutants; return(projectContentsMutants); }