Skip to content

Commit 6bef01c

Browse files
committed
output directory from AllProjectsCoverageOutputFolder
tests to come...
1 parent 1da6ad2 commit 6bef01c

File tree

14 files changed

+311
-131
lines changed

14 files changed

+311
-131
lines changed

FineCodeCoverage/Core/Cobertura/CoberturaUtil.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using FineCodeCoverage.Engine.Model;
66
using System.ComponentModel.Composition;
7+
using System.IO;
78

89
namespace FineCodeCoverage.Engine.Cobertura
910
{
@@ -16,9 +17,9 @@ internal class CoberturaUtil:ICoberturaUtil
1617
private CoverageReport coverageReport;
1718
public List<CoverageLine> CoverageLines { get; private set; }
1819

19-
private CoverageReport LoadReportFile(string inputFilePath)
20+
private CoverageReport LoadReport(string xml)
2021
{
21-
using (var reader = XmlReader.Create(inputFilePath, READER_SETTINGS))
22+
using (var reader = XmlReader.Create(new StringReader(xml), READER_SETTINGS))
2223
{
2324
var report = (CoverageReport)SERIALIZER.Deserialize(reader);
2425
return report;
@@ -67,11 +68,11 @@ private CoverageReport LoadReportFile(string inputFilePath)
6768
// return jsonText;
6869
//}
6970

70-
public void ProcessCoberturaXmlFile(string xmlFilePath)
71+
public void ProcessCoberturaXml(string xml)
7172
{
7273
CoverageLines = new List<CoverageLine>();
7374

74-
coverageReport = LoadReportFile(xmlFilePath);
75+
coverageReport = LoadReport(xml);
7576

7677
foreach (var package in coverageReport.Packages.Package)
7778
{

FineCodeCoverage/Core/Cobertura/ICoberturaUtil.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ interface ICoberturaUtil
77
{
88
List<CoverageLine> CoverageLines { get; }
99

10-
void ProcessCoberturaXmlFile(string xmlFilePath);
10+
void ProcessCoberturaXml(string xml);
1111
string[] GetSourceFiles(string assemblyName, string qualifiedClassName, int file);
1212
}
1313
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System.Collections.Generic;
2+
using System.ComponentModel.Composition;
3+
using System.IO;
4+
using System.Linq;
5+
using FineCodeCoverage.Core.Utilities;
6+
using FineCodeCoverage.Engine.Model;
7+
8+
namespace FineCodeCoverage.Engine
9+
{
10+
[Export(typeof(ICoverageToolOutputManager))]
11+
internal class CoverageToolOutputManager : ICoverageToolOutputManager
12+
{
13+
private readonly ILogger logger;
14+
private readonly IFileUtil fileUtil;
15+
private const string unifiedHtmlFileName = "index.html";
16+
private const string unifiedXmlFileName = "Cobertura.xml";
17+
private const string processedHtmlFileName = "index-processed.html";
18+
private const string projectCoverageToolOutputFolderName = "coverage-tool-output";
19+
private string outputFolderForAllProjects;
20+
private List<ICoverageProject> coverageProjects;
21+
22+
[ImportingConstructor]
23+
public CoverageToolOutputManager(IFileUtil fileUtil, ILogger logger)
24+
{
25+
this.logger = logger;
26+
this.fileUtil = fileUtil;
27+
}
28+
29+
public void SetProjectCoverageOutputFolder(List<ICoverageProject> coverageProjects)
30+
{
31+
this.coverageProjects = coverageProjects;
32+
DetermineOutputFolderForAllProjects();
33+
if(outputFolderForAllProjects == null)
34+
{
35+
foreach(var coverageProject in coverageProjects)
36+
{
37+
coverageProject.CoverageOutputFolder = Path.Combine(coverageProject.FCCOutputFolder, projectCoverageToolOutputFolderName);
38+
}
39+
}
40+
else
41+
{
42+
fileUtil.TryEmptyDirectory(outputFolderForAllProjects);
43+
foreach (var coverageProject in coverageProjects)
44+
{
45+
coverageProject.CoverageOutputFolder = Path.Combine(outputFolderForAllProjects, coverageProject.ProjectName);
46+
}
47+
}
48+
}
49+
50+
public void SetReportOutput(string unifiedHtml, string processedReport, string unifiedXml)
51+
{
52+
var outputFolder = outputFolderForAllProjects ?? coverageProjects[0].CoverageOutputFolder;
53+
54+
fileUtil.WriteAllText(Path.Combine(outputFolder, unifiedHtmlFileName), unifiedHtml);
55+
fileUtil.WriteAllText(Path.Combine(outputFolder, processedHtmlFileName), processedReport);
56+
fileUtil.WriteAllText(Path.Combine(outputFolder, unifiedXmlFileName), unifiedXml);
57+
}
58+
59+
private void DetermineOutputFolderForAllProjects()
60+
{
61+
outputFolderForAllProjects = null;
62+
var coverageProjectWithAllProjectsCoverageOutputFolder = coverageProjects.FirstOrDefault(cp => cp.AllProjectsCoverageOutputFolder != null);
63+
if(coverageProjectWithAllProjectsCoverageOutputFolder != null)
64+
{
65+
var allProjectsCoverageOutputFolder = fileUtil.EnsureAbsolute(
66+
coverageProjectWithAllProjectsCoverageOutputFolder.AllProjectsCoverageOutputFolder,
67+
fileUtil.ParentDirectoryPath(coverageProjectWithAllProjectsCoverageOutputFolder.ProjectFile)
68+
);
69+
70+
outputFolderForAllProjects = allProjectsCoverageOutputFolder;
71+
logger.Log($"Outputting coverage files to - {outputFolderForAllProjects}");
72+
return;
73+
}
74+
75+
76+
logger.Log($"Outputting coverage files in project output folder");
77+
78+
}
79+
}
80+
}

FineCodeCoverage/Core/FCCEngine.cs

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ internal class FCCEngine : IFCCEngine
2222
{
2323
internal int InitializeWait { get; set; } = 5000;
2424
internal const string initializationFailedMessagePrefix = "Initialization failed. Please check the following error which may be resolved by reopening visual studio which will start the initialization process again.";
25-
internal const string errorReadingReportGeneratorOutputMessage = "error reading report generator output";
2625
private readonly object colorThemeService;
2726
private string CurrentTheme => $"{((dynamic)colorThemeService)?.CurrentTheme?.Name}".Trim();
2827

@@ -44,6 +43,7 @@ internal class FCCEngine : IFCCEngine
4443
private readonly IAppDataFolder appDataFolder;
4544
private readonly IServiceProvider serviceProvider;
4645
private IInitializeStatusProvider initializeStatusProvider;
46+
private readonly ICoverageToolOutputManager coverageOutputManager;
4747
internal System.Threading.Tasks.Task reloadCoverageTask;
4848

4949
[ImportingConstructor]
@@ -56,10 +56,12 @@ public FCCEngine(
5656
IAppOptionsProvider appOptionsProvider,
5757
ILogger logger,
5858
IAppDataFolder appDataFolder,
59+
ICoverageToolOutputManager coverageOutputManager,
5960
[Import(typeof(SVsServiceProvider))]
6061
IServiceProvider serviceProvider
6162
)
6263
{
64+
this.coverageOutputManager = coverageOutputManager;
6365
this.coverageUtilManager = coverageUtilManager;
6466
this.coberturaUtil = coberturaUtil;
6567
this.msTestPlatformUtil = msTestPlatformUtil;
@@ -142,54 +144,38 @@ private async System.Threading.Tasks.Task<string[]> RunCoverageAsync(List<ICover
142144

143145
}
144146

145-
private void RaiseUpdateOutputWindow(string reportFilePath)
147+
private void RaiseUpdateOutputWindow(string reportHtml)
146148
{
147-
UpdateOutputWindowEventArgs updateOutputWindowEventArgs = new UpdateOutputWindowEventArgs { };
148-
149-
try
150-
{
151-
if (!string.IsNullOrEmpty(reportFilePath))
152-
{
153-
var htmlContent = File.ReadAllText(reportFilePath);
154-
updateOutputWindowEventArgs.HtmlContent = htmlContent;
155-
}
156-
}
157-
catch
158-
{
159-
logger.Log(errorReadingReportGeneratorOutputMessage);
160-
}
161-
finally
162-
{
163-
UpdateOutputWindow?.Invoke(updateOutputWindowEventArgs);
164-
}
149+
UpdateOutputWindowEventArgs updateOutputWindowEventArgs = new UpdateOutputWindowEventArgs { HtmlContent = reportHtml};
150+
UpdateOutputWindow?.Invoke(updateOutputWindowEventArgs);
165151
}
166-
private void UpdateUI(List<CoverageLine> coverageLines, string reportFilePath)
152+
private void UpdateUI(List<CoverageLine> coverageLines, string reportHtml)
167153
{
168154
CoverageLines = coverageLines;
169155
UpdateMarginTags?.Invoke(new UpdateMarginTagsEventArgs());
170-
RaiseUpdateOutputWindow(reportFilePath);
156+
RaiseUpdateOutputWindow(reportHtml);
171157
}
172158

173159
private async System.Threading.Tasks.Task<(List<CoverageLine> coverageLines,string reportFilePath)> RunAndProcessReportAsync(string[] coverOutputFiles,CancellationToken cancellationToken)
174160
{
175161
cancellationToken.ThrowIfCancellationRequested();
176162

177163
List<CoverageLine> coverageLines = null;
178-
string reportFilePath = null;
164+
string processedReport = null;
179165

180166
var darkMode = CurrentTheme.Equals("Dark", StringComparison.OrdinalIgnoreCase);
181167

182168
var result = await reportGeneratorUtil.RunReportGeneratorAsync(coverOutputFiles, darkMode, true);
183169

184170
if (result.Success)
185171
{
186-
coberturaUtil.ProcessCoberturaXmlFile(result.UnifiedXmlFile);
172+
coberturaUtil.ProcessCoberturaXml(result.UnifiedXml);
187173
coverageLines = coberturaUtil.CoverageLines;
188174

189-
reportGeneratorUtil.ProcessUnifiedHtmlFile(result.UnifiedHtmlFile, darkMode, out var htmlFilePath);
190-
reportFilePath = htmlFilePath;
175+
processedReport = reportGeneratorUtil.ProcessUnifiedHtml(result.UnifiedHtml, darkMode);
176+
coverageOutputManager.SetReportOutput(result.UnifiedHtml, processedReport, result.UnifiedXml);
191177
}
192-
return (coverageLines, reportFilePath);
178+
return (coverageLines, processedReport);
193179
}
194180

195181
private async System.Threading.Tasks.Task PrepareCoverageProjectsAsync(List<ICoverageProject> coverageProjects, CancellationToken cancellationToken)
@@ -213,7 +199,7 @@ private async System.Threading.Tasks.Task PrepareCoverageProjectsAsync(List<ICov
213199
}
214200
}
215201

216-
private void ReloadCoverageTaskContinuation(System.Threading.Tasks.Task<(List<CoverageLine> coverageLines, string reportFilePath)> t)
202+
private void ReloadCoverageTaskContinuation(System.Threading.Tasks.Task<(List<CoverageLine> coverageLines, string reportHtml)> t)
217203
{
218204
switch (t.Status)
219205
{
@@ -228,7 +214,7 @@ private void ReloadCoverageTaskContinuation(System.Threading.Tasks.Task<(List<Co
228214
case System.Threading.Tasks.TaskStatus.RanToCompletion:
229215
LogReloadCoverageStatus(ReloadCoverageStatus.Done);
230216
#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits
231-
UpdateUI(t.Result.coverageLines, t.Result.reportFilePath);
217+
UpdateUI(t.Result.coverageLines, t.Result.reportHtml);
232218
#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits
233219
break;
234220
}
@@ -263,24 +249,26 @@ public void ReloadCoverage(Func<System.Threading.Tasks.Task<List<ICoverageProjec
263249
reloadCoverageTask = System.Threading.Tasks.Task.Run(async () =>
264250
{
265251
List<CoverageLine> coverageLines = null;
266-
string reportFilePath = null;
252+
string reportHtml = null;
267253

268254
await PollInitializedStatusAsync(cancellationToken);
269255

270256
LogReloadCoverageStatus(ReloadCoverageStatus.Start);
271257

272258
var coverageProjects = await coverageRequestCallback();
273259

260+
coverageOutputManager.SetProjectCoverageOutputFolder(coverageProjects);
261+
274262
var coverOutputFiles = await RunCoverageAsync(coverageProjects, cancellationToken);
275263

276264
if (coverOutputFiles.Any())
277265
{
278-
var (lines, rFilePath) = await RunAndProcessReportAsync(coverOutputFiles,cancellationToken);
266+
var (lines, report) = await RunAndProcessReportAsync(coverOutputFiles,cancellationToken);
279267
coverageLines = lines;
280-
reportFilePath = rFilePath;
268+
reportHtml = report;
281269
}
282270

283-
return (coverageLines, reportFilePath);
271+
return (coverageLines, reportHtml);
284272

285273
}, cancellationToken)
286274
.ContinueWith(t =>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using FineCodeCoverage.Engine.Model;
7+
8+
namespace FineCodeCoverage.Engine
9+
{
10+
internal interface ICoverageToolOutputManager
11+
{
12+
void SetProjectCoverageOutputFolder(List<ICoverageProject> coverageProjects);
13+
void SetReportOutput(string unifiedHtml, string processedReport, string unifiedXml);
14+
}
15+
}

FineCodeCoverage/Core/Model/CoverageProject.cs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ internal class CoverageProject : ICoverageProject
2424
private readonly bool canUseMsBuildWorkspace;
2525
private XElement projectFileXElement;
2626
private IAppOptions settings;
27-
private string fccPath;
2827
private readonly string fccFolderName = "fine-code-coverage";
2928
private readonly string buildOutputFolderName = "build-output";
30-
private string buildOutputPath;
29+
private string BuildOutputPath => Path.Combine(FCCOutputFolder, buildOutputFolderName);
3130
private readonly string coverageToolOutputFolderName = "coverage-tool-output";
3231

3332
public CoverageProject(IAppOptionsProvider appOptionsProvider, IFileSynchronizationUtil fileSynchronizationUtil, ILogger logger, DTE dte, bool canUseMsBuildWorkspace)
@@ -39,6 +38,9 @@ public CoverageProject(IAppOptionsProvider appOptionsProvider, IFileSynchronizat
3938
this.canUseMsBuildWorkspace = canUseMsBuildWorkspace;
4039
}
4140

41+
public string AllProjectsCoverageOutputFolder => ProjectFileXElement.XPathSelectElement($"/PropertyGroup/AllProjectsCoverageOutputFolder")?.Value;
42+
43+
public string FCCOutputFolder => Path.Combine(ProjectOutputFolder, fccFolderName);
4244
public bool IsDotNetSdkStyle()
4345
{
4446
return ProjectFileXElement
@@ -126,7 +128,7 @@ public bool IsDotNetSdkStyle()
126128
public bool HasFailed => !string.IsNullOrWhiteSpace(FailureStage) || !string.IsNullOrWhiteSpace(FailureDescription);
127129
public string ProjectFile { get; set; }
128130
public string ProjectName { get; set; }
129-
public string CoverageOutputFile { get; set; }
131+
public string CoverageOutputFile => Path.Combine(CoverageOutputFolder, $"{ProjectName}.coverage.xml");
130132

131133
private bool TypeMatch(Type type, params Type[] otherTypes)
132134
{
@@ -356,7 +358,6 @@ public async System.Threading.Tasks.Task StepAsync(string stepName, Func<ICovera
356358

357359
public async System.Threading.Tasks.Task PrepareForCoverageAsync()
358360
{
359-
SetPaths();
360361
EnsureDirectories();
361362
CleanDirectory();
362363
SynchronizeBuildOutput();
@@ -493,13 +494,6 @@ private async Task<List<ReferencedProject>> GetReferencedProjectsFromProjectFile
493494
return referencedProjectFiles.Select(referencedProjectProjectFile => new ReferencedProject(referencedProjectProjectFile)).ToList();
494495
}
495496

496-
private void SetPaths()
497-
{
498-
fccPath = Path.Combine(ProjectOutputFolder, fccFolderName);
499-
buildOutputPath = Path.Combine(fccPath, buildOutputFolderName);
500-
CoverageOutputFolder = Path.Combine(fccPath, coverageToolOutputFolderName);
501-
CoverageOutputFile = Path.Combine(CoverageOutputFolder, $"{ProjectName}.coverage.xml");
502-
}
503497
private void EnsureDirectories()
504498
{
505499
EnsureFccDirectory();
@@ -508,11 +502,11 @@ private void EnsureDirectories()
508502
}
509503
private void EnsureFccDirectory()
510504
{
511-
CreateIfDoesNotExist(fccPath);
505+
CreateIfDoesNotExist(FCCOutputFolder);
512506
}
513507
private void EnsureBuildOutputDirectory()
514508
{
515-
CreateIfDoesNotExist(buildOutputPath);
509+
CreateIfDoesNotExist(BuildOutputPath);
516510
}
517511
private void CreateIfDoesNotExist(string path)
518512
{
@@ -546,7 +540,7 @@ private void EnsureEmptyOutputFolder()
546540
private void CleanDirectory()
547541
{
548542
var exclusions = new List<string> { buildOutputFolderName, coverageToolOutputFolderName };
549-
var fccDirectory = new DirectoryInfo(fccPath);
543+
var fccDirectory = new DirectoryInfo(FCCOutputFolder);
550544

551545
fccDirectory.EnumerateFileSystemInfos().AsParallel().ForAll(fileOrDirectory =>
552546
{
@@ -570,8 +564,8 @@ private void CleanDirectory()
570564
}
571565
private void SynchronizeBuildOutput()
572566
{
573-
fileSynchronizationUtil.Synchronize(ProjectOutputFolder, buildOutputPath, fccFolderName);
574-
TestDllFile = Path.Combine(buildOutputPath, Path.GetFileName(TestDllFile));
567+
fileSynchronizationUtil.Synchronize(ProjectOutputFolder, BuildOutputPath, fccFolderName);
568+
TestDllFile = Path.Combine(BuildOutputPath, Path.GetFileName(TestDllFile));
575569
}
576570

577571
}

FineCodeCoverage/Core/Model/ICoverageProject.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ namespace FineCodeCoverage.Engine.Model
88
{
99
internal interface ICoverageProject
1010
{
11-
string CoverageOutputFile { get; set; }
11+
string AllProjectsCoverageOutputFolder { get; }
12+
string FCCOutputFolder { get; }
13+
string CoverageOutputFile { get; }
1214
string CoverageOutputFolder { get; set; }
1315
List<string> ExcludedReferencedProjects { get; }
1416
string FailureDescription { get; set; }

0 commit comments

Comments
 (0)