From cefee3bdecbdf2c648c0ba8e24ed542d8a1e7196 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Fri, 21 May 2021 10:48:02 +0100 Subject: [PATCH 1/6] replace File.ReadAllText(cobertura) with reading from file by xmlreader --- .../Core/Cobertura/CoberturaUtil.cs | 8 +-- .../Core/Cobertura/ICoberturaUtil.cs | 2 +- .../CoverageToolOutputManager.cs | 17 ++--- .../ICoverageToolOutputManager.cs | 2 +- FineCodeCoverage/Core/FCCEngine.cs | 14 ++-- .../ReportGenerator/ReportGeneratorUtil.cs | 35 +++++----- .../CoverageToolOutputManager_Tests.cs | 15 ++--- FineCodeCoverageTests/FCCEngine_Tests.cs | 66 ++++--------------- 8 files changed, 55 insertions(+), 104 deletions(-) diff --git a/FineCodeCoverage/Core/Cobertura/CoberturaUtil.cs b/FineCodeCoverage/Core/Cobertura/CoberturaUtil.cs index e6cbe363..478efa95 100644 --- a/FineCodeCoverage/Core/Cobertura/CoberturaUtil.cs +++ b/FineCodeCoverage/Core/Cobertura/CoberturaUtil.cs @@ -17,9 +17,9 @@ internal class CoberturaUtil:ICoberturaUtil private CoverageReport coverageReport; public List CoverageLines { get; private set; } - private CoverageReport LoadReport(string xml) + private CoverageReport LoadReport(string xmlFile) { - using (var reader = XmlReader.Create(new StringReader(xml), READER_SETTINGS)) + using (var reader = XmlReader.Create(xmlFile, READER_SETTINGS)) { var report = (CoverageReport)SERIALIZER.Deserialize(reader); return report; @@ -68,11 +68,11 @@ private CoverageReport LoadReport(string xml) // return jsonText; //} - public void ProcessCoberturaXml(string xml) + public void ProcessCoberturaXml(string xmlFile) { CoverageLines = new List(); - coverageReport = LoadReport(xml); + coverageReport = LoadReport(xmlFile); foreach (var package in coverageReport.Packages.Package) { diff --git a/FineCodeCoverage/Core/Cobertura/ICoberturaUtil.cs b/FineCodeCoverage/Core/Cobertura/ICoberturaUtil.cs index 670fb2d2..74759354 100644 --- a/FineCodeCoverage/Core/Cobertura/ICoberturaUtil.cs +++ b/FineCodeCoverage/Core/Cobertura/ICoberturaUtil.cs @@ -7,7 +7,7 @@ interface ICoberturaUtil { List CoverageLines { get; } - void ProcessCoberturaXml(string xml); + void ProcessCoberturaXml(string xmlFile); string[] GetSourceFiles(string assemblyName, string qualifiedClassName, int file); } } \ No newline at end of file diff --git a/FineCodeCoverage/Core/CoverageToolOutput/CoverageToolOutputManager.cs b/FineCodeCoverage/Core/CoverageToolOutput/CoverageToolOutputManager.cs index 603b0b42..731d634c 100644 --- a/FineCodeCoverage/Core/CoverageToolOutput/CoverageToolOutputManager.cs +++ b/FineCodeCoverage/Core/CoverageToolOutput/CoverageToolOutputManager.cs @@ -13,9 +13,6 @@ internal class CoverageToolOutputManager : ICoverageToolOutputManager { private readonly ILogger logger; private readonly IFileUtil fileUtil; - private const string unifiedHtmlFileName = "index.html"; - private const string unifiedXmlFileName = "Cobertura.xml"; - private const string processedHtmlFileName = "index-processed.html"; private const string projectCoverageToolOutputFolderName = "coverage-tool-output"; private string outputFolderForAllProjects; private List coverageProjects; @@ -50,14 +47,7 @@ public void SetProjectCoverageOutputFolder(List coverageProjec } } - public void OutputReports(string unifiedHtml, string processedReport, string unifiedXml) - { - var outputFolder = outputFolderForAllProjects ?? coverageProjects[0].CoverageOutputFolder; - - fileUtil.WriteAllText(Path.Combine(outputFolder, unifiedHtmlFileName), unifiedHtml); - fileUtil.WriteAllText(Path.Combine(outputFolder, processedHtmlFileName), processedReport); - fileUtil.WriteAllText(Path.Combine(outputFolder, unifiedXmlFileName), unifiedXml); - } + private void DetermineOutputFolder() { @@ -67,5 +57,10 @@ private void DetermineOutputFolder() logger.Log($"FCC output in {outputFolderForAllProjects}"); } } + + public string GetReportOutputFolder() + { + return outputFolderForAllProjects ?? coverageProjects[0].CoverageOutputFolder; + } } } diff --git a/FineCodeCoverage/Core/CoverageToolOutput/ICoverageToolOutputManager.cs b/FineCodeCoverage/Core/CoverageToolOutput/ICoverageToolOutputManager.cs index 63393c3a..ada5754b 100644 --- a/FineCodeCoverage/Core/CoverageToolOutput/ICoverageToolOutputManager.cs +++ b/FineCodeCoverage/Core/CoverageToolOutput/ICoverageToolOutputManager.cs @@ -6,6 +6,6 @@ namespace FineCodeCoverage.Engine internal interface ICoverageToolOutputManager { void SetProjectCoverageOutputFolder(List coverageProjects); - void OutputReports(string unifiedHtml, string processedReport, string unifiedXml); + string GetReportOutputFolder(); } } diff --git a/FineCodeCoverage/Core/FCCEngine.cs b/FineCodeCoverage/Core/FCCEngine.cs index b400ff1c..e1d338a6 100644 --- a/FineCodeCoverage/Core/FCCEngine.cs +++ b/FineCodeCoverage/Core/FCCEngine.cs @@ -155,7 +155,7 @@ private void UpdateUI(List coverageLines, string reportHtml) RaiseUpdateOutputWindow(reportHtml); } - private async System.Threading.Tasks.Task<(List coverageLines,string reportFilePath)> RunAndProcessReportAsync(string[] coverOutputFiles,CancellationToken cancellationToken) + private async System.Threading.Tasks.Task<(List coverageLines,string reportFilePath)> RunAndProcessReportAsync(string[] coverOutputFiles,string reportOutputFolder,CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -164,15 +164,16 @@ private void UpdateUI(List coverageLines, string reportHtml) var darkMode = CurrentTheme.Equals("Dark", StringComparison.OrdinalIgnoreCase); - var result = await reportGeneratorUtil.GenerateAsync(coverOutputFiles, darkMode, true); + var result = await reportGeneratorUtil.GenerateAsync(coverOutputFiles,reportOutputFolder, darkMode, true); if (result.Success) { - coberturaUtil.ProcessCoberturaXml(result.UnifiedXml); + logger.Log("Processing cobertura"); + coberturaUtil.ProcessCoberturaXml(result.UnifiedXmlFile); coverageLines = coberturaUtil.CoverageLines; - processedReport = reportGeneratorUtil.ProcessUnifiedHtml(result.UnifiedHtml, darkMode); - coverageOutputManager.OutputReports(result.UnifiedHtml, processedReport, result.UnifiedXml); + logger.Log("Processing report"); + processedReport = reportGeneratorUtil.ProcessUnifiedHtml(result.UnifiedHtml,reportOutputFolder, darkMode); } return (coverageLines, processedReport); } @@ -257,12 +258,13 @@ public void ReloadCoverage(Func GenerateAsync(IEnumerable coverOutputFiles, bool darkMode, bool throwError = false); + string ProcessUnifiedHtml(string htmlForProcessing,string reportOutputFolder, bool darkMode); + Task GenerateAsync(IEnumerable coverOutputFiles,string reportOutputFolder, bool darkMode, bool throwError = false); } internal class ReportGeneratorResult { public string UnifiedHtml { get; set; } - public string UnifiedXml { get; set; } + public string UnifiedXmlFile { get; set; } public bool Success { get; set; } } @@ -68,17 +68,16 @@ public void Initialize(string appDataFolder) ?? Directory.GetFiles(zipDestination, "*reportGenerator*.exe", SearchOption.AllDirectories).FirstOrDefault(); } - public async Task GenerateAsync(IEnumerable coverOutputFiles, bool darkMode, bool throwError = false) + public async Task GenerateAsync(IEnumerable coverOutputFiles,string reportOutputFolder, bool darkMode, bool throwError = false) { var title = "ReportGenerator Run"; - var tempDirectory = fileUtil.CreateTempDirectory(); - var unifiedHtmlFile = Path.Combine(tempDirectory, "index.html"); - var unifiedXmlFile = Path.Combine(tempDirectory, "Cobertura.xml"); + var unifiedHtmlFile = Path.Combine(reportOutputFolder, "index.html"); + var unifiedXmlFile = Path.Combine(reportOutputFolder, "Cobertura.xml"); var reportGeneratorSettings = new List(); - reportGeneratorSettings.Add($@"""-targetdir:{tempDirectory}"""); + reportGeneratorSettings.Add($@"""-targetdir:{reportOutputFolder}"""); async Task run(string outputReportType, string inputReports) { @@ -107,7 +106,7 @@ async Task run(string outputReportType, string inputReports) { FilePath = ReportGeneratorExePath, Arguments = string.Join(" ", reportTypeSettings), - WorkingDirectory = tempDirectory + WorkingDirectory = reportOutputFolder }); @@ -115,12 +114,13 @@ async Task run(string outputReportType, string inputReports) { if (result.ExitCode != 0) { + logger.Log($"{title} [reporttype:{outputReportType}] Error", result.Output); + if (throwError) { throw new Exception(result.Output); } - logger.Log($"{title} [reporttype:{outputReportType}] Error", result.Output); return false; } @@ -131,7 +131,7 @@ async Task run(string outputReportType, string inputReports) } - var reportGeneratorResult = new ReportGeneratorResult { Success = false, UnifiedHtml = null, UnifiedXml = null }; + var reportGeneratorResult = new ReportGeneratorResult { Success = false, UnifiedHtml = null, UnifiedXmlFile = unifiedXmlFile }; var coberturaResult = await run("Cobertura", string.Join(";", coverOutputFiles)); @@ -140,20 +140,17 @@ async Task run(string outputReportType, string inputReports) var htmlResult = await run("HtmlInline_AzurePipelines", unifiedXmlFile); if (htmlResult) { - reportGeneratorResult.UnifiedXml = fileUtil.ReadAllText(unifiedXmlFile); reportGeneratorResult.UnifiedHtml = fileUtil.ReadAllText(unifiedHtmlFile); reportGeneratorResult.Success = true; } } - fileUtil.TryDeleteDirectory(tempDirectory); - return reportGeneratorResult; } - public string ProcessUnifiedHtml(string htmlForProcessing, bool darkMode) + public string ProcessUnifiedHtml(string htmlForProcessing, string reportOutputFolder, bool darkMode) { return assemblyUtil.RunInAssemblyResolvingContext(() => { @@ -163,6 +160,7 @@ public string ProcessUnifiedHtml(string htmlForProcessing, bool darkMode) doc.OptionAutoCloseOnEnd = true; doc.LoadHtml(htmlForProcessing); + htmlForProcessing = null; doc.DocumentNode.QuerySelectorAll(".footer").ToList().ForEach(x => x.SetAttributeValue("style", "display:none")); doc.DocumentNode.QuerySelectorAll(".container").ToList().ForEach(x => x.SetAttributeValue("style", "margin:0;padding:0;border:0")); @@ -500,7 +498,7 @@ Risk Hotspots htmlSb.Replace("branchCoverageAvailable = true", "branchCoverageAvailable = false"); - return string.Join( + var processed = string.Join( Environment.NewLine, htmlSb.ToString().Split('\r', '\n') .Select(line => @@ -566,6 +564,11 @@ Risk Hotspots return line; })); + var processedHtmlFile = Path.Combine(reportOutputFolder, "index-processed.html"); + File.WriteAllText(processedHtmlFile, processed); + + return processed; + }); } } diff --git a/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs b/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs index 692b0cda..8cc253c0 100644 --- a/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs +++ b/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs @@ -124,28 +124,21 @@ public void Should_Output_Reports_To_First_Project_CoverageOutputFolder_When_Not var coverageToolOutputManager = mocker.Create(); coverageToolOutputManager.SetProjectCoverageOutputFolder(coverageProjects); - coverageToolOutputManager.OutputReports("unified html", "processed report", "unified xml"); - var firstProjectOutputFolder = mockProject1.Object.CoverageOutputFolder; - - mocker.Verify(f => f.WriteAllText(Path.Combine(firstProjectOutputFolder, "index.html"), "unified html")); - mocker.Verify(f => f.WriteAllText(Path.Combine(firstProjectOutputFolder, "index-processed.html"), "processed report")); - mocker.Verify(f => f.WriteAllText(Path.Combine(firstProjectOutputFolder, "Cobertura.xml"), "unified xml")); + Assert.AreEqual(coverageToolOutputManager.GetReportOutputFolder(), firstProjectOutputFolder); } [Test] - public void Should_Output_Reports_To_Provided_When_Not_Provided() + public void Should_Output_Reports_To_Provided_When_Provided() { SetUpProviders(true, "Provided", null); var coverageToolOutputManager = mocker.Create(); coverageToolOutputManager.SetProjectCoverageOutputFolder(coverageProjects); - coverageToolOutputManager.OutputReports("unified html", "processed report", "unified xml"); + var outputFolder = coverageToolOutputManager.GetReportOutputFolder(); - mocker.Verify(f => f.WriteAllText(Path.Combine("Provided", "index.html"), "unified html")); - mocker.Verify(f => f.WriteAllText(Path.Combine("Provided", "index-processed.html"), "processed report")); - mocker.Verify(f => f.WriteAllText(Path.Combine("Provided", "Cobertura.xml"), "unified xml")); + Assert.AreEqual(outputFolder, "Provided"); } diff --git a/FineCodeCoverageTests/FCCEngine_Tests.cs b/FineCodeCoverageTests/FCCEngine_Tests.cs index eb54b6f5..a6ee9ed6 100644 --- a/FineCodeCoverageTests/FCCEngine_Tests.cs +++ b/FineCodeCoverageTests/FCCEngine_Tests.cs @@ -276,6 +276,7 @@ public async Task Should_Run_Report_Generator_With_Output_Files_From_Coverage_Fo rg.GenerateAsync( It.Is( coverOutputFiles => coverOutputFiles.Count() == 1 && coverOutputFiles.First() == passedProjectCoverageOutputFile), + It.IsAny(), It.IsAny(), true).Result).Returns(new ReportGeneratorResult { Success = true }); @@ -289,62 +290,37 @@ public async Task Should_Run_Report_Generator_With_Output_Files_From_Coverage_Fo public async Task Should_Not_Run_ReportGenerator_If_No_Successful_Projects() { await ReloadInitializedCoverage(); - mocker.Verify(rg => rg.GenerateAsync(It.IsAny>(), It.IsAny(), It.IsAny()), Times.Never()); + mocker.Verify(rg => rg.GenerateAsync(It.IsAny>(),It.IsAny(), It.IsAny(), It.IsAny()), Times.Never()); } [Test] public async Task Should_Process_ReportGenerator_Output_If_Success() { var passedProject = CreateSuitableProject(); - + var mockReportGenerator = mocker.GetMock(); mockReportGenerator.Setup(rg => rg.GenerateAsync( It.IsAny>(), + It.IsAny(), It.IsAny(), true).Result) .Returns( new ReportGeneratorResult { Success = true, - UnifiedXml = "Unified xml", + UnifiedXmlFile = "Unified xml file", UnifiedHtml = "Unified html" } ); - mockReportGenerator.Setup(rg => rg.ProcessUnifiedHtml("Unified html", It.IsAny())); + mockReportGenerator.Setup(rg => rg.ProcessUnifiedHtml("Unified html",It.IsAny(), It.IsAny())); await ReloadInitializedCoverage(passedProject.Object); - mocker.Verify(coberturaUtil => coberturaUtil.ProcessCoberturaXml("Unified xml")); + mocker.Verify(coberturaUtil => coberturaUtil.ProcessCoberturaXml("Unified xml file")); mockReportGenerator.VerifyAll(); } - [Test] - public async Task Should_Set_Report_Output_If_Success() - { - var passedProject = CreateSuitableProject(); - - var mockReportGenerator = mocker.GetMock(); - mockReportGenerator.Setup(rg => - rg.GenerateAsync( - It.IsAny>(), - It.IsAny(), - true).Result) - .Returns( - new ReportGeneratorResult - { - Success = true, - UnifiedXml = "Unified xml", - UnifiedHtml = "Unified html" - } - ); - - mockReportGenerator.Setup(rg => rg.ProcessUnifiedHtml("Unified html", It.IsAny())).Returns("Processed html"); - - await ReloadInitializedCoverage(passedProject.Object); - mocker.Verify(coverageToolOutputManager => coverageToolOutputManager.OutputReports("Unified html","Processed html","Unified xml")); - } - [Test] public async Task Should_Not_Process_ReportGenerator_Output_If_Failure() { @@ -354,6 +330,7 @@ public async Task Should_Not_Process_ReportGenerator_Output_If_Failure() mockReportGenerator.Setup(rg => rg.GenerateAsync( It.IsAny>(), + It.IsAny(), It.IsAny(), true).Result) .Returns( @@ -368,28 +345,6 @@ public async Task Should_Not_Process_ReportGenerator_Output_If_Failure() } - [Test] - public async Task Should_Not_Set_Report_Output_If_Failure() - { - var passedProject = CreateSuitableProject(); - - var mockReportGenerator = mocker.GetMock(); - mockReportGenerator.Setup(rg => - rg.GenerateAsync( - It.IsAny>(), - It.IsAny(), - true).Result) - .Returns( - new ReportGeneratorResult - { - Success = false, - } - ); - - await ReloadInitializedCoverage(passedProject.Object); - mocker.Verify(coverageToolOutputManager => coverageToolOutputManager.OutputReports(It.IsAny(), It.IsAny(), It.IsAny()),Times.Never()); - } - [Test] public async Task Should_Clear_UI_Then_Update_UI_When_ReloadCoverage_Completes_Fully() { @@ -524,6 +479,7 @@ private void VerifyClearUIEvents(int eventNumber) mockReportGenerator.Setup(rg => rg.GenerateAsync( It.Is>(coverOutputFiles => coverOutputFiles.Count() == 1 && coverOutputFiles.First() == coverageProject.CoverageOutputFile), + It.IsAny(), It.IsAny(), true).Result) .Returns( @@ -535,7 +491,7 @@ private void VerifyClearUIEvents(int eventNumber) ); var reportGeneratedHtmlContent = ""; - mockReportGenerator.Setup(rg => rg.ProcessUnifiedHtml("Unified", It.IsAny())).Returns(reportGeneratedHtmlContent); + mockReportGenerator.Setup(rg => rg.ProcessUnifiedHtml("Unified", It.IsAny(), It.IsAny())).Returns(reportGeneratedHtmlContent); List coverageLines = new List() { new CoverageLine() }; mocker.GetMock().Setup(coberturaUtil => coberturaUtil.CoverageLines).Returns(coverageLines); @@ -560,6 +516,7 @@ private async Task ThrowReadingReportHtml() mockReportGenerator.Setup(rg => rg.GenerateAsync( It.IsAny>(), + It.IsAny(), It.IsAny(), true).Result) .Returns( @@ -614,6 +571,7 @@ private void SetUpSuccessfulRunReportGenerator() mocker.GetMock() .Setup(rg => rg.GenerateAsync( It.IsAny>(), + It.IsAny(), It.IsAny(), It.IsAny() ).Result) From e43acc0a87d510ba81d9ff80568e01bd6c2772e7 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Fri, 21 May 2021 11:12:11 +0100 Subject: [PATCH 2/6] log exit code as well as output when report generator unsuccessful --- FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs index 52a67ae9..3785b6bb 100644 --- a/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs +++ b/FineCodeCoverage/Core/ReportGenerator/ReportGeneratorUtil.cs @@ -115,6 +115,7 @@ async Task run(string outputReportType, string inputReports) if (result.ExitCode != 0) { logger.Log($"{title} [reporttype:{outputReportType}] Error", result.Output); + logger.Log($"{title} [reporttype:{outputReportType}] Error", result.ExitCode); if (throwError) { From 6dc2ecfcf55564bbd1fa14b4ec1bd869173d65a1 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Fri, 21 May 2021 22:06:56 +0100 Subject: [PATCH 3/6] improve logging coverlet console --- FineCodeCoverage/Core/Coverlet/Console/CoverletConsoleUtil.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/FineCodeCoverage/Core/Coverlet/Console/CoverletConsoleUtil.cs b/FineCodeCoverage/Core/Coverlet/Console/CoverletConsoleUtil.cs index 9e99c436..86e08923 100644 --- a/FineCodeCoverage/Core/Coverlet/Console/CoverletConsoleUtil.cs +++ b/FineCodeCoverage/Core/Coverlet/Console/CoverletConsoleUtil.cs @@ -138,12 +138,14 @@ public async Task RunAsync(ICoverageProject project, bool throwError = fal */ if (result.ExitCode > 3) { + logger.Log($"{title} Error. Exit code: {result.ExitCode}"); + logger.Log($"{title} Error. Output: ", result.Output); if (throwError) { throw new Exception(result.Output); } - logger.Log($"{title} Error", result.Output); + return false; } From 798b462575a459a9f27b279a47ac036a7711b386 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Tue, 25 May 2021 16:51:50 +0100 Subject: [PATCH 4/6] use path.combine for generated run settings path --- .../DataCollector/CoverletDataCollectorUtil.cs | 2 +- .../CoverletDataCollectorUtil_RunAsync_Tests.cs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/FineCodeCoverage/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs b/FineCodeCoverage/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs index e295a3f0..c6d461c7 100644 --- a/FineCodeCoverage/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs +++ b/FineCodeCoverage/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs @@ -120,7 +120,7 @@ private string GetSettings() { var dataCollectorSettingsBuilder = dataCollectorSettingsBuilderFactory.Create(); dataCollectorSettingsBuilder - .Initialize(coverageProject.Settings, coverageProject.RunSettingsFile, $"{coverageProject.CoverageOutputFolder}/FCC.runsettings"); + .Initialize(coverageProject.Settings, coverageProject.RunSettingsFile, Path.Combine(coverageProject.CoverageOutputFolder,"FCC.runsettings")); // command arguments dataCollectorSettingsBuilder diff --git a/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs b/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs index 450298bb..664dbf8b 100644 --- a/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs +++ b/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs @@ -34,6 +34,7 @@ public void SetUp() mockCoverageProject = new Mock(); mockCoverageProject.Setup(cp => cp.Settings).Returns(new Mock().Object); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); mockCoverageProject.Setup(cp => cp.ExcludedReferencedProjects).Returns(new List()); mockRunSettingsCoverletConfiguration = new Mock(); coverletDataCollectorUtil.runSettingsCoverletConfiguration = mockRunSettingsCoverletConfiguration.Object; @@ -60,6 +61,7 @@ private DirectoryInfo CreateTemporaryDirectory() public async Task Should_Get_Settings_With_TestDllFile() { mockCoverageProject.Setup(cp => cp.TestDllFile).Returns("test.dll"); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); await coverletDataCollectorUtil.RunAsync(false); mockDataCollectorSettingsBuilder.Verify(b => b.WithProjectDll("test.dll")); @@ -71,6 +73,7 @@ public async Task Should_Get_Settings_With_Exclude_From_CoverageProject_And_RunS { var projectExclude = new string[] { "excluded" }; mockCoverageProject.Setup(cp => cp.Settings.Exclude).Returns(projectExclude); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); var referencedExcluded = new List { "referencedExcluded" }; mockCoverageProject.Setup(cp => cp.ExcludedReferencedProjects).Returns(referencedExcluded); mockRunSettingsCoverletConfiguration.Setup(rsc => rsc.Exclude).Returns("rsexclude"); @@ -83,6 +86,7 @@ public async Task Should_Not_Throw_When_Project_Setttings_Exclude_Is_Null() { var referencedExcluded = new List { "referencedExcluded" }; mockCoverageProject.Setup(cp => cp.ExcludedReferencedProjects).Returns(referencedExcluded); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); mockRunSettingsCoverletConfiguration.Setup(rsc => rsc.Exclude).Returns("rsexclude"); await coverletDataCollectorUtil.RunAsync(false); mockDataCollectorSettingsBuilder.Verify(b => b.WithExclude(new string[] { "referencedExcluded"}, "rsexclude")); @@ -93,6 +97,8 @@ public async Task Should_Get_Settings_With_ExcludeByFile_From_CoverageProject_An { var projectExcludeByFile = new string[] { "excludedByFile" }; mockCoverageProject.Setup(cp => cp.Settings.ExcludeByFile).Returns(projectExcludeByFile); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); + mockRunSettingsCoverletConfiguration.Setup(rsc => rsc.ExcludeByFile).Returns("rsexcludeByFile"); await coverletDataCollectorUtil.RunAsync(false); mockDataCollectorSettingsBuilder.Verify(b => b.WithExcludeByFile(projectExcludeByFile, "rsexcludeByFile")); @@ -113,6 +119,8 @@ public async Task Should_Get_Settings_With_Include_From_CoverageProject_And_RunS { var projectInclude= new string[] { "included" }; mockCoverageProject.Setup(cp => cp.Settings.Include).Returns(projectInclude); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); + mockRunSettingsCoverletConfiguration.Setup(rsc => rsc.Include).Returns("rsincluded"); await coverletDataCollectorUtil.RunAsync(false); mockDataCollectorSettingsBuilder.Verify(b => b.WithInclude(projectInclude, "rsincluded")); @@ -123,6 +131,7 @@ public async Task Should_Get_Settings_With_Include_From_CoverageProject_And_RunS public async Task Should_Get_Settings_With_IncludeTestAssembly_From_CoverageProject_And_RunSettings(bool projectIncludeTestAssembly, string runSettingsIncludeTestAssembly) { mockCoverageProject.Setup(cp => cp.Settings.IncludeTestAssembly).Returns(projectIncludeTestAssembly); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); mockRunSettingsCoverletConfiguration.Setup(rsc => rsc.IncludeTestAssembly).Returns(runSettingsIncludeTestAssembly); await coverletDataCollectorUtil.RunAsync(false); mockDataCollectorSettingsBuilder.Verify(b => b.WithIncludeTestAssembly(projectIncludeTestAssembly, runSettingsIncludeTestAssembly)); @@ -137,7 +146,7 @@ public async Task Should_Initialize_With_Options_And_Run_Settings_First() mockCoverageProject.Setup(cp => cp.Settings).Returns(settings); await coverletDataCollectorUtil.RunAsync(false); - mockDataCollectorSettingsBuilder.Verify(b => b.Initialize(settings, ".runsettings","output/FCC.runsettings")); + mockDataCollectorSettingsBuilder.Verify(b => b.Initialize(settings, ".runsettings",Path.Combine("output","FCC.runsettings"))); var invocations = mockDataCollectorSettingsBuilder.Invocations.GetEnumerator().ToIEnumerable().ToList(); Assert.AreEqual(invocations.First().Method.Name, nameof(IDataCollectorSettingsBuilder.Initialize)); @@ -209,6 +218,7 @@ public async Task Should_Get_Settings_With_SkipAutoProps_From_RunSettings() public async Task Should_Log_VSTest_Run_With_Settings() { mockCoverageProject.Setup(cp => cp.ProjectName).Returns("TestProject"); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); mockDataCollectorSettingsBuilder.Setup(sb => sb.Build()).Returns("settings string"); await coverletDataCollectorUtil.RunAsync(false); mocker.Verify(l => l.Log(coverletDataCollectorUtil.LogRunMessage("settings string"))); @@ -218,6 +228,7 @@ public async Task Should_Log_VSTest_Run_With_Settings() public async Task Should_Execute_DotNet_Test_Collect_XPlat_With_Settings_Using_The_ProcessUtil() { mockCoverageProject.Setup(cp => cp.ProjectOutputFolder).Returns("projectOutputFolder"); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); mockDataCollectorSettingsBuilder.Setup(sb => sb.Build()).Returns("settings"); coverletDataCollectorUtil.TestAdapterPathArg = "testadapterpath"; await coverletDataCollectorUtil.RunAsync(false); @@ -228,6 +239,7 @@ private async Task Use_Custom_TestAdapterPath() { CreateTemporaryDirectory(); mockCoverageProject.Setup(cp => cp.ProjectOutputFolder).Returns("projectOutputFolder"); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); mockCoverageProject.Setup(cp => cp.Settings.CoverletCollectorDirectoryPath).Returns(tempDirectory); mockDataCollectorSettingsBuilder.Setup(sb => sb.Build()).Returns("settings"); coverletDataCollectorUtil.TestAdapterPathArg = "testadapterpath"; @@ -253,6 +265,7 @@ public async Task Should_Log_When_Using_Custom_TestAdapterPath() public async Task Should_Use_The_ProcessResponseProcessor(bool throwOnError,bool processResponseProcessorResult) { mockCoverageProject.Setup(cp => cp.ProjectName).Returns("TestProject"); + mockCoverageProject.Setup(cp => cp.CoverageOutputFolder).Returns(""); var mockProcesUtil = mocker.GetMock(); var executeResponse = new ExecuteResponse(); From e58faec0e10d2cc4924917987230078b83e6af05 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Tue, 25 May 2021 16:56:14 +0100 Subject: [PATCH 5/6] log saving run settings --- .../Coverlet/DataCollector/DataCollectorSettingsBuilder.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs b/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs index 1efb5915..a846c8ae 100644 --- a/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs +++ b/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs @@ -14,7 +14,13 @@ internal class DataCollectorSettingsBuilder : IDataCollectorSettingsBuilder private string generatedRunSettingsPath; private string existingRunSettings; private IAppOptions coverageProjectSettings; + private readonly ILogger logger; + [ImportingConstructor] + public DataCollectorSettingsBuilder(ILogger logger) + { + this.logger = logger; + } #region Arguments internal string ProjectDll { get; set; } internal string Blame { get; set; } @@ -67,6 +73,7 @@ public string Build() private void GenerateRunSettings() { var runSettingsDocument = existingRunSettings == null ? GenerateFullRunSettings() : GenerateRunSettingsFromExisting(); + logger.Log($"Saving run settings to {generatedRunSettingsPath}"); runSettingsDocument.Save(generatedRunSettingsPath); } From 7f3d67708b7dfbb30e12d6927f1d9c89ca67e7ce Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Tue, 25 May 2021 17:00:40 +0100 Subject: [PATCH 6/6] correct the providing of the logger. --- .../DataCollector/DataCollectorSettingsBuilder.cs | 1 - .../DataCollector/DataCollectorSettingsBuilderFactory.cs | 8 +++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs b/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs index a846c8ae..1c4611ad 100644 --- a/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs +++ b/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs @@ -16,7 +16,6 @@ internal class DataCollectorSettingsBuilder : IDataCollectorSettingsBuilder private IAppOptions coverageProjectSettings; private readonly ILogger logger; - [ImportingConstructor] public DataCollectorSettingsBuilder(ILogger logger) { this.logger = logger; diff --git a/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs b/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs index c00ff429..3111e53f 100644 --- a/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs +++ b/FineCodeCoverage/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs @@ -6,10 +6,16 @@ namespace FineCodeCoverage.Engine.Coverlet [Export(typeof(IDataCollectorSettingsBuilderFactory))] internal class DataCollectorSettingsBuilderFactory : IDataCollectorSettingsBuilderFactory { + private readonly ILogger logger; + [ImportingConstructor] + public DataCollectorSettingsBuilderFactory(ILogger logger) + { + this.logger = logger; + } public IDataCollectorSettingsBuilder Create() { - return new DataCollectorSettingsBuilder(); + return new DataCollectorSettingsBuilder(logger); } } }