public void OnAllMutantsTested(IReadOnlyInputComponent inputComponent) { // setup display handlers inputComponent.DisplayFolder = (int depth, IReadOnlyInputComponent current) => { // show depth _chalk.Default($"{new string('-', depth)} {Path.DirectorySeparatorChar}{Path.GetFileName(current.Name)} "); DisplayComponent(current); }; inputComponent.DisplayFile = (int depth, IReadOnlyInputComponent current) => { // show depth _chalk.Default($"{new string('-', depth)} {current.Name} "); DisplayComponent(current); foreach (var mutant in current.TotalMutants) { if (mutant.ResultStatus == MutantStatus.Killed || mutant.ResultStatus == MutantStatus.Timeout) { _chalk.Green($"[{mutant.ResultStatus}] "); } else { _chalk.Red($"[{mutant.ResultStatus}] "); } _chalk.Default($"{mutant.Mutation.DisplayName} on line {mutant.Mutation.OriginalNode.GetLocation().GetLineSpan().StartLinePosition.Line + 1}: '{mutant.Mutation.OriginalNode}' ==> '{mutant.Mutation.ReplacementNode}'{Environment.NewLine}"); } }; // print empty line for readability _chalk.Default($"{Environment.NewLine}{Environment.NewLine}All mutants have been tested, and your mutation score has been calculated{Environment.NewLine}"); // start recursive invocation of handlers inputComponent.Display(1); }
private void MutantAnalyzerOnMutantExecuted(object sender, CppMutantEventArgs e) { lock (Sync) { var mutant = e.Mutant; var lineNumber = mutant.Mutation.LineNumber; var status = $"{Environment.NewLine}Line: {lineNumber} - {mutant.ResultStatus.ToString()} - {mutant.Mutation.DisplayName}".PrintWithDateTimeSimple(); if (mutant.ResultStatus == MutantStatus.Survived) { _chalk.Yellow($"{status}{Environment.NewLine}"); } else if (mutant.ResultStatus == MutantStatus.BuildError) { _chalk.Red($"{status}{Environment.NewLine}"); } else if (mutant.ResultStatus == MutantStatus.Timeout) { _chalk.Cyan($"{status}{Environment.NewLine}"); } else { _chalk.Green($"{status}{Environment.NewLine}"); } if (_options.EnableDiagnostics) { _chalk.Red($"{e.BuildLog.ConvertToPlainText()}{Environment.NewLine}"); _chalk.Red($"{e.TestLog.ConvertToPlainText()}{Environment.NewLine}"); } _mutantProgress++; UpdateProgress(); } }
private async Task ExecuteTests(SourceClassDetail source) { _chalk.Default("\nExecuting Tests..."); var log = new StringBuilder(); void OutputData(object sender, string args) => log.AppendLine(args); var testExecutor = new TestExecutor(_settings, source.TestClaz.ClassLibrary) { X64TargetPlatform = X64TargetPlatform, FullyQualifiedName = source.TestClaz.MethodDetails.Count > _useClassFilterTestsThreshold || UseClassFilter || source.TestClaz.BaseClass != null ? source.TestClaz.Claz.Syntax.FullName() : string.Empty, EnableCustomOptions = true, EnableLogging = true }; testExecutor.OutputDataReceived += OutputData; testExecutor.BeforeTestExecuted += (sender, args) => { _chalk.Yellow($"\nRunning VSTest.Console with {args}\n"); }; await testExecutor.ExecuteTests(source.TestClaz.MethodDetails.ToList()); source.NumberOfTests = Convert.ToInt32(testExecutor.TestResult?.ResultSummary?.Counters?.Total); _chalk.Yellow($"\nNumber of Tests: {source.NumberOfTests}\n"); if (testExecutor.LastTestExecutionStatus != Constants.TestExecutionStatus.Success) { throw new MuTestFailingTestException(log.ToString()); } if (!NoCoverage) { _chalk.Green("\nCalculating Code Coverage..."); if (testExecutor.CodeCoverage != null) { var coverage = new CoverageAnalyzer(); coverage.FindCoverage(source, testExecutor.CodeCoverage); } if (source.Coverage != null) { var coveredLines = source.Coverage.LinesCovered; var totalLines = source.Coverage.TotalLines; _chalk.Yellow( $"\nCode Coverage for Class {Path.GetFileName(source.FilePath)} is {decimal.Divide(coveredLines, totalLines):P} ({coveredLines}/{totalLines})\n"); } } testExecutor.OutputDataReceived -= OutputData; }
public void OnAllMutantsTested(IReadOnlyInputComponent mutationTree) { var mutationReport = JsonReport.Build(_options, mutationTree); var reportPath = Path.Combine(_options.OutputPath, "reports", "mutation-report.json"); WriteReportToJsonFile(reportPath, mutationReport.ToJson()); _chalk.Green($"\nYour json report has been generated at: \n " + $"{reportPath} \n"); }
public void OnAllMutantsTested(IReadOnlyInputComponent mutationTree) { var mutationReport = JsonReport.Build(_options, mutationTree); var reportPath = Path.Combine(_options.OutputPath, "reports", "mutation-report.html"); WriteHtmlReport(reportPath, mutationReport.ToJson()); _chalk.Green($"\nYour html report has been generated at: \n " + $"{reportPath} \n" + $"You can open it in your browser of choice. \n"); }
public void OnAllMutantsTested(IReadOnlyInputComponent reportComponent) { var mutationReport = JsonReport.Build(_options, reportComponent); var reportUrl = PublishReport(mutationReport.ToJson()).Result; if (reportUrl != null) { _chalk.Green($"\nYour stryker report has been uploaded to: \n {reportUrl} \nYou can open it in your browser of choice."); } else { _chalk.Red("Uploading to stryker dashboard failed..."); } Console.WriteLine(Environment.NewLine); }
private async Task UploadHumanReadableReport(JsonReport mutationReport) { var reportUrl = await _dashboardClient.PublishReport(mutationReport.ToJson(), _options.ProjectVersion); if (reportUrl != null) { _logger.LogDebug("Your stryker report has been uploaded to: \n {0} \nYou can open it in your browser of choice.", reportUrl); _chalk.Green($"Your stryker report has been uploaded to: \n {reportUrl} \nYou can open it in your browser of choice."); } else { _logger.LogError("Uploading to stryker dashboard failed..."); } Console.WriteLine(Environment.NewLine); }
public void OnAllMutantsTested(IReadOnlyInputComponent reportComponent) { var mutationReport = JsonReport.Build(_options, reportComponent); var reportUrl = _dashboardClient.PublishReport(mutationReport.ToJson(), _options.ProjectVersion).Result; if (reportUrl != null) { _logger.LogDebug("Your stryker report has been uploaded to: \n {0} \nYou can open it in your browser of choice.", reportUrl); _chalk.Green($"Your stryker report has been uploaded to: \n {reportUrl} \nYou can open it in your browser of choice."); } else { _logger.LogError("Uploading to stryker dashboard failed..."); } Console.WriteLine(Environment.NewLine); }
private static void WriteClassificationToConsole( IAnalyzableNode @class, NodesClassification classification, IChalk chalk) { foreach (var node in @class.DescendantNodesAndSelf()) { var result = classification.GetResult(node); if (result.IsArid) { chalk.Magenta($"ARID {node.Kind()}"); } else { chalk.Green($"NON-ARID {node.Kind()}"); } chalk.Default(node.GetText()); chalk.Default(Environment.NewLine + Environment.NewLine); } }
private void DisplayComponent(ProjectComponent inputComponent, int filePathLength) { _chalk.Default($"│ {(inputComponent.RelativePathToProjectFile ?? "All files").PadRight(filePathLength)}│ "); var mutationScore = inputComponent.GetMutationScore(); if (inputComponent is FileLeaf && inputComponent.IsComponentExcluded(_options.FilePatterns)) { _chalk.DarkGray("Excluded"); } else if (double.IsNaN(mutationScore)) { _chalk.DarkGray(" N/A"); } else { var scoreText = $"{mutationScore * 100:N2}".PadLeft(8); var checkHealth = inputComponent.CheckHealth(_options.Thresholds); if (checkHealth is Health.Good) { _chalk.Green(scoreText); } else if (checkHealth is Health.Warning) { _chalk.Yellow(scoreText); } else if (checkHealth is Health.Danger) { _chalk.Red(scoreText); } } _chalk.Default($" │ {inputComponent.ReadOnlyMutants.Count(m => m.ResultStatus == MutantStatus.Killed),8}"); _chalk.Default($" │ {inputComponent.ReadOnlyMutants.Count(m => m.ResultStatus == MutantStatus.Timeout),9}"); _chalk.Default($" │ {inputComponent.TotalMutants.Count() - inputComponent.DetectedMutants.Count(),10}"); _chalk.Default($" │ {inputComponent.ReadOnlyMutants.Count(m => m.ResultStatus == MutantStatus.NoCoverage),8}"); _chalk.Default($" │ {inputComponent.ReadOnlyMutants.Count(m => m.ResultStatus == MutantStatus.CompileError),7}"); _chalk.Default($" │{Environment.NewLine}"); }
public void OnAllMutantsTested(IReadOnlyInputComponent reportComponent) { // setup display handlers reportComponent.DisplayFolder = (int depth, IReadOnlyInputComponent current) => { // show depth _chalk.Default($"{new string('-', depth)} {Path.DirectorySeparatorChar}{Path.GetFileName(current.Name)} "); DisplayComponent(current); }; reportComponent.DisplayFile = (int depth, IReadOnlyInputComponent current) => { // show depth _chalk.Default($"{new string('-', depth)} {current.Name} "); DisplayComponent(current); foreach (var mutant in current.TotalMutants) { if (mutant.ResultStatus == MutantStatus.Killed || mutant.ResultStatus == MutantStatus.Timeout) { _chalk.Green($"[{mutant.ResultStatus}] "); } else if (mutant.ResultStatus == MutantStatus.NoCoverage) { _chalk.Yellow($"[{mutant.ResultStatus}] "); } else { _chalk.Red($"[{mutant.ResultStatus}] "); } _chalk.Default(mutant.LongName + Environment.NewLine); } }; // print empty line for readability _chalk.Default($"{Environment.NewLine}{Environment.NewLine}All mutants have been tested, and your mutation score has been calculated{Environment.NewLine}"); // start recursive invocation of handlers reportComponent.Display(1); }
public async Task RunMutationTest(MuTestOptions options) { if (!File.Exists(MuTestSettings.MSBuildPath)) { throw new MuTestInputException($"Unable to locate MSBuild Path at {MuTestSettings.MSBuildPath}. Please update MSBuildPath in MuTest.Console.exe.config if you are using different version"); } if (!File.Exists(MuTestSettings.VSTestConsolePath)) { throw new MuTestInputException($"Unable to locate VS Test Console Path at {MuTestSettings.VSTestConsolePath}. Please update VSTestConsolePath in MuTest.Console.exe.config if you are using different version"); } if (!File.Exists(MuTestSettings.RunSettingsPath)) { throw new MuTestInputException($"Unable to locate tests run settings path at {MuTestSettings.RunSettingsPath}. Please update RunSettingsPath in MuTest.Console.exe.config if you are using different location"); } _stopwatch = new Stopwatch(); _stopwatch.Start(); _options = options; if (!_options.SkipTestProjectBuild) { var originalProject = _options.TestProjectParameter; if (_options.OptimizeTestProject && _options.MultipleTargetClasses.Count == 1) { var targetClass = _options.MultipleTargetClasses.First(); _options.TestProjectParameter = _options .TestProjectParameter .UpdateTestProject(targetClass.TestClassPath.GetClass().ClassName()); } await ExecuteBuild(); if (!originalProject.Equals(_options.TestProjectParameter, StringComparison.InvariantCultureIgnoreCase)) { if (File.Exists(_options.TestProjectParameter)) { File.Delete(_options.TestProjectParameter); } _options.TestProjectParameter = originalProject; } } var serial = 1; _chalk.Default("\n*********************************** Matched Classes ***********************************"); foreach (var srcClass in _options.MultipleTargetClasses) { _chalk.Green($"\n{serial++}. {srcClass.ClassName} in {srcClass.ClassPath}"); } _chalk.Default("\n***************************************************************************************"); var projectSummary = new ProjectSummary { SourceProject = _options.SourceProjectParameter, TestProject = _options.TestProjectParameter }; var mutantAnalyzer = new MutantAnalyzer(_chalk, MuTestSettings) { ProcessWholeProject = _options.ProcessWholeProject, BuildInReleaseMode = _options.BuildInReleaseModeParameter, ConcurrentTestRunners = _options.ConcurrentTestRunners, EnableDiagnostics = _options.EnableDiagnostics, ExecuteAllTests = _options.ExecuteAllTests, IncludeNestedClasses = _options.IncludeNestedClasses, IncludePartialClasses = _options.IncludePartialClasses || _options.UseClassFilter || _options.ExecuteAllTests, KilledThreshold = _options.KilledThreshold, NoCoverage = _options.NoCoverage, RegEx = _options.RegEx, Specific = _options.Specific, SurvivedThreshold = _options.SurvivedThreshold, TestProject = _options.TestProjectParameter, TestProjectLibrary = _options.TestProjectLibraryParameter, UseClassFilter = _options.UseClassFilter, X64TargetPlatform = _options.X64TargetPlatform, TestExecutionTime = _options.TestExecutionThreshold, MutantsPerLine = _options.MutantsPerLine }; foreach (var targetClass in _options.MultipleTargetClasses) { mutantAnalyzer.TestClass = targetClass.TestClassPath; mutantAnalyzer.UseExternalCodeCoverage = false; mutantAnalyzer.MutantExecutor = null; var sourceClass = targetClass.ClassPath; var className = targetClass.ClassName; mutantAnalyzer.SourceProjectLibrary = _options.SourceProjectLibraryParameter; try { var sourceHash = sourceClass.GetCodeFileContent().ComputeHash(); var testHash = targetClass.TestClassPath.GetCodeFileContent().ComputeHash(); var hash = $"{sourceHash}-{testHash}".ComputeHash(); await GetFromDB(hash); if (_source != null) { var testClaz = targetClass.TestClassPath.GetClass(); var loader = new SemanticsClassDeclarationLoader(); _source.Claz = loader.Load(sourceClass, _options.SourceProjectParameter, className); _source.ClassLibrary = _options.SourceProjectLibraryParameter; _source.ClassProject = _options.SourceProjectParameter; _source.FilePath = sourceClass; _source.TestClaz = new TestClassDetail { Claz = new ClassDeclaration(testClaz), FilePath = targetClass.TestClassPath, ClassProject = _options.TestProjectParameter, FullName = testClaz.FullName(), ClassLibrary = _options.TestProjectLibraryParameter, X64TargetPlatform = _options.X64TargetPlatform }; } if (_source == null) { mutantAnalyzer.ExternalCoveredMutants.Clear(); _source = await mutantAnalyzer.Analyze(sourceClass, className, _options.SourceProjectParameter); _source.SHA256 = hash; _source.StoreToDb = true; if (_source.ExternalCoveredClassesIncluded.Any() && _options.AnalyzeExternalCoveredClasses) { _chalk.Yellow("\n\nAnalyzing External Coverage..."); mutantAnalyzer.UseExternalCodeCoverage = true; foreach (var acc in _source.ExternalCoveredClassesIncluded) { mutantAnalyzer.ExternalCoveredMutants.AddRange(acc.MutantsLines); var projectFile = new FileInfo(acc.ClassPath).FindProjectFile(); mutantAnalyzer.SourceProjectLibrary = projectFile.FindLibraryPath()?.FullName; if (!string.IsNullOrWhiteSpace(mutantAnalyzer.SourceProjectLibrary)) { var accClass = await mutantAnalyzer.Analyze( acc.ClassPath, acc.ClassName, projectFile.FullName); accClass.CalculateMutationScore(); if (accClass.MutationScore.Survived == 0) { acc.ZeroSurvivedMutants = true; } } } mutantAnalyzer.ExternalCoveredMutants.Clear(); } } } catch (Exception ex) when(!(ex is MuTestInputException)) { throw; } finally { MutantExecutor = mutantAnalyzer.MutantExecutor ?? new MutantExecutor(_source, MuTestSettings); _stopwatch.Stop(); if (_source != null) { await GenerateReports(); if (!string.IsNullOrWhiteSpace(_options.ProcessWholeProject)) { projectSummary.Classes.Add(new ClassSummary { TargetClass = new TargetClass { ClassPath = _source.FilePath, ClassName = _source.Claz.Syntax.FullName(), TestClassPath = _source.TestClaz.FilePath }, MutationScore = _source.MutationScore, Coverage = _source.Coverage ?? new Coverage() }); } } } } if (!string.IsNullOrWhiteSpace(_options.ProcessWholeProject)) { projectSummary.CalculateMutationScore(); var builder = new StringBuilder(HtmlTemplate); builder.AppendLine("<fieldset style=\"margin-bottom:10; margin-top:10\">"); builder.AppendLine("Mutation Report".PrintImportantWithLegend()); builder.Append(" ".PrintWithPreTag()); builder.Append($"{"Source Project:".PrintImportant()} {projectSummary.SourceProject}".PrintWithPreTag()); builder.Append($"{"Test Project :".PrintImportant()} {projectSummary.TestProject}".PrintWithPreTag()); builder.Append(" ".PrintWithPreTag()); builder.AppendLine("<fieldset style=\"margin-bottom:10; margin-top:10\">"); builder.AppendLine("Classes Mutation".PrintImportantWithLegend()); foreach (var claz in projectSummary.Classes) { builder.AppendLine("<fieldset style=\"margin-bottom:10; margin-top:10\">"); builder.AppendLine($"{claz.TargetClass.ClassName} [{claz.TargetClass.ClassPath}]".PrintImportantWithLegend(color: Colors.BlueViolet)); builder.Append($"{claz.MutationScore.Mutation} - {claz.MutationScore}".PrintWithPreTagWithMarginImportant()); builder.Append($"Code Coverage - {claz.Coverage}".PrintWithPreTagWithMarginImportant()); builder.AppendLine("</fieldset>"); } builder.AppendLine("</fieldset>"); builder.AppendLine("<fieldset style=\"margin-bottom:10; margin-top:10\">"); builder.AppendLine("ProjectWise Summary".PrintImportantWithLegend()); builder.Append(projectSummary.MutationScore.ToString().PrintWithPreTagWithMarginImportant(color: Colors.BlueViolet)); builder.Append($"Coverage: Mutation({projectSummary.MutationScore.Mutation}) {projectSummary.Coverage}".PrintWithPreTagWithMarginImportant(color: Colors.Blue)); builder.AppendLine("</fieldset>"); builder.AppendLine("</fieldset>"); CreateHtmlReport(builder, ProjectSummary); await CreateJsonReport(ProjectSummary, projectSummary); } }
public void OnAllMutantsTested(IReadOnlyInputComponent reportComponent) { var rootFolderProcessed = false; // setup display handlers reportComponent.DisplayFolder = (int _, IReadOnlyInputComponent current) => { // show depth var continuationLines = ParentContinuationLines(current); var stringBuilder = new StringBuilder(); foreach (var item in continuationLines.SkipLast(1)) { stringBuilder.Append(item ? ContinueLine : NoLine); } var folderLines = string.Empty; if (continuationLines.Count > 0) { folderLines = continuationLines.Last() ? BranchLine : FinalBranchLine; } var name = current.Name; if (name == null && !rootFolderProcessed) { name = "All files"; rootFolderProcessed = true; } if (!string.IsNullOrWhiteSpace(name)) { _chalk.Default($"{stringBuilder}{folderLines}{name}"); DisplayComponent(current); } }; reportComponent.DisplayFile = (int _, IReadOnlyInputComponent current) => { // show depth var continuationLines = ParentContinuationLines(current); var stringBuilder = new StringBuilder(); foreach (var item in continuationLines.SkipLast(1)) { stringBuilder.Append(item ? ContinueLine : NoLine); } _chalk.Default($"{stringBuilder}{(continuationLines.Last() ? BranchLine : FinalBranchLine)}{current.Name}"); DisplayComponent(current); stringBuilder.Append(continuationLines.Last() ? ContinueLine : NoLine); var prefix = stringBuilder.ToString(); foreach (var mutant in current.TotalMutants) { var isLastMutant = current.TotalMutants.Last() == mutant; _chalk.Default($"{prefix}{(isLastMutant ? FinalBranchLine : BranchLine)}"); switch (mutant.ResultStatus) { case MutantStatus.Killed: case MutantStatus.Timeout: _chalk.Green($"[{mutant.ResultStatus}]"); break; case MutantStatus.NoCoverage: _chalk.Yellow($"[{mutant.ResultStatus}]"); break; default: _chalk.Red($"[{mutant.ResultStatus}]"); break; } _chalk.Default($" {mutant.Mutation.DisplayName} on line {mutant.Line}{Environment.NewLine}"); _chalk.Default($"{prefix}{(isLastMutant ? NoLine : ContinueLine)}{BranchLine}[-] {mutant.Mutation.OriginalNode}{Environment.NewLine}"); _chalk.Default($"{prefix}{(isLastMutant ? NoLine : ContinueLine)}{FinalBranchLine}[+] {mutant.Mutation.ReplacementNode}{Environment.NewLine}"); } }; // print empty line for readability _chalk.Default($"{Environment.NewLine}{Environment.NewLine}All mutants have been tested, and your mutation score has been calculated{Environment.NewLine}"); // start recursive invocation of handlers reportComponent.Display(1); }