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 async Task BtnApplyMutantsClick() { _numberOfMutantsExecutingInParallel = Convert.ToByte(NumberOfMutantsExecutedInParallel); if (SelectedMutants.All(x => x.Level != MutantLevel.Mutant)) { if (!_silently) { MessageBoxService.Show("Click Find Mutants Or Select At Least One Mutant"); } return; } try { await InitializeMutants((ObservableCollection <object>) _selectedMutators); IsSplashScreenShown = true; if (ChkEnableDiagnostic.IsChecked) { _testDiagnosticDocument = MutationDocumentManagerService.CreateDocument( nameof(CommandPromptOutputViewer), _testDiagnosticDocumentViewModel); _buildDiagnosticDocument = MutationDocumentManagerService.CreateDocument( nameof(CommandPromptOutputViewer), _buildDiagnosticDocumentViewModel); _testDiagnosticDocument.Show(); _buildDiagnosticDocument.Show(); } MutantOperationsEnabled = false; ProgressBarMutationVisible = Visibility.Visible; MinimumProgress = 0; CurrentProgress = 0; var stopWatch = new Stopwatch(); stopWatch.Start(); _mutationProcessLog = new StringBuilder(); if (!_source.MethodDetails.SelectMany(x => x.Mutants).Any()) { if (!_silently) { MessageBoxService.Show(MutantsNotExist); } return; } var selectedMutants = SelectedMutants.Where(x => x.Level == MutantLevel.Mutant).ToList(); foreach (var mutant in _source.MethodDetails.SelectMany(x => x.Mutants)) { if (selectedMutants.All(x => x.MutantId != mutant.Id && mutant.ResultStatus == MutantStatus.NotRun)) { mutant.ResultStatus = MutantStatus.Skipped; } } _directoryFactory.BuildExtensions = BuildExtensions; _directoryFactory.NumberOfMutantsExecutingInParallel = _numberOfMutantsExecutingInParallel; _directoryFactory.DeleteDirectories(); await _directoryFactory.PrepareDirectoriesAndFiles(); var methodDetails = _source.MethodDetails.Where(x => x.TestMethods.Any()).ToList(); MaximumProgress = methodDetails.SelectMany(x => x.NotRunMutants).Count(); if (!methodDetails.Any()) { if (!_silently) { MessageBoxService.Show(NoAnyTestsExist); } return; } IsSplashScreenShown = false; _mutantExecutor = new MutantExecutor(_source, Settings) { EnableDiagnostics = ChkEnableDiagnostic.IsChecked, NumberOfMutantsExecutingInParallel = _numberOfMutantsExecutingInParallel, UseClassFilter = ChkUseClassFilter.IsChecked || _source.TestClaz.MethodDetails.Count > Convert.ToInt32(Settings.UseClassFilterTestsThreshold) || _source.TestClaz.BaseClass != null, BaseAddress = Settings.ServiceAddress }; if (_silently) { _mutantExecutor.UseClassFilter = true; } _testDiagnosticDocumentViewModel.CommandPromptOutput = HtmlTemplate; _buildDiagnosticDocumentViewModel.CommandPromptOutput = HtmlTemplate; void MutantExecutorOnMutantExecuted(object sender, MutantEventArgs e) { if (ChkEnableDiagnostic.IsChecked) { _testDiagnosticDocumentViewModel.CommandPromptOutput += e.TestLog; _buildDiagnosticDocumentViewModel.CommandPromptOutput += e.BuildLog; } CurrentProgress++; } _mutantExecutor.MutantExecuted += MutantExecutorOnMutantExecuted; await _mutantExecutor.ExecuteMutants(); _mutationProcessLog.Append(_mutantExecutor.LastExecutionOutput); _mutantExecutor.MutantExecuted -= MutantExecutorOnMutantExecuted; if (!_silently && ChkAnalyzeExternalCoverage.IsChecked && _source.ExternalCoveredClassesIncluded.Any()) { const string title = "Analyzing External Coverage"; var externalCoverageLog = _outputLogger.GetLogFromOutput(title, string.Empty); externalCoverageLog.CommandPromptOutput = HtmlTemplate; var chalkHtml = new ChalkHtml(); void OutputDataReceived(object sender, string output) => externalCoverageLog.CommandPromptOutput += output; chalkHtml.OutputDataReceived += OutputDataReceived; var mutantAnalyzer = new MutantAnalyzer(chalkHtml, Settings) { BuildInReleaseMode = _source.BuildInReleaseMode, ConcurrentTestRunners = _numberOfMutantsExecutingInParallel, EnableDiagnostics = ChkEnableDiagnostic.IsChecked, ExecuteAllTests = ChkExecuteAllTests.IsChecked, IncludeNestedClasses = _source.IncludeNestedClasses, IncludePartialClasses = _source.TestClaz.PartialClassNodesAdded, SourceProjectLibrary = _source.ClassLibrary, SurvivedThreshold = 0.01, TestClass = _source.TestClaz.FilePath, TestProject = _source.TestClaz.ClassProject, TestProjectLibrary = _source.TestClaz.ClassLibrary, UseClassFilter = ChkUseClassFilter.IsChecked, X64TargetPlatform = _source.X64TargetPlatform, UseExternalCodeCoverage = true, ProgressIndicator = '*', MutantsPerLine = Convert.ToInt32(MutantsPerLine) }; var document = MutationDocumentManagerService.CreateDocument(nameof(CommandPromptOutputViewer), externalCoverageLog); document.Title = title; document.Show(); 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; } } } chalkHtml.OutputDataReceived -= OutputDataReceived; mutantAnalyzer.ExternalCoveredMutants.Clear(); } stopWatch.Stop(); _mutantExecutor.PrintMutatorSummary(_mutationProcessLog); _mutantExecutor.PrintClassSummary(_mutationProcessLog); _mutationProcessLog.AppendLine("<fieldset style=\"margin-bottom:10; margin-top:10;\">"); _mutationProcessLog.AppendLine("Execution Time: ".PrintImportantWithLegend()); _mutationProcessLog.Append($"{stopWatch.Elapsed}".PrintWithPreTagWithMarginImportant()); _mutationProcessLog.AppendLine("</fieldset>"); _previousMutants.Clear(); foreach (var mutant in _source.MethodDetails.SelectMany(x => x.Mutants)) { var key = $"{mutant.Mutation.Location} - {mutant.Mutation.DisplayName}"; if (!_previousMutants.ContainsKey(key)) { _previousMutants.Add(key, mutant.ResultStatus); } } PrintMutants(); RunFileWatcherService(); } catch (Exception exception) { Trace.TraceError("Unknown Exception Occurred by Mutation Analyzer {0}", exception.StackTrace); MessageBoxService.Show(exception.Message); } finally { MutantOperationsEnabled = true; IsSplashScreenShown = false; ProgressBarMutationVisible = Visibility.Hidden; _directoryFactory.DeleteDirectories(); _idle = true; _silently = false; var notification = NotificationService.CreatePredefinedNotification(MutationIsCompletedNotification, string.Empty, string.Empty); await notification.ShowAsync(); } }