public void ClearTextTreeReporter_ShouldPrintOnReportDone() { var textWriter = new StringWriter(); var target = new ClearTextTreeReporter(new StrykerOptions(), textWriter); var folder = new FolderComposite() { Name = "RootFolder", RelativePath = "RootFolder", FullPath = "C://RootFolder", }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", RelativePath = "RootFolder/SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { } }); target.OnAllMutantsTested(folder.ToReadOnly()); textWriter.RemoveAnsi().ShouldBeWithNewlineReplace($@" All mutants have been tested, and your mutation score has been calculated RootFolder [0/0 (N/A)] └── SomeFile.cs [0/0 (N/A)] "); textWriter.DarkGraySpanCount().ShouldBe(2); }
public void ReportComponent_ShouldCalculateMutationScore_BuildErrorIsNull() { var target = new FolderComposite() { Name = "RootFolder" }; var subFolder = new FolderComposite() { Name = "SubFolder" }; target.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.CompileError } } }); var result = target.GetMutationScore(); result.ShouldBe(null); }
private static void InjectMutantHelpers(FolderComposite rootFolderComposite, CSharpParseOptions cSharpParseOptions) { foreach (var(name, code) in CodeInjection.MutantHelpers) { rootFolderComposite.AddCompilationSyntaxTree(CSharpSyntaxTree.ParseText(code, path: name, encoding: Encoding.UTF32, options: cSharpParseOptions)); } }
private void MarkInputFilesAsExcluded(FolderComposite root, List <string> pathsToExclude, string projectUnderTestPath) { var allFiles = root.GetAllFiles().ToList(); foreach (var path in pathsToExclude) { var fullPath = path.StartsWith(projectUnderTestPath) ? path : Path.GetFullPath(projectUnderTestPath + path); if (!Path.HasExtension(path)) { _logger.LogDebug("Scanning dir {0} for files to exclude.", fullPath); } var filesToExclude = allFiles.Where(x => x.FullPath.StartsWith(fullPath)).ToList(); if (filesToExclude.Count() == 0) { _logger.LogWarning("No file to exclude was found for path {0}. Did you mean to exclude another file?", fullPath); } foreach (var file in filesToExclude) { _logger.LogDebug("File {0} will be excluded from mutation.", file.FullPath); file.IsExcluded = true; } } var excludedCount = allFiles.Where(x => x.IsExcluded).Count(); if (excludedCount > 0) { _logger.LogInformation("Your settings have excluded {0} files from mutation", excludedCount); } }
public void ConsoleReportReporter_ShouldPrintYellowBetweenThresholdLowAndThresholdBreak() { string output = ""; var chalkMock = new Mock <IChalk>(MockBehavior.Strict); chalkMock.Setup(x => x.Red(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Default(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Green(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Yellow(It.IsAny <string>())).Callback((string text) => { output += text; }); var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = MutatorType.Arithmetic }; var target = new ConsoleReportReporter(new StrykerOptions(), chalkMock.Object); var folder = new FolderComposite() { Name = "RootFolder" }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation } } }); target.OnAllMutantsTested(folder); chalkMock.Verify(x => x.Yellow(It.IsAny <string>()), Times.Exactly(2)); }
public void ReportComponent_ShouldCalculateMutationScore_OnlyKilledIsSuccessful(MutantStatus status, decimal expectedScore) { var target = new FolderComposite() { Name = "RootFolder" }; var subFolder = new FolderComposite() { Name = "SubFolder" }; target.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = status } } }); var result = target.GetMutationScore(); result.ShouldBe(expectedScore); }
public void Stryker_ShouldInvokeAllProcesses() { var projectOrchestratorMock = new Mock <IProjectOrchestrator>(MockBehavior.Strict); var mutationTestProcessMock = new Mock <IMutationTestProcess>(MockBehavior.Strict); var reporterFactoryMock = new Mock <IReporterFactory>(MockBehavior.Strict); var reporterMock = new Mock <IReporter>(MockBehavior.Strict); var fileSystemMock = new MockFileSystem(); var folder = new FolderComposite { Name = "ProjectRoot" }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", Mutants = new List <Mutant> { new Mutant { Id = 1 } } }); var mutationTestInput = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectContents = folder }, }; var options = new StrykerOptions(basePath: "c:/test", fileSystem: fileSystemMock); projectOrchestratorMock.Setup(x => x.MutateProjects(options, It.IsAny <IReporter>())) .Returns(new List <IMutationTestProcess>() { mutationTestProcessMock.Object }); reporterFactoryMock.Setup(x => x.Create(It.IsAny <StrykerOptions>(), It.IsAny <IGitInfoProvider>())).Returns(reporterMock.Object); reporterMock.Setup(x => x.OnMutantsCreated(It.IsAny <IReadOnlyProjectComponent>())); reporterMock.Setup(x => x.OnStartMutantTestRun(It.IsAny <IEnumerable <IReadOnlyMutant> >())); reporterMock.Setup(x => x.OnAllMutantsTested(It.IsAny <IReadOnlyProjectComponent>())); mutationTestProcessMock.SetupGet(x => x.Input).Returns(mutationTestInput); mutationTestProcessMock.Setup(x => x.GetCoverage()); mutationTestProcessMock.Setup(x => x.Test(It.IsAny <IEnumerable <Mutant> >())) .Returns(new StrykerRunResult(It.IsAny <StrykerOptions>(), It.IsAny <double>())); var target = new StrykerRunner(projectOrchestratorMock.Object, reporterFactory: reporterFactoryMock.Object); target.RunMutationTest(options); projectOrchestratorMock.Verify(x => x.MutateProjects(options, It.IsAny <IReporter>()), Times.Once); mutationTestProcessMock.Verify(x => x.GetCoverage(), Times.Once); mutationTestProcessMock.Verify(x => x.Test(It.IsAny <IEnumerable <Mutant> >()), Times.Once); reporterMock.Verify(x => x.OnMutantsCreated(It.IsAny <IReadOnlyProjectComponent>()), Times.Once); reporterMock.Verify(x => x.OnStartMutantTestRun(It.IsAny <IEnumerable <IReadOnlyMutant> >()), Times.Once); reporterMock.Verify(x => x.OnAllMutantsTested(It.IsAny <IReadOnlyProjectComponent>()), Times.Once); }
/// <summary> /// Finds the referencedProjects and looks for all files that should be mutated in those projects /// </summary> public ProjectInfo ResolveInput(string currentDirectory, string projectName) { var projectFile = ScanProjectFile(currentDirectory); var currentProjectInfo = ReadProjectFile(projectFile, projectName); var projectReferencePath = FilePathUtils.ConvertPathSeparators(currentProjectInfo.ProjectReference); var projectUnderTestPath = Path.GetDirectoryName(Path.GetFullPath(Path.Combine(currentDirectory, projectReferencePath))); var projectReference = Path.Combine(projectUnderTestPath, Path.GetFileName(projectReferencePath)); var projectFilePath = Path.GetFullPath(projectReference); var projectUnderTestInfo = FindProjectUnderTestAssemblyName(projectFilePath); var inputFiles = new FolderComposite(); foreach (var dir in ExtractProjectFolders(projectFilePath)) { var folder = _fileSystem.Path.Combine(Path.GetDirectoryName(projectFilePath), dir); _logger.LogDebug($"Scanning {folder}"); if (!_fileSystem.Directory.Exists(folder)) { throw new DirectoryNotFoundException($"Can't find {folder}"); } inputFiles.Add(FindInputFiles(folder)); } return(new ProjectInfo() { TestProjectPath = currentDirectory, TestProjectFileName = Path.GetFileName(projectFile), TargetFramework = currentProjectInfo.TargetFramework, ProjectContents = inputFiles, ProjectUnderTestPath = projectUnderTestPath, ProjectUnderTestAssemblyName = projectUnderTestInfo ?? Path.GetFileNameWithoutExtension(projectReferencePath), ProjectUnderTestProjectName = Path.GetFileNameWithoutExtension(projectReferencePath), }); }
public void ConsoleReportReporter_ShouldPrintOnReportDone() { string output = ""; var chalkMock = new Mock <IChalk>(MockBehavior.Strict); chalkMock.Setup(x => x.DarkGray(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Default(It.IsAny <string>())).Callback((string text) => { output += text; }); var target = new ConsoleReportReporter(new StrykerOptions(), chalkMock.Object); var folder = new FolderComposite() { Name = "RootFolder" }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", Mutants = new Collection <Mutant>() { } }); target.OnAllMutantsTested(folder); output.ToString().ShouldBeWithNewlineReplace($@" All mutants have been tested, and your mutation score has been calculated - {Path.DirectorySeparatorChar}RootFolder [0/0 (- %)] --- SomeFile.cs [0/0 (- %)] "); chalkMock.Verify(x => x.DarkGray(It.IsAny <string>()), Times.Exactly(2)); }
public void ReportComponent_ShouldCalculateMutationScore_TwoFolders() { var target = new FolderComposite() { Name = "RootFolder" }; target.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Killed } } }); target.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived } } }); var result = target.GetMutationScore(); result.ShouldBe(50M); }
public void InitialisationProcess_ShouldCallNeededResolvers() { var testRunnerMock = new Mock <ITestRunner>(MockBehavior.Strict); var inputFileResolverMock = new Mock <IInputFileResolver>(MockBehavior.Strict); var initialBuildProcessMock = new Mock <IInitialBuildProcess>(MockBehavior.Strict); var initialTestProcessMock = new Mock <IInitialTestProcess>(MockBehavior.Strict); var assemblyReferenceResolverMock = new Mock <IAssemblyReferenceResolver>(MockBehavior.Strict); testRunnerMock.Setup(x => x.RunAll(It.IsAny <int>(), null, null)) .Returns(new TestRunResult(true)); // testrun is successful testRunnerMock.Setup(x => x.DiscoverNumberOfTests()).Returns(999); testRunnerMock.Setup(x => x.Dispose()); var projectContents = new FolderComposite(); projectContents.Add(new FileLeaf { Name = "SomeFile.cs" }); var folder = new FolderComposite { Name = "ProjectRoot" }; folder.AddRange(new Collection <IProjectComponent> { new FileLeaf { Name = "SomeFile.cs" } }); inputFileResolverMock.Setup(x => x.ResolveInput(It.IsAny <IStrykerOptions>())) .Returns(new ProjectInfo { ProjectUnderTestAnalyzerResult = TestHelper.SetupProjectAnalyzerResult( references: new string[0]).Object, TestProjectAnalyzerResults = new List <IAnalyzerResult> { TestHelper.SetupProjectAnalyzerResult( projectFilePath: "C://Example/Dir/ProjectFolder").Object }, ProjectContents = folder }); initialTestProcessMock.Setup(x => x.InitialTest(It.IsAny <ITestRunner>())).Returns(999); initialBuildProcessMock.Setup(x => x.InitialBuild(It.IsAny <bool>(), It.IsAny <string>(), It.IsAny <string>())); assemblyReferenceResolverMock.Setup(x => x.LoadProjectReferences(It.IsAny <string[]>())) .Returns(Enumerable.Empty <PortableExecutableReference>()); var target = new InitialisationProcess( inputFileResolverMock.Object, initialBuildProcessMock.Object, initialTestProcessMock.Object, testRunnerMock.Object, assemblyReferenceResolverMock.Object); var options = new StrykerOptions(); var result = target.Initialize(options); inputFileResolverMock.Verify(x => x.ResolveInput(It.IsAny <IStrykerOptions>()), Times.Once); }
public void InitialisationProcess_ShouldThrowOnFailedInitialTestRun() { var testRunnerMock = new Mock <ITestRunner>(MockBehavior.Strict); var inputFileResolverMock = new Mock <IInputFileResolver>(MockBehavior.Strict); var initialBuildProcessMock = new Mock <IInitialBuildProcess>(MockBehavior.Strict); var initialTestProcessMock = new Mock <IInitialTestProcess>(MockBehavior.Strict); var assemblyReferenceResolverMock = new Mock <IAssemblyReferenceResolver>(MockBehavior.Strict); testRunnerMock.Setup(x => x.RunAll(It.IsAny <int>(), null, null)); var folder = new FolderComposite { Name = "ProjectRoot" }; folder.Add(new FileLeaf { Name = "SomeFile.cs" }); inputFileResolverMock.Setup(x => x.ResolveInput(It.IsAny <StrykerOptions>())).Returns( new ProjectInfo { ProjectUnderTestAnalyzerResult = new ProjectAnalyzerResult(null, null) { References = new string[0] }, TestProjectAnalyzerResults = new List <ProjectAnalyzerResult> { new ProjectAnalyzerResult(null, null) { ProjectFilePath = "C://Example/Dir/ProjectFolder" } }, ProjectContents = folder }); initialBuildProcessMock.Setup(x => x.InitialBuild(It.IsAny <bool>(), It.IsAny <string>(), It.IsAny <string>())); testRunnerMock.Setup(x => x.DiscoverNumberOfTests()).Returns(999); testRunnerMock.Setup(x => x.Dispose()); initialTestProcessMock.Setup(x => x.InitialTest(It.IsAny <ITestRunner>())).Throws(new StrykerInputException("")); // failing test assemblyReferenceResolverMock.Setup(x => x.LoadProjectReferences(It.IsAny <string[]>())) .Returns(Enumerable.Empty <PortableExecutableReference>()) .Verifiable(); var target = new InitialisationProcess( inputFileResolverMock.Object, initialBuildProcessMock.Object, initialTestProcessMock.Object, testRunnerMock.Object, assemblyReferenceResolverMock.Object); var options = new StrykerOptions(); target.Initialize(options); Assert.Throws <StrykerInputException>(() => target.InitialTest(options, out var nbTests)); inputFileResolverMock.Verify(x => x.ResolveInput(It.IsAny <StrykerOptions>()), Times.Once); assemblyReferenceResolverMock.Verify(); initialTestProcessMock.Verify(x => x.InitialTest(testRunnerMock.Object), Times.Once); }
public void ClearTextReporter_ShouldPrintYellowBetweenThresholdLowAndThresholdBreak() { var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = Mutator.Arithmetic }; var textWriter = new StringWriter(); var target = new ClearTextReporter(new StrykerOptions(thresholdHigh: 90, thresholdLow: 70, thresholdBreak: 0), textWriter); var folder = new FolderComposite() { Name = "RootFolder", RelativePath = "RootFolder", FullPath = "C://RootFolder", }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", RelativePath = "RootFolder/SomeFile.cs", RelativePathToProjectFile = "SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation }, new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation } } }); target.OnAllMutantsTested(folder.ToReadOnly()); textWriter.YellowSpanCount().ShouldBe(2); }
public void ClearTextReporter_ShouldPrintSurvivedMutation() { string output = ""; var chalkMock = new Mock <IChalk>(MockBehavior.Strict); chalkMock.Setup(x => x.Red(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Default(It.IsAny <string>())).Callback((string text) => { output += text; }); var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = Mutator.Arithmetic }; var target = new ClearTextReporter(new StrykerOptions(), chalkMock.Object); var folder = new FolderComposite() { Name = "RootFolder", RelativePath = "RootFolder", FullPath = "C://RootFolder", }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", RelativePath = "RootFolder/SomeFile.cs", RelativePathToProjectFile = "SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived, Mutation = mutation } } }); target.OnAllMutantsTested(folder); output.ShouldBeWithNewlineReplace($@" All mutants have been tested, and your mutation score has been calculated ┌─────────────┬──────────┬──────────┬───────────┬────────────┬──────────┬─────────┐ │ File │ % score │ # killed │ # timeout │ # survived │ # no cov │ # error │ ├─────────────┼──────────┼──────────┼───────────┼────────────┼──────────┼─────────┤ │ All files │ {0:N2} │ 0 │ 0 │ 1 │ 0 │ 0 │ │ SomeFile.cs │ {0:N2} │ 0 │ 0 │ 1 │ 0 │ 0 │ └─────────────┴──────────┴──────────┴───────────┴────────────┴──────────┴─────────┘ "); // All percentages should be red and the [Survived] too chalkMock.Verify(x => x.Red(It.IsAny <string>()), Times.Exactly(2)); }
public void ShouldStop_WhenAllMutationsWereIgnored() { var projectOrchestratorMock = new Mock <IProjectOrchestrator>(MockBehavior.Strict); var mutationTestProcessMock = new Mock <IMutationTestProcess>(MockBehavior.Strict); var reporterFactoryMock = new Mock <IReporterFactory>(MockBehavior.Strict); var reporterMock = new Mock <IReporter>(MockBehavior.Strict); var fileSystemMock = new MockFileSystem(); var folder = new FolderComposite() { Name = "ProjectRoot" }; folder.Add(new FileLeaf { Name = "SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { Id = 1, ResultStatus = MutantStatus.Ignored } } }); var mutationTestInput = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectContents = folder } }; var options = new StrykerOptions(basePath: "c:/test", fileSystem: fileSystemMock, coverageAnalysis: "off"); projectOrchestratorMock.Setup(x => x.MutateProjects(options, It.IsAny <IReporter>())) .Returns(new List <IMutationTestProcess>() { mutationTestProcessMock.Object }); mutationTestProcessMock.SetupGet(x => x.Input).Returns(mutationTestInput); reporterFactoryMock.Setup(x => x.Create(It.IsAny <StrykerOptions>(), It.IsAny <IGitInfoProvider>())).Returns(reporterMock.Object); reporterMock.Setup(x => x.OnMutantsCreated(It.IsAny <IReadOnlyProjectComponent>())); reporterMock.Setup(x => x.OnStartMutantTestRun(It.IsAny <IEnumerable <IReadOnlyMutant> >())); var target = new StrykerRunner(projectOrchestratorMock.Object, reporterFactory: reporterFactoryMock.Object); var result = target.RunMutationTest(options); result.MutationScore.ShouldBe(double.NaN); reporterMock.Verify(x => x.OnStartMutantTestRun(It.IsAny <IList <Mutant> >()), Times.Never); reporterMock.Verify(x => x.OnMutantTested(It.IsAny <Mutant>()), Times.Never); reporterMock.Verify(x => x.OnAllMutantsTested(It.IsAny <IReadOnlyProjectComponent>()), Times.Never); }
public void ClearTextTreeReporter_ShouldPrintKilledMutation() { string output = ""; var chalkMock = new Mock <IChalk>(MockBehavior.Strict); chalkMock.Setup(x => x.Green(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Default(It.IsAny <string>())).Callback((string text) => { output += text; }); var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = Mutator.Arithmetic }; var target = new ClearTextTreeReporter(new StrykerOptions(), chalkMock.Object); var folder = new FolderComposite() { Name = "RootFolder", RelativePath = "RootFolder", FullPath = "C://RootFolder", }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", RelativePath = "RootFolder/SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation } } }); target.OnAllMutantsTested(folder); output.ShouldBeWithNewlineReplace($@" All mutants have been tested, and your mutation score has been calculated RootFolder [1/1 ({1:P2})] └── SomeFile.cs [1/1 ({1:P2})] └── [Killed] This name should display on line 1 ├── [-] 0 + 8 └── [+] 0 -8 "); chalkMock.Verify(x => x.Green(It.IsAny <string>()), Times.Exactly(3)); }
/// <summary> /// Recursively scans the given directory for files to mutate /// </summary> private FolderComposite FindInputFiles(string path, string projectUnderTestDir, string parentFolder, CSharpParseOptions cSharpParseOptions) { var lastPathComponent = Path.GetFileName(path); var folderComposite = new FolderComposite { Name = lastPathComponent, FullPath = Path.GetFullPath(path), RelativePath = Path.Combine(parentFolder, lastPathComponent), RelativePathToProjectFile = 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, folderComposite.RelativePath, cSharpParseOptions)); } foreach (var file in _fileSystem.Directory.GetFiles(folderComposite.FullPath, "*.cs", SearchOption.TopDirectoryOnly)) { // Roslyn cannot compile xaml.cs files generated by xamarin. // Since the files are generated they should not be mutated anyway, so skip these files. if (!file.EndsWith(".xaml.cs")) { var fileName = Path.GetFileName(file); var fileLeaf = new FileLeaf() { SourceCode = _fileSystem.File.ReadAllText(file), Name = _fileSystem.Path.GetFileName(file), RelativePath = Path.Combine(folderComposite.RelativePath, fileName), FullPath = file, RelativePathToProjectFile = 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.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 } fileLeaf.SyntaxTree = syntaxTree; folderComposite.Add(fileLeaf); } } return(folderComposite); }
public void ShouldNotTest_WhenThereAreNoMutationsAtAll() { string basePath = Path.Combine(FilesystemRoot, "ExampleProject.Test"); var folder = new FolderComposite() { Name = "ProjectRoot" }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", Mutants = new Collection <Mutant>() { } }); var input = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectContents = folder }, AssemblyReferences = _assemblies }; var reporterMock = new Mock <IReporter>(MockBehavior.Strict); reporterMock.Setup(x => x.OnMutantTested(It.IsAny <Mutant>())); reporterMock.Setup(x => x.OnAllMutantsTested(It.IsAny <ReadOnlyProjectComponent>())); reporterMock.Setup(x => x.OnStartMutantTestRun(It.IsAny <IList <Mutant> >(), It.IsAny <IEnumerable <TestDescription> >())); var executorMock = new Mock <IMutationTestExecutor>(MockBehavior.Strict); executorMock.SetupGet(x => x.TestRunner).Returns(Mock.Of <ITestRunner>()); executorMock.Setup(x => x.Test(It.IsAny <IList <Mutant> >(), It.IsAny <int>(), It.IsAny <TestUpdateHandler>())); var mutantFilterMock = new Mock <IMutantFilter>(MockBehavior.Loose); var options = new StrykerOptions(fileSystem: new MockFileSystem(), basePath: basePath); var target = new MutationTestProcess(input, reporterMock.Object, executorMock.Object, mutantFilter: mutantFilterMock.Object, options: options); var testResult = target.Test(options); executorMock.Verify(x => x.Test(It.IsAny <IList <Mutant> >(), It.IsAny <int>(), It.IsAny <TestUpdateHandler>()), Times.Never); reporterMock.Verify(x => x.OnStartMutantTestRun(It.IsAny <IList <Mutant> >(), It.IsAny <IEnumerable <TestDescription> >()), Times.Never); reporterMock.Verify(x => x.OnMutantTested(It.IsAny <Mutant>()), Times.Never); reporterMock.Verify(x => x.OnAllMutantsTested(It.IsAny <ReadOnlyProjectComponent>()), Times.Never); testResult.MutationScore.ShouldBe(double.NaN); }
public void ClearTextReporter_ShouldPrintSurvivedMutation() { var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = Mutator.Arithmetic }; var textWriter = new StringWriter(); var target = new ClearTextReporter(new StrykerOptions(), textWriter); var folder = new FolderComposite() { Name = "RootFolder", RelativePath = "RootFolder", FullPath = "C://RootFolder", }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", RelativePath = "RootFolder/SomeFile.cs", RelativePathToProjectFile = "SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived, Mutation = mutation } } }); target.OnAllMutantsTested(folder.ToReadOnly()); textWriter.RemoveAnsi().ShouldBeWithNewlineReplace($@" All mutants have been tested, and your mutation score has been calculated ┌─────────────┬──────────┬──────────┬───────────┬────────────┬──────────┬─────────┐ │ File │ % score │ # killed │ # timeout │ # survived │ # no cov │ # error │ ├─────────────┼──────────┼──────────┼───────────┼────────────┼──────────┼─────────┤ │ All files │ {0:N2} │ 0 │ 0 │ 1 │ 0 │ 0 │ │ SomeFile.cs │ {0:N2} │ 0 │ 0 │ 1 │ 0 │ 0 │ └─────────────┴──────────┴──────────┴───────────┴────────────┴──────────┴─────────┘ "); // All percentages should be red and the [Survived] too textWriter.RedSpanCount().ShouldBe(2); }
public static IReadOnlyInputComponent CreateProjectWith(bool duplicateMutant = false, int mutationScore = 60) { var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = Mutator.Arithmetic }; var folder = new FolderComposite { Name = "RootFolder", RelativePath = "src" }; int mutantCount = 0; for (var i = 1; i <= 2; i++) { var addedFolder = new FolderComposite { Name = $"{i}", RelativePath = $"src/{i}" }; folder.Add(addedFolder); for (var y = 0; y <= 4; y++) { var m = new Collection <Mutant>(); addedFolder.Add(new FileLeaf() { Name = $"SomeFile{y}.cs", RelativePath = $"src/{i}/SomeFile{y}.cs", Mutants = m, SourceCode = "void M(){ int i = 0 + 8; }" }); for (var z = 0; z <= 5; z++) { m.Add(new Mutant() { Id = duplicateMutant ? 2 : ++mutantCount, ResultStatus = 100 / 6 * z < mutationScore ? MutantStatus.Killed : MutantStatus.Survived, Mutation = mutation, CoveringTest = new Dictionary <string, bool> { { mutantCount.ToString(), false } } }); } } } return(folder); }
public void Stryker_ShouldInvokeAllProcesses() { var initialisationMock = new Mock <IInitialisationProcess>(MockBehavior.Strict); var mutationTestProcessMock = new Mock <IMutationTestProcess>(MockBehavior.Strict); var fileSystemMock = new MockFileSystem(); var reporterMock = new Mock <IReporter>(MockBehavior.Loose); var folder = new FolderComposite() { Name = "ProjectRoot" }; var file = new FileLeaf() { Name = "SomeFile.cs", Mutants = new List <Mutant> { new Mutant { Id = 1 } } }; folder.Add(file); var mutationTestInput = new MutationTestInput() { ProjectInfo = new ProjectInfo() { ProjectContents = folder }, }; initialisationMock.Setup(x => x.Initialize(It.IsAny <StrykerOptions>())).Returns(mutationTestInput); var options = new StrykerOptions(basePath: "c:/test", fileSystem: fileSystemMock); var nbTests = 0; initialisationMock.Setup(x => x.InitialTest(options, out nbTests)).Returns(0); mutationTestProcessMock.Setup(x => x.Mutate()); mutationTestProcessMock.Setup(x => x.GetCoverage()); mutationTestProcessMock.Setup(x => x.FilterMutants()); mutationTestProcessMock.Setup(x => x.Test(It.IsAny <StrykerOptions>())) .Returns(new StrykerRunResult(It.IsAny <StrykerOptions>(), It.IsAny <double>())); var target = new StrykerRunner(initialisationMock.Object, mutationTestProcessMock.Object, reporter: reporterMock.Object); target.RunMutationTest(options); initialisationMock.Verify(x => x.Initialize(It.IsAny <StrykerOptions>()), Times.Once); mutationTestProcessMock.Verify(x => x.Mutate(), Times.Once); mutationTestProcessMock.Verify(x => x.Test(It.IsAny <StrykerOptions>()), Times.Once); }
public void ClearTextTreeReporter_ShouldPrintSurvivedMutation() { var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = Mutator.Arithmetic }; var textWriter = new StringWriter(); var target = new ClearTextTreeReporter(new StrykerOptions(), textWriter); var folder = new FolderComposite() { Name = "RootFolder", RelativePath = "RootFolder", FullPath = "C://RootFolder", }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", RelativePath = "RootFolder/SomeFile.cs", FullPath = "C://RootFolder/SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived, Mutation = mutation } } }); target.OnAllMutantsTested(folder); textWriter.RemoveAnsi().ShouldBeWithNewlineReplace($@" All mutants have been tested, and your mutation score has been calculated RootFolder [0/1 ({0:P2})] └── SomeFile.cs [0/1 ({0:P2})] └── [Survived] This name should display on line 1 ├── [-] 0 + 8 └── [+] 0 -8 "); // All percentages should be red and the [Survived] too textWriter.RedSpanCount().ShouldBe(3); }
public void ConsoleReportReporter_ShouldPrintSurvivedMutation() { string output = ""; var chalkMock = new Mock <IChalk>(MockBehavior.Strict); chalkMock.Setup(x => x.Red(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Default(It.IsAny <string>())).Callback((string text) => { output += text; }); var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = MutatorType.Arithmetic }; var target = new ConsoleReportReporter(new StrykerOptions(), chalkMock.Object); var folder = new FolderComposite() { Name = "RootFolder" }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived, Mutation = mutation } } }); target.OnAllMutantsTested(folder); output.ShouldBeWithNewlineReplace( $@" All mutants have been tested, and your mutation score has been calculated - {Path.DirectorySeparatorChar}RootFolder [0/1 (0.00 %)] --- SomeFile.cs [0/1 (0.00 %)] [Survived] This name should display on line 1: '0 + 8' ==> '0 -8' "); // All percentages should be red and the [Survived] too chalkMock.Verify(x => x.Red(It.IsAny <string>()), Times.Exactly(3)); }
public void RapportComponent_ShouldCalculateMutationScore_Recursive() { var target = new FolderComposite() { Name = "RootFolder" }; var subFolder = new FolderComposite() { Name = "SubFolder" }; target.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Killed } } }); target.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived } } }); target.Add(subFolder); subFolder.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Survived }, new Mutant() { ResultStatus = MutantStatus.Killed } } }); var result = target.GetMutationScore(); result.ShouldBe(0.5M); }
// get the FolderComposite object representing the the project's folder 'targetFolder'. Build the needed FolderComposite(s) for a complete path private FolderComposite GetOrBuildFolderComposite(IDictionary <string, FolderComposite> cache, string targetFolder, string projectUnderTestDir, string projectRoot, ProjectComponent inputFiles) { if (cache.ContainsKey(targetFolder)) { return(cache[targetFolder]); } var folder = targetFolder; FolderComposite subDir = null; while (!string.IsNullOrEmpty(folder)) { if (!cache.ContainsKey(folder)) { // we have not scanned this folder yet var sub = Path.GetFileName(folder); var fullPath = _fileSystem.Path.Combine(projectUnderTestDir, sub); var newComposite = new FolderComposite { Name = sub, FullPath = fullPath, RelativePath = Path.GetRelativePath(projectRoot, fullPath), RelativePathToProjectFile = Path.GetRelativePath(projectUnderTestDir, fullPath) }; if (subDir != null) { newComposite.Add(subDir); } cache.Add(folder, newComposite); subDir = newComposite; folder = Path.GetDirectoryName(folder); if (string.IsNullOrEmpty(folder)) { // we are at root inputFiles.Add(subDir); } } else { cache[folder].Add(subDir); break; } } return(cache[targetFolder]); }
private FolderComposite FindProjectFilesUsingBuildAlyzer(ProjectAnalyzerResult analyzerResult) { var inputFiles = new FolderComposite(); var projectUnderTestDir = Path.GetDirectoryName(analyzerResult.ProjectFilePath); var projectRoot = Path.GetDirectoryName(projectUnderTestDir); var generatedAssemblyInfo = (_fileSystem.Path.GetFileNameWithoutExtension(analyzerResult.ProjectFilePath) + ".AssemblyInfo.cs").ToLowerInvariant(); var rootFolderComposite = new FolderComposite() { Name = string.Empty, FullPath = projectRoot, RelativePath = string.Empty, RelativePathToProjectFile = Path.GetRelativePath(projectUnderTestDir, projectUnderTestDir) }; var cache = new Dictionary <string, FolderComposite> { [string.Empty] = rootFolderComposite }; inputFiles.Add(rootFolderComposite); foreach (var sourceFile in analyzerResult.SourceFiles) { if (sourceFile.EndsWith(".xaml.cs")) { continue; } if (_fileSystem.Path.GetFileName(sourceFile).ToLowerInvariant() == generatedAssemblyInfo) { continue; } var relativePath = Path.GetRelativePath(projectUnderTestDir, sourceFile); var folderComposite = GetOrBuildFolderComposite(cache, Path.GetDirectoryName(relativePath), projectUnderTestDir, projectRoot, inputFiles); var fileName = Path.GetFileName(sourceFile); folderComposite.Add(new FileLeaf() { SourceCode = _fileSystem.File.ReadAllText(sourceFile), Name = _fileSystem.Path.GetFileName(sourceFile), RelativePath = _fileSystem.Path.Combine(folderComposite.RelativePath, fileName), FullPath = sourceFile, RelativePathToProjectFile = Path.GetRelativePath(projectUnderTestDir, sourceFile) }); } return(inputFiles); }
/// <summary> /// In the case of multiple projects we wrap them inside a wrapper root component. Otherwise the only project root will be the root component. /// </summary> /// <param name="projectComponents">A list of all project root components</param> /// <param name="options">The current stryker options</param> /// <returns>The root folder component</returns> private IProjectComponent AddRootFolderIfMultiProject(IEnumerable <IProjectComponent> projectComponents, StrykerOptions options) { if (projectComponents.Count() > 1) { var rootComponent = new FolderComposite { FullPath = options.BasePath // in case of a solution run the basepath will be where the solution file is }; rootComponent.AddRange(projectComponents); return(rootComponent); } else { return(projectComponents.FirstOrDefault()); } }
public void ReportComponent_ShouldCalculateMutationScore_NoMutations() { var target = new FolderComposite() { Name = "RootFolder" }; target.Add(new FileLeaf() { Mutants = new Collection <Mutant>() { } }); var result = target.GetMutationScore(); result.ShouldBe(null); }
public void ConsoleReportReporter_ShouldGreenOn80PercentAndHigher() { string output = ""; var chalkMock = new Mock <IChalk>(MockBehavior.Strict); chalkMock.Setup(x => x.Default(It.IsAny <string>())).Callback((string text) => { output += text; }); chalkMock.Setup(x => x.Green(It.IsAny <string>())).Callback((string text) => { output += text; }); var tree = CSharpSyntaxTree.ParseText("void M(){ int i = 0 + 8; }"); var originalNode = tree.GetRoot().DescendantNodes().OfType <BinaryExpressionSyntax>().First(); var mutation = new Mutation() { OriginalNode = originalNode, ReplacementNode = SyntaxFactory.BinaryExpression(SyntaxKind.SubtractExpression, originalNode.Left, originalNode.Right), DisplayName = "This name should display", Type = "Not relevant" }; var target = new ConsoleReportReporter(new StrykerOptions("", "ReportOnly", "", 1000, "debug", false, 1, 80, 60, 0), chalkMock.Object); var folder = new FolderComposite() { Name = "RootFolder" }; folder.Add(new FileLeaf() { Name = "SomeFile.cs", Mutants = new Collection <Mutant>() { new Mutant() { ResultStatus = MutantStatus.Killed, Mutation = mutation }, } }); target.OnAllMutantsTested(folder); chalkMock.Verify(x => x.Green(It.IsAny <string>()), Times.Exactly(3)); }
/// <summary> /// Recursively scans the given directory for files to mutate /// </summary> private FolderComposite FindInputFiles(string path, string projectUnderTestDir, IAnalyzerResult analyzerResult, IStrykerOptions options) { var rootFolderComposite = new FolderComposite { Name = Path.GetFileName(path), FullPath = Path.GetFullPath(path), RelativePath = Path.GetFileName(path), RelativePathToProjectFile = Path.GetRelativePath(projectUnderTestDir, Path.GetFullPath(path)) }; CSharpParseOptions cSharpParseOptions = BuildCsharpParseOptions(analyzerResult, options); InjectMutantHelpers(rootFolderComposite, cSharpParseOptions); rootFolderComposite.Add( FindInputFiles(path, Path.GetDirectoryName(analyzerResult.ProjectFilePath), rootFolderComposite.RelativePath, cSharpParseOptions) ); return(rootFolderComposite); }