Beispiel #1
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);
            }
        }
        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();
            }
        }