private void PrintClassCoverage(SourceClassDetail source, string coverageClassName) { Output += " ".PrintWithPreTag(); Output += "Class Coverage: ".PrintWithPreTagImportant(3, Colors.Green); Output += $"Class Name: {coverageClassName} {source.Coverage.ToString().Print(color: Colors.BlueViolet)}".PrintWithPreTagImportant(); Output += "Methods Coverage: ".PrintWithPreTagImportant(); }
private async Task InitItemSources(SourceClassDetail source) { await new MethodsInitializer { IncludeNestedClasses = IncludeNestedClasses }.FindMethods(source); }
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; }
private async Task GetFromDB(string hash) { var data = await _client.GetFileDataFromStorage(hash); if (data != null) { _source = JsonConvert.DeserializeObject <SourceClassDetail>(data); _source.StoreToDb = false; } }
private void PrintExternalCoveredClasses(SourceClassDetail source) { if (source.ExternalCoveredClasses.Any()) { Output += " ".PrintWithPreTag(); Output += "External Coverage: ".PrintWithPreTagImportant(3, Colors.Red); foreach (var clz in source.ExternalCoveredClasses) { Output += clz.ToString().PrintWithPreTagWithMarginImportant(color: Colors.BlueViolet); } } }
public void ClassLookupSelectedIndexChanged(object selectedItem) { try { IsSplashScreenShown = true; _selectedClass = (SourceClassDetail)selectedItem; ShowAnalyzeButton(); } catch (Exception) { IsSplashScreenShown = false; MessageBoxService.Show(ErrorMessage); } IsSplashScreenShown = false; }
private async Task Initialization(SourceClassDetail source) { var defaultMutants = MutantOrchestrator.GetDefaultMutants(source.Claz.Syntax, source.Claz); await InitItemSources(source); if ((defaultMutants.Any() || string.IsNullOrWhiteSpace(ProcessWholeProject)) && !UseExternalCodeCoverage) { if (TestExecutionTime > -1) { await FindTestExecutionTime(source); } await ExecuteTests(source); } await InitializeMutants(source); await AnalyzeMutant(source); }
private async Task InitializeMutants(SourceClassDetail source) { _chalk.Default("\nInitialize Mutants..."); var mutantAnalyzer = new MutantInitializer(source) { ExecuteAllTests = source.TestClaz.MethodDetails.Count > _useClassFilterTestsThreshold || ExecuteAllTests, MutantFilterRegEx = RegEx, SpecificFilterRegEx = Specific, MutantsPerLine = MutantsPerLine }; if (UseExternalCodeCoverage) { mutantAnalyzer.ExecuteAllTests = true; mutantAnalyzer.MutantFilterRegEx = string.Empty; mutantAnalyzer.SpecificFilterRegEx = string.Empty; mutantAnalyzer.MutantsAtSpecificLines.AddRange(ExternalCoveredMutants); } await mutantAnalyzer.InitializeMutants(MutantOrchestrator.DefaultMutators); }
protected MutantViewerViewModel(SourceClassDetail source) { _source = source; _silently = false; MutantList = ListBoxEditViewModel.CreateListBoxEdit(); _outputLogger = new CommandPromptOutputLogger(); ChkExecuteAllTests = ControlViewModel.Create(); ChkEnableDiagnostic = ControlViewModel.Create(); ChkEnableCodeCoverage = ControlViewModel.CreateWithChecked(); ChkAnalyzeExternalCoverage = ControlViewModel.Create(); ChkOptimizeTestProject = ControlViewModel.CreateWithChecked(); ChkUseClassFilter = ControlViewModel.CreateWithChecked(); ChkRealTimeAnalysis = ControlViewModel.Create(); _testDiagnosticDocumentViewModel = _outputLogger.GetLogFromOutput("Test Diagnostics Window", string.Empty); _buildDiagnosticDocumentViewModel = _outputLogger.GetLogFromOutput("Build Diagnostics Window", string.Empty); InitItemSources(); _directoryFactory = new TestDirectoryFactory(_source); _mutantInitializer = new MutantInitializer(_source); _previousMutants = new Dictionary <string, MutantStatus>(); _isRealMutationAnalysisRunning = false; _isClosed = false; }
private async Task AnalyzeMutant(SourceClassDetail source) { _chalk.Default("\nPreparing Tests Files...\n"); var directoryFactory = new TestDirectoryFactory(source) { NumberOfMutantsExecutingInParallel = ConcurrentTestRunners }; directoryFactory.DeleteDirectories(); await directoryFactory.PrepareDirectoriesAndFiles(); _chalk.Default("\nRunning Mutation...\n"); var mutantAnalyzer = new MutantExecutor(source, _settings) { NumberOfMutantsExecutingInParallel = ConcurrentTestRunners, EnableDiagnostics = EnableDiagnostics, SurvivedThreshold = 0.01, BaseAddress = _settings.ServiceAddress }; if (!UseExternalCodeCoverage) { MutantExecutor = mutantAnalyzer; mutantAnalyzer.UseClassFilter = UseClassFilter || source.TestClaz.MethodDetails.Count > _useClassFilterTestsThreshold || source.TestClaz.BaseClass != null; mutantAnalyzer.SurvivedThreshold = SurvivedThreshold; mutantAnalyzer.KilledThreshold = KilledThreshold; } TotalMutants = source.MethodDetails.SelectMany(x => x.NotRunMutants).Count(); MutantProgress = 0; mutantAnalyzer.MutantExecuted += MutantAnalyzerOnMutantExecuted; await mutantAnalyzer.ExecuteMutants(); directoryFactory.DeleteDirectories(); }
public void FindCoverage(SourceClassDetail source, CoverageDS codeCoverage) { if (codeCoverage != null) { source.ExternalCoveredClasses.Clear(); source.ExternalCoveredClasses.AddRange(FindExternalCoveredClasses(source, codeCoverage)); var parentClassName = string.Join(".", source.Claz.Syntax.Ancestors <ClassDeclarationSyntax>().Select(x => x.ClassName())); var className = $"{parentClassName}.{source.Claz.Syntax.ClassName()}".TrimStart('.'); var coverages = codeCoverage .Class .Where(x => x.NamespaceTableRow.NamespaceName == source.Claz.Syntax.NameSpace() && (x.ClassName == className || x.ClassName.StartsWith($"{className}.{GenericMethodStart}") || x.ClassName.StartsWith($"{className}{GenericMethodStart}"))).ToList(); if (coverages.Any()) { source.Coverage = new Coverage { LinesCovered = (uint)coverages.Sum(x => x.LinesCovered), LinesNotCovered = (uint)coverages.Sum(x => x.LinesNotCovered), BlocksCovered = (uint)coverages.Sum(x => x.BlocksCovered), BlocksNotCovered = (uint)coverages.Sum(x => x.BlocksNotCovered) }; var methodsWithCoverage = new List <MethodDetail>(); PrintClassCoverage(source, className); foreach (var coverage in coverages) { var coverageClassName = coverage.ClassName; var methods = codeCoverage .Method.Where(x => x.ClassKeyName == coverage.ClassKeyName) .ToList(); foreach (CoverageDSPriv.MethodRow mCoverage in methods) { var methodFullName = mCoverage.MethodFullName; if (methodFullName.StartsWith(GenericMethodStart) && methodFullName.Contains(GenericMethodEnd)) { var startIndex = methodFullName.IndexOf(GenericMethodStart, StringComparison.InvariantCulture) + 1; var length = methodFullName.IndexOf(GenericMethodEnd, StringComparison.InvariantCulture) - 1; methodFullName = $"{methodFullName.Substring(startIndex, length)}("; } var numberOfOverloadedMethods = source.MethodDetails.Where(x => methodFullName.StartsWith($"{x.Method.MethodName()}(") || methodFullName.StartsWith($"set_{x.Method.MethodName()}(") || methodFullName.StartsWith($"get_{x.Method.MethodName()}(")).ToList(); MethodDetail methodDetail = null; if (numberOfOverloadedMethods.Count == 1) { methodDetail = numberOfOverloadedMethods.First(); } if (methodDetail == null) { methodDetail = source.MethodDetails .FirstOrDefault(x => x.Method.MethodWithParameterTypes() == methodFullName.Replace("System.", string.Empty)); } string methodName; if (methodDetail == null && coverageClassName.Contains(GenericMethodStart)) { var startIndex = coverageClassName.IndexOf(GenericMethodStart, StringComparison.InvariantCulture); var endIndex = coverageClassName.IndexOf(GenericMethodEnd, StringComparison.InvariantCulture); methodName = coverageClassName.Substring(startIndex + 1, endIndex - startIndex - 1); methodDetail = source.MethodDetails.FirstOrDefault(x => x.Method.MethodName().Equals(methodName)); } if (methodDetail != null) { if (methodDetail.Coverage == null) { methodDetail.Coverage = new Coverage(); } methodDetail.Coverage = new Coverage { LinesCovered = methodDetail.Coverage.LinesCovered + mCoverage.LinesCovered, LinesNotCovered = methodDetail.Coverage.LinesNotCovered + mCoverage.LinesNotCovered, BlocksCovered = methodDetail.Coverage.BlocksCovered + mCoverage.BlocksCovered, BlocksNotCovered = methodDetail.Coverage.BlocksNotCovered + mCoverage.BlocksNotCovered }; methodDetail.Lines.AddRange(mCoverage.GetLinesRows()); methodsWithCoverage.Add(methodDetail); } } } methodsWithCoverage = methodsWithCoverage.GroupBy(x => x.Method.MethodWithParameterTypes()).Select(x => { var methodDetail = new MethodDetail { Coverage = x.Last().Coverage, Method = x.First().Method, MethodName = x.First().MethodName }; methodDetail.Lines.AddRange(x.First().Lines); return(methodDetail); }).ToList(); foreach (var methodDetail in methodsWithCoverage) { var methodName = methodDetail.Method.MethodWithParameterTypes(); Output += $"{methodName} {methodDetail.Coverage.ToString().Print(color: Colors.BlueViolet)}".PrintWithPreTagWithMarginImportant(); } } PrintExternalCoveredClasses(source); } }
private static IList <ClassCoverage> FindExternalCoveredClasses(SourceClassDetail source, CoverageDSPriv codeCoverage) { var data = new List <ClassCoverage>(); var thirdPartyLibs = source.TestClaz.ClassProject .GetProjectThirdPartyLibraries() .Select(x => x .Split('\\') .Last()).ToList(); thirdPartyLibs.Add("nunit"); thirdPartyLibs.Add("microsoft."); if (codeCoverage != null) { var parentClassNameList = $"{source.Claz.Syntax.NameSpace()}.{string.Join(".", source.Claz.Syntax.Ancestors<ClassDeclarationSyntax>().Select(x => x.ClassNameWithoutGeneric()))}".TrimEnd('.'); var nestedClassNameList = $"{parentClassNameList}.{source.Claz.Syntax.ClassNameWithoutGeneric()}.{string.Join(".", source.Claz.Syntax.DescendantNodes<ClassDeclarationSyntax>().Select(x => x.ClassNameWithoutGeneric()))}".TrimEnd('.'); if (parentClassNameList == source.Claz.Syntax.NameSpace()) { parentClassNameList = $"{parentClassNameList}.{source.Claz.Syntax.ClassNameWithoutGeneric()}"; } foreach (CoverageDSPriv.ClassRow claz in codeCoverage.Class) { if (claz.LinesCovered > 0 && thirdPartyLibs.All(x => !claz.NamespaceTableRow.ModuleRow.ModuleName.StartsWith(x, StringComparison.InvariantCultureIgnoreCase))) { var className = claz.ClassName; var genericIndexLocation = claz.ClassName.IndexOf(GenericMethodStart, StringComparison.Ordinal); if (genericIndexLocation != -1) { className = className.Substring(0, genericIndexLocation).TrimEnd('.'); } var fullName = $"{claz.NamespaceTableRow.NamespaceName}.{className}"; if (data.All(x => x.ClassName != fullName) && !fullName.Contains(parentClassNameList) && !fullName.Contains(nestedClassNameList)) { var coverages = codeCoverage .Class .Where(x => x.ClassName == className || x.ClassName.StartsWith($"{className}.{GenericMethodStart}") || x.ClassName.StartsWith($"{className}{GenericMethodStart}")).ToList(); coverages = coverages.Where(x => x.NamespaceTableRow.NamespaceKeyName == claz.NamespaceKeyName).ToList(); if (coverages.Any()) { var methods = codeCoverage.Method.Where(x => x.ClassKeyName == claz.ClassKeyName).ToList(); var method = methods.FirstOrDefault(); var numberOfMutants = 0; var excluded = false; var mutantsLines = new List <int>(); uint autogeneratedLineCovered = 0; uint autogeneratedLineNonCovered = 0; uint autogeneratedBlockCovered = 0; uint autogeneratedBlockNonCovered = 0; var file = string.Empty; if (method != null) { file = codeCoverage.SourceFileNames.FirstOrDefault(x => x.SourceFileID == method.GetLinesRows().FirstOrDefault()?.SourceFileID)?.SourceFileName; if (!string.IsNullOrWhiteSpace(file) && File.Exists(file)) { var root = file.GetCodeFileContent().RootNode().ClassNode(className.Split('.').Last()); var classDeclaration = new ClassDeclaration(root); var classDetail = new SourceClassDetail { Claz = classDeclaration, TestClaz = new TestClassDetail() }; if (root != null) { new MethodsInitializer().FindMethods(classDetail).Wait(); var mutants = classDetail.MethodDetails .Where(x => !x.IsProperty && !x.IsConstructor && !x.IsOverrideMethod) .SelectMany(x => MutantOrchestrator.GetDefaultMutants(x.Method, classDetail.Claz)); var coveredLines = claz.GetMethodRows().SelectMany(x => x.GetLinesRows()).Where(x => x.Coverage == 0).ToList(); mutants = mutants.Where(x => coveredLines.Any(y => y.LnStart == x.Mutation.Location)).ToList(); mutantsLines = mutants.Select(x => x.Mutation.Location ?? 0).ToList(); numberOfMutants = mutants.Count(); excluded = root.ExcludeFromExternalCoverage(); var autogeneratedMethods = root.GetGeneratedCodeMethods(); foreach (var methodSyntax in autogeneratedMethods) { var autoGeneratedCoverage = methods.FirstOrDefault(x => x.MethodFullName.Equals($"{methodSyntax.MethodName()}()") || x.MethodName.Equals($"{methodSyntax.MethodName()}()")); if (autoGeneratedCoverage != null) { autogeneratedLineCovered += autoGeneratedCoverage.LinesCovered; autogeneratedLineNonCovered += autoGeneratedCoverage.LinesNotCovered; autogeneratedBlockCovered += autoGeneratedCoverage.BlocksCovered; autogeneratedBlockNonCovered += autoGeneratedCoverage.BlocksNotCovered; } } if (methods.Any(x => x.MethodFullName.Equals($"{InitializecomponentMethod}()")) && !autogeneratedMethods.Any() && !classDetail.MethodDetails.Any(x => x.Method.MethodName().Equals(InitializecomponentMethod))) { var autoGeneratedCoverage = methods.First(x => x.MethodFullName.Equals($"{InitializecomponentMethod}()")); autogeneratedLineCovered += autoGeneratedCoverage.LinesCovered; autogeneratedLineNonCovered += autoGeneratedCoverage.LinesNotCovered; autogeneratedBlockCovered += autoGeneratedCoverage.BlocksCovered; autogeneratedBlockNonCovered += autoGeneratedCoverage.BlocksNotCovered; } } else { excluded = true; } } } var classCoverage = new ClassCoverage { ClassName = fullName, ClassPath = file, Coverage = new Coverage { LinesCovered = (uint)coverages.Sum(x => x.LinesCovered) - autogeneratedLineCovered, LinesNotCovered = (uint)coverages.Sum(x => x.LinesNotCovered) - autogeneratedLineNonCovered, BlocksCovered = (uint)coverages.Sum(x => x.BlocksCovered) - autogeneratedBlockCovered, BlocksNotCovered = (uint)coverages.Sum(x => x.BlocksNotCovered) - autogeneratedBlockNonCovered }, NumberOfMutants = numberOfMutants, Excluded = excluded }; classCoverage.MutantsLines.AddRange(mutantsLines); data.Add(classCoverage); } } } } } return(data); }
public MutantInitializer(SourceClassDetail source, IMutantSelector selector = null) { _source = source ?? throw new ArgumentNullException(nameof(source)); _selector = selector ?? new MutantSelector(); }
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 MutantExecutor(SourceClassDetail source, MuTestSettings settings) { _source = source ?? throw new ArgumentNullException(nameof(source)); _directoryFactory = new TestDirectoryFactory(_source); _settings = settings; }
public TestDirectoryFactory(SourceClassDetail source) { _source = source ?? throw new ArgumentNullException(nameof(source)); }
public static MutantViewerViewModel Create(SourceClassDetail source) { return(ViewModelSource.Create(() => new MutantViewerViewModel(source))); }
public async Task <SourceClassDetail> Analyze(string sourceClass, string className, string sourceProject) { var testClaz = TestClass.GetClass(); var semanticsClassDeclarationLoader = new SemanticsClassDeclarationLoader(); var source = new SourceClassDetail { ClassLibrary = SourceProjectLibrary, ClassProject = sourceProject, BuildInReleaseMode = BuildInReleaseMode, Claz = semanticsClassDeclarationLoader.Load(sourceClass, sourceProject, className), FullName = className, FilePath = sourceClass, X64TargetPlatform = X64TargetPlatform, TestClaz = new TestClassDetail { Claz = new ClassDeclaration(testClaz), BuildInReleaseMode = BuildInReleaseMode, ClassLibrary = TestProjectLibrary, ClassProject = TestProject, FilePath = TestClass, FullName = testClaz.FullName(), X64TargetPlatform = X64TargetPlatform } }; _chalk.Yellow($"\nProcessing source class {source.DisplayName}"); _chalk.Yellow($"\nTest class {source.TestClaz.DisplayName}"); source.TestClaz.PartialClasses.Clear(); source.TestClaz.PartialClasses.Add(new ClassDetail { Claz = source.TestClaz.Claz, FilePath = source.TestClaz.FilePath }); var baseListSyntax = source.TestClaz.Claz.Syntax.BaseList; if (baseListSyntax != null && baseListSyntax.Types.Any()) { foreach (var type in baseListSyntax.Types) { var typeSyntax = type.Type; var fileName = typeSyntax.ToString(); if (typeSyntax is GenericNameSyntax syntax) { fileName = syntax.Identifier.ValueText; } if (Path.GetDirectoryName(TestProject) .FindFile($"{fileName}.cs")? .GetCodeFileContent() .RootNode() is CompilationUnitSyntax baseFile) { source.TestClaz.BaseClass = baseFile; } } } if (IncludePartialClasses) { var testProjectFiles = Path.GetDirectoryName(TestClass).GetCSharpClassDeclarations(); var testClassDetails = testProjectFiles .SelectMany(cu => cu.CompilationUnitSyntax.DescendantNodes <ClassDeclarationSyntax>(), (cu, classDeclarationSyntax) => new TestClassDetail { FullName = $"{cu.CompilationUnitSyntax.NameSpace()}.{classDeclarationSyntax.Identifier.Text}", FilePath = cu.FileName, TotalNumberOfMethods = classDeclarationSyntax.DescendantNodes <MethodDeclarationSyntax>().Count, Claz = new ClassDeclaration(classDeclarationSyntax) }).Where(x => x.TotalNumberOfMethods > 0) .OrderByDescending(x => x.TotalNumberOfMethods) .ToList(); foreach (var data in testClassDetails) { if (!source.TestClaz.PartialClassNodesAdded && source.TestClaz.FullName == data.FullName && data.FilePath != source.TestClaz.FilePath) { source.TestClaz.PartialClasses.Add(data); } } source.TestClaz.PartialClassNodesAdded = true; } await Initialization(source); return(source); }
private async Task FindTestExecutionTime(SourceClassDetail source) { _chalk.Default("\nFinding Tests Execution Time..."); 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, EnableLogging = true, EnableCustomOptions = false }; testExecutor.OutputDataReceived += OutputData; await testExecutor.ExecuteTests(source.TestClaz.MethodDetails.ToList()); testExecutor.OutputDataReceived -= OutputData; if (testExecutor.LastTestExecutionStatus != Constants.TestExecutionStatus.Success) { throw new MuTestFailingTestException(log.ToString()); } if (testExecutor.TestResult?.Results?.UnitTestResult != null) { var tests = testExecutor.TestResult?.Results?.UnitTestResult; foreach (var test in tests) { var executionTime = 0d; if (test.Duration != null) { executionTime = TimeSpan.Parse(test.Duration).TotalMilliseconds; } if (executionTime <= TestExecutionTime) { source.TestExecutionTimes.Add(new TestExecutionTime(test.TestName, executionTime)); } else { source.TestExecutionTimesAboveThreshold.Add(new TestExecutionTime(test.TestName, executionTime)); } } source.TestExecutionTimes.Sort((x1, x2) => x2.ExecutionTime.CompareTo(x1.ExecutionTime)); source.TestExecutionTimesAboveThreshold.Sort((x1, x2) => x2.ExecutionTime.CompareTo(x1.ExecutionTime)); foreach (var test in source.TestExecutionTimesAboveThreshold) { _chalk.Red($"\n {test.TestName} ({test.ExecutionTime}ms)"); } foreach (var test in source.TestExecutionTimes) { _chalk.Green($"\n {test.TestName} ({test.ExecutionTime}ms)"); } } }
public async Task FindMethods(SourceClassDetail source) { if (source.Claz == null) { return; } source.MethodDetails.Clear(); var index = 1; IList <MethodDeclarationSyntax> sourceMethods; IList <ConstructorDeclarationSyntax> constructorMethods; IList <PropertyDeclarationSyntax> sourceProperties; if (IncludeNestedClasses) { sourceMethods = source .Claz .Syntax .Root() .GetMethods() .OrderBy(x => x.MethodName()).ToList(); constructorMethods = source .Claz .Syntax .Root() .DescendantNodes <ConstructorDeclarationSyntax>() .OrderBy(x => x.MethodName()) .ToList(); sourceProperties = source .Claz .Syntax .Root() .DescendantNodes <PropertyDeclarationSyntax>() .Where(x => MutantOrchestrator.GetDefaultMutants(x, source.Claz).Any()) .OrderBy(x => x.Identifier.ValueText) .ToList(); } else { var parentClassNodesCount = source.Claz?.Syntax.AncestorsAndSelf().OfType <ClassDeclarationSyntax>().Count() ?? 0; sourceMethods = source .Claz .Syntax .GetMethods() .Where(x => x.Ancestors <ClassDeclarationSyntax>().Count == parentClassNodesCount) .OrderBy(x => x.MethodName()) .ToList(); constructorMethods = source .Claz .Syntax .DescendantNodes <ConstructorDeclarationSyntax>() .Where(x => x.Ancestors <ClassDeclarationSyntax>().Count == parentClassNodesCount) .OrderBy(x => x.MethodName()) .ToList(); sourceProperties = source .Claz .Syntax .DescendantNodes <PropertyDeclarationSyntax>() .Where(x => x.Ancestors <ClassDeclarationSyntax>().Count == parentClassNodesCount) .Where(x => MutantOrchestrator.GetDefaultMutants(x, source.Claz).Any()) .OrderBy(x => x.Identifier.ValueText) .ToList(); } source.MethodDetails.AddRange(sourceMethods .Select(x => new MethodDetail { MethodName = $"{index++}. {x.MethodName()}{x.DescendantNodes<ParameterListSyntax>().FirstOrDefault()}", Method = x, IsOverrideMethod = x.IsOverride() })); source.MethodDetails.AddRange(constructorMethods .Select(x => new MethodDetail { MethodName = $"{index++}. {x.MethodName()}{x.DescendantNodes<ParameterListSyntax>().FirstOrDefault()}", Method = x, IsConstructor = true })); source.MethodDetails.AddRange(sourceProperties .Select(x => new MethodDetail { MethodName = $"{index++}. Property - {x.Identifier.ValueText}", Method = x, IsProperty = true })); source.TestClaz.MethodDetails.Clear(); if (source.TestClaz.BaseClass != null) { source.TestClaz.MethodDetails.AddRange(GetTestMethods(source.TestClaz.BaseClass)); } foreach (var partialClass in source.TestClaz.PartialClasses) { source.TestClaz.MethodDetails.AddRange(GetTestMethods(partialClass.Claz.Syntax)); } }