public async Task RunAsync(CancellationToken cancellationToken) { var settings = GetSettings(); LogRun(settings); var result = await processUtil .ExecuteAsync(new ExecuteRequest { FilePath = "dotnet", Arguments = $@"test --collect:""XPlat Code Coverage"" {settings} --test-adapter-path {GetTestAdapterPathArg()}", WorkingDirectory = coverageProject.ProjectOutputFolder }, cancellationToken); // this is how coverlet console determines exit code // https://github.com/coverlet-coverage/coverlet/blob/ac0e0fad2f0301a3fe9a3de9f8cdb32f406ce6d8/src/coverlet.console/Program.cs // https://github.com/coverlet-coverage/coverlet/issues/388 // vstest // https://github.com/microsoft/vstest/blob/34fa5b59661c3d87c849e81fa5be68e3dec90b76/src/vstest.console/CommandLine/Executor.cs#L146 // dotnet // https://github.com/dotnet/sdk/blob/936935f18c3540ed77c97e392780a9dd82aca441/src/Cli/dotnet/commands/dotnet-test/Program.cs#L86 // test failure has exit code 1 processResponseProcessor.Process(result, code => code == 0 || code == 1, true, GetLogTitle(), () => { coverletDataCollectorGeneratedCobertura.CorrectPath(coverageProject.CoverageOutputFolder, coverageProject.CoverageOutputFile); }); }
public async Task RunAsync(ICoverageProject project, CancellationToken cancellationToken) { var title = $"Coverlet Run ({project.ProjectName})"; var coverletSettings = GetCoverletSettings(project); logger.Log($"{title} Arguments {Environment.NewLine}{string.Join($"{Environment.NewLine}", coverletSettings)}"); var result = await processUtil .ExecuteAsync(GetExecuteRequest(project, string.Join(" ", coverletSettings)), cancellationToken); /* * 0 - Success. * 1 - If any test fails. * 2 - Coverage percentage is below threshold. * 3 - Test fails and also coverage percentage is below threshold. */ if (result.ExitCode > 3) { logger.Log($"{title} Error. Exit code: {result.ExitCode}"); logger.Log($"{title} Error. Output: ", result.Output); throw new Exception(result.Output); } logger.Log(title, result.Output); }
public async Task <bool> RunAsync(ICoverageProject project, bool throwError = false) { var title = $"Coverlet Run ({project.ProjectName})"; var coverletSettings = GetCoverletSettings(project); logger.Log($"{title} Arguments {Environment.NewLine}{string.Join($"{Environment.NewLine}", coverletSettings)}"); var result = await processUtil .ExecuteAsync(GetExecuteRequest(project, string.Join(" ", coverletSettings))); if (result != null) { /* * 0 - Success. * 1 - If any test fails. * 2 - Coverage percentage is below threshold. * 3 - Test fails and also coverage percentage is below threshold. */ if (result.ExitCode > 3) { if (throwError) { throw new Exception(result.Output); } logger.Log($"{title} Error", result.Output); return(false); } logger.Log(title, result.Output); return(true); } return(false); }
public async Task RunOpenCoverAsync(ICoverageProject project, CancellationToken cancellationToken) { var title = $"OpenCover Run ({project.ProjectName})"; var opencoverSettings = new List <string>(); opencoverSettings.Add($@" -mergebyhash "); opencoverSettings.Add($@" -hideskipped:all "); { // -register: var registerValue = "path32"; if (project.Is64Bit) { registerValue = "path64"; } opencoverSettings.Add($@" -register:{registerValue} "); } { // -target: opencoverSettings.Add($@" ""-target:{msTestPlatformUtil.MsTestPlatformExePath}"" "); } { // -filter: var filters = new List <string>(); var defaultFilter = "+[*]*"; foreach (var value in (project.Settings.Include ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x))) { filters.Add($@"+{value.Replace("\"", "\\\"").Trim(' ', '\'')}"); } foreach (var includedReferencedProject in project.IncludedReferencedProjects) { filters.Add($@"+[{includedReferencedProject}]*"); } if (!filters.Any()) { filters.Add(defaultFilter); } foreach (var value in (project.Settings.Exclude ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x))) { filters.Add($@"-{value.Replace("\"", "\\\"").Trim(' ', '\'')}"); } foreach (var referencedProjectExcludedFromCodeCoverage in project.ExcludedReferencedProjects) { filters.Add($@"-[{referencedProjectExcludedFromCodeCoverage}]*"); } if (filters.Any(x => !x.Equals(defaultFilter))) { opencoverSettings.Add($@" ""-filter:{string.Join(" ", filters.Distinct())}"" "); } } { // -excludebyfile: var excludes = new List <string>(); foreach (var value in (project.Settings.ExcludeByFile ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x))) { excludes.Add(value.Replace("\"", "\\\"").Trim(' ', '\'')); } if (excludes.Any()) { opencoverSettings.Add($@" ""-excludebyfile:{string.Join(";", excludes)}"" "); } } { // -excludebyattribute: var excludes = new List <string>() { // coverlet knows these implicitly "ExcludeFromCoverage", "ExcludeFromCodeCoverage" }; foreach (var value in (project.Settings.ExcludeByAttribute ?? new string[0]).Where(x => !string.IsNullOrWhiteSpace(x))) { excludes.Add(value.Replace("\"", "\\\"").Trim(' ', '\'')); } foreach (var exclude in excludes.ToArray()) { var excludeAlternateName = default(string); if (exclude.EndsWith("Attribute", StringComparison.OrdinalIgnoreCase)) { // remove 'Attribute' suffix excludeAlternateName = exclude.Substring(0, exclude.IndexOf("Attribute", StringComparison.OrdinalIgnoreCase)); } else { // add 'Attribute' suffix excludeAlternateName = $"{exclude}Attribute"; } excludes.Add(excludeAlternateName); } excludes = excludes.Distinct(StringComparer.OrdinalIgnoreCase).OrderBy(x => x).ToList(); if (excludes.Any()) { opencoverSettings.Add($@" ""-excludebyattribute:(*.{string.Join(")|(*.", excludes)})"" "); } } if (!project.Settings.IncludeTestAssembly) { // deleting the pdb of the test assembly seems to work; this is a VERY VERY shameful hack :( var testDllPdbFile = Path.Combine(project.ProjectOutputFolder, Path.GetFileNameWithoutExtension(project.TestDllFile)) + ".pdb"; File.Delete(testDllPdbFile); // filtering out the test-assembly blows up the entire process and nothing gets instrumented or analysed //var nameOnlyOfDll = Path.GetFileNameWithoutExtension(project.TestDllFileInWorkFolder); //filters.Add($@"-[{nameOnlyOfDll}]*"); } var runSettings = !string.IsNullOrWhiteSpace(project.RunSettingsFile) ? $@"/Settings:\""{project.RunSettingsFile}\""" : default; opencoverSettings.Add($@" ""-targetargs:\""{project.TestDllFile}\"" {runSettings}"" "); opencoverSettings.Add($@" ""-output:{ project.CoverageOutputFile }"" "); logger.Log($"{title} Arguments {Environment.NewLine}{string.Join($"{Environment.NewLine}", opencoverSettings)}"); var result = await processUtil .ExecuteAsync(new ExecuteRequest { FilePath = GetOpenCoverExePath(project.Settings.OpenCoverCustomPath), Arguments = string.Join(" ", opencoverSettings), WorkingDirectory = project.ProjectOutputFolder }, cancellationToken); if (result.ExitCode != 0) { throw new Exception(result.Output); } logger.Log(title, result.Output); }
public async Task <ReportGeneratorResult> RunReportGeneratorAsync(IEnumerable <string> coverOutputFiles, bool darkMode, bool throwError = false) { var title = "ReportGenerator Run"; var outputFolder = Path.GetDirectoryName(coverOutputFiles.OrderBy(x => x).First()); // use location of first file to output reports Directory.GetFiles(outputFolder, "*.htm*").ToList().ForEach(File.Delete); // delete html files if they exist var unifiedHtmlFile = Path.Combine(outputFolder, "index.html"); var unifiedXmlFile = Path.Combine(outputFolder, "Cobertura.xml"); var reportGeneratorSettings = new List <string>(); reportGeneratorSettings.Add($@"""-targetdir:{outputFolder}"""); async Task <bool> run(string outputReportType, string inputReports) { var reportTypeSettings = reportGeneratorSettings.ToArray().ToList(); if (outputReportType.Equals("Cobertura", StringComparison.OrdinalIgnoreCase)) { reportTypeSettings.Add($@"""-reports:{inputReports}"""); reportTypeSettings.Add($@"""-reporttypes:Cobertura"""); } else if (outputReportType.Equals("HtmlInline_AzurePipelines", StringComparison.OrdinalIgnoreCase)) { reportTypeSettings.Add($@"""-reports:{inputReports}"""); reportTypeSettings.Add($@"""-plugins:{typeof(FccLightReportBuilder).Assembly.Location}"""); reportTypeSettings.Add($@"""-reporttypes:{(darkMode ? FccDarkReportBuilder.REPORT_TYPE : FccLightReportBuilder.REPORT_TYPE)}"""); } else { throw new Exception($"Unknown reporttype '{outputReportType}'"); } logger.Log($"{title} Arguments [reporttype:{outputReportType}] {Environment.NewLine}{string.Join($"{Environment.NewLine}", reportTypeSettings)}"); var result = await processUtil .ExecuteAsync(new ExecuteRequest { FilePath = ReportGeneratorExePath, Arguments = string.Join(" ", reportTypeSettings), WorkingDirectory = outputFolder }); if (result != null) { if (result.ExitCode != 0) { if (throwError) { throw new Exception(result.Output); } logger.Log($"{title} [reporttype:{outputReportType}] Error", result.Output); return(false); } logger.Log($"{title} [reporttype:{outputReportType}]", result.Output); return(true); } return(false); } var reportGeneratorResult = new ReportGeneratorResult { Success = false, UnifiedHtmlFile = unifiedHtmlFile, UnifiedXmlFile = unifiedXmlFile }; var coberturaResult = await run("Cobertura", string.Join(";", coverOutputFiles)); if (!coberturaResult) { return(reportGeneratorResult); } reportGeneratorResult.Success = await run("HtmlInline_AzurePipelines", unifiedXmlFile); return(reportGeneratorResult); }