示例#1
0
        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);
        }
示例#2
0
        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();
            }
        }
示例#3
0
        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;
        }
示例#4
0
        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");
        }
示例#5
0
        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");
        }
示例#6
0
        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);
        }
示例#7
0
        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);
        }
示例#8
0
        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);
        }
示例#9
0
        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);
            }
        }
示例#10
0
        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}");
        }
示例#11
0
        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);
        }
示例#12
0
        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);
            }
        }
示例#13
0
        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);
        }