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);
            });
        }
예제 #2
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }