@@ -186,16 +186,17 @@ public void Copy(List<ICoverageProject> coverageProjects)
186186 private const string msCodeCoverageMessage = "Ms code coverage" ;
187187 internal Dictionary < string , UserRunSettingsProjectDetails > userRunSettingsProjectDetailsLookup ;
188188 private ShimCopier shimCopier ;
189- private ProjectRunSettingsGenerator projectRunSettingsGenerator ;
189+ private readonly IProjectRunSettingsGenerator projectRunSettingsGenerator ;
190+ private readonly IUserRunSettingsService userRunSettingsService ;
190191
191192 [ ImportingConstructor ]
192193 public MsCodeCoverageRunSettingsService (
193194 IToolFolder toolFolder ,
194195 IToolZipProvider toolZipProvider ,
195- [ Import ( typeof ( SVsServiceProvider ) ) ]
196- IServiceProvider serviceProvider ,
197196 IAppOptionsProvider appOptionsProvider ,
198197 ICoverageToolOutputManager coverageOutputManager ,
198+ IProjectRunSettingsGenerator projectRunSettingsGenerator ,
199+ IUserRunSettingsService userRunSettingsService ,
199200 IBuiltInRunSettingsTemplate builtInRunSettingsTemplate ,
200201 ICustomRunSettingsTemplateProvider customRunSettingsTemplateProvider ,
201202 ILogger logger ,
@@ -211,7 +212,8 @@ IReportGeneratorUtil reportGeneratorUtil
211212 this . logger = logger ;
212213 this . reportGeneratorUtil = reportGeneratorUtil ;
213214 builtInRunSettingsTemplateString = builtInRunSettingsTemplate . Template ;
214- this . projectRunSettingsGenerator = new ProjectRunSettingsGenerator ( serviceProvider ) ;
215+ this . projectRunSettingsGenerator = projectRunSettingsGenerator ;
216+ this . userRunSettingsService = userRunSettingsService ;
215217 }
216218
217219 public void Initialize ( string appDataFolder , IFCCEngine fccEngine , CancellationToken cancellationToken )
@@ -234,7 +236,7 @@ public MsCodeCoverageCollectionStatus IsCollecting(ITestOperation testOperation)
234236 var coverageProjects = await testOperation . GetCoverageProjectsAsync ( ) ;
235237 var coverageProjectsWithRunSettings = coverageProjects . Where ( coverageProject => coverageProject . RunSettingsFile != null ) . ToList ( ) ;
236238
237- var ( suitable , specifiedMsCodeCoverage ) = CheckUserRunSettingsSuitability (
239+ var ( suitable , specifiedMsCodeCoverage ) = userRunSettingsService . CheckUserRunSettingsSuitability (
238240 coverageProjectsWithRunSettings . Select ( cp => cp . RunSettingsFile ) , useMsCodeCoverage
239241 ) ;
240242
@@ -275,69 +277,6 @@ await CombinedLogAsync(() =>
275277 return collectionStatus ;
276278 }
277279
278- #region user runsettings suitability
279- private static ( bool Suitable , bool SpecifiedMsCodeCoverage ) CheckUserRunSettingsSuitability ( IEnumerable < string > userRunSettingsFiles , bool useMsCodeCoverage )
280- {
281- var specifiedMsCodeCoverage = false ;
282- foreach ( var userRunSettingsFile in userRunSettingsFiles )
283- {
284- var ( suitable , projectSpecifiedMsCodeCoverage ) = ValidateUserRunSettings ( File . ReadAllText ( userRunSettingsFile ) , useMsCodeCoverage ) ;
285- if ( ! suitable )
286- {
287- return ( false , false ) ;
288- }
289- if ( projectSpecifiedMsCodeCoverage )
290- {
291- specifiedMsCodeCoverage = true ;
292- }
293- }
294-
295- return ( true , specifiedMsCodeCoverage ) ;
296- }
297-
298- internal static ( bool Suitable , bool SpecifiedMsCodeCoverage ) ValidateUserRunSettings ( string runSettings , bool useMsCodeCoverage )
299- {
300- try
301- {
302- var runSettingsDoc = XDocument . Parse ( runSettings ) ;
303- var dataCollectorsElement = runSettingsDoc . GetStrictDescendant ( "RunSettings/DataCollectionRunSettings/DataCollectors" ) ;
304- if ( dataCollectorsElement == null )
305- {
306- return ( useMsCodeCoverage , false ) ;
307- }
308-
309- var msDataCollectorElement = RunSettingsHelper . FindMsDataCollector ( dataCollectorsElement ) ;
310-
311- if ( msDataCollectorElement == null )
312- {
313- return ( useMsCodeCoverage , false ) ;
314- }
315-
316- if ( HasCoberturaFormat ( msDataCollectorElement ) )
317- {
318- return ( true , true ) ;
319- }
320-
321- return ( useMsCodeCoverage , true ) ;
322- }
323- catch
324- {
325- return ( false , false ) ;
326- }
327- }
328-
329- private static bool HasCoberturaFormat ( XElement msDataCollectorElement )
330- {
331- var formatElement = msDataCollectorElement . GetStrictDescendant ( "Configuration/Format" ) ;
332- if ( formatElement == null )
333- {
334- return false ;
335- }
336- return formatElement . Value == "Cobertura" ;
337- }
338-
339- #endregion
340-
341280 private async Task PrepareCoverageProjectsAsync ( List < ICoverageProject > coverageProjects )
342281 {
343282 userRunSettingsProjectDetailsLookup = new Dictionary < string , UserRunSettingsProjectDetails > ( ) ;
@@ -457,27 +396,21 @@ public IXPathNavigable AddRunSettings(IXPathNavigable inputRunSettingDocument, I
457396 {
458397 if ( configurationInfo . RequestState == RunSettingConfigurationInfoState . Execution && NotFCCGenerated ( inputRunSettingDocument ) )
459398 {
460- return AddFCCSettings ( inputRunSettingDocument , configurationInfo ) ;
399+ var replacements = CreateReplacements ( configurationInfo . TestContainers ) ;
400+ return userRunSettingsService . AddFCCRunSettings ( replacements , inputRunSettingDocument ) ;
461401 }
462402 return null ;
463403 }
464404
465- internal IXPathNavigable AddFCCSettings ( IXPathNavigable inputRunSettingDocument , IRunSettingsConfigurationInfo configurationInfo )
405+ private bool NotFCCGenerated ( IXPathNavigable inputRunSettingDocument )
466406 {
467407 var navigator = inputRunSettingDocument . CreateNavigator ( ) ;
468- navigator . MoveToFirstChild ( ) ;
469- var clonedNavigator = navigator . Clone ( ) ;
470- IRunSettingsTemplateReplacements runSettingsTemplateReplacements = CreateReplacements ( configurationInfo ) ;
471- ConfigureRunConfiguration ( navigator , runSettingsTemplateReplacements ) ;
472- EnsureMsDataCollector ( clonedNavigator , runSettingsTemplateReplacements ) ;
473-
474- return inputRunSettingDocument ;
408+ return navigator . SelectSingleNode ( $ "//{ builtInRunSettingsTemplate . FCCMarkerElementName } ") == null ;
475409 }
476410
477- private IRunSettingsTemplateReplacements CreateReplacements ( IRunSettingsConfigurationInfo configurationInfo )
411+ private IRunSettingsTemplateReplacements CreateReplacements ( IEnumerable < ITestContainer > testContainers )
478412 {
479- var allProjectDetails = configurationInfo . TestContainers . Select ( tc => userRunSettingsProjectDetailsLookup [ tc . Source ] ) . ToList ( ) ;
480- // might have an issue with &resultsdirectory& as there is a ResultsDirectory property ?
413+ var allProjectDetails = testContainers . Select ( tc => userRunSettingsProjectDetailsLookup [ tc . Source ] ) . ToList ( ) ;
481414 var resultsDirectory = allProjectDetails [ 0 ] . OutputFolder ;
482415 var allSettings = allProjectDetails . Select ( pd => pd . Settings ) ;
483416 var mergedSettings = new MergedIncludesExcludesOptions ( allSettings ) ;
@@ -501,6 +434,142 @@ private IRunSettingsTemplateReplacements CreateReplacements(IRunSettingsConfigur
501434 return new RunSettingsTemplateReplacements ( mergedSettings , resultsDirectory , "true" , modulePathsInclude , modulePathsExclude , MsCodeCoveragePath ) ;
502435 }
503436
437+ #endregion
438+
439+ public void Collect ( IOperation operation , ITestOperation testOperation )
440+ {
441+ var resultsUris = operation . GetRunSettingsMsDataCollectorResultUri ( ) ;
442+ var coberturaFiles = new string [ 0 ] ;
443+ if ( resultsUris != null )
444+ {
445+ coberturaFiles = resultsUris . Select ( uri => uri . LocalPath ) . Where ( f => f . EndsWith ( ".cobertura.xml" ) ) . ToArray ( ) ;
446+ }
447+
448+ if ( coberturaFiles . Length == 0 )
449+ {
450+ ThreadHelper . JoinableTaskFactory . Run ( async ( ) =>
451+ {
452+ await CombinedLogAsync ( "No cobertura files for ms code coverage." ) ;
453+ } ) ;
454+ }
455+
456+ fccEngine . RunAndProcessReport ( coberturaFiles , ( ) =>
457+ {
458+ ThreadHelper . JoinableTaskFactory . Run ( async ( ) =>
459+ {
460+ List < ICoverageProject > coverageProjects = await testOperation . GetCoverageProjectsAsync ( ) ;
461+ await projectRunSettingsGenerator . RemoveGeneratedProjectSettingsAsync ( coverageProjects ) ;
462+ } ) ;
463+ } ) ;
464+ }
465+
466+ public void StopCoverage ( )
467+ {
468+ fccEngine . StopCoverage ( ) ;
469+ }
470+
471+ #region Logging
472+ private async Task CombinedLogAsync ( string message )
473+ {
474+ await CombinedLogAsync ( ( ) =>
475+ {
476+ logger . Log ( message ) ;
477+ reportGeneratorUtil . LogCoverageProcess ( message ) ;
478+ } ) ;
479+ }
480+
481+ private async Task CombinedLogAsync ( Action action )
482+ {
483+ await ThreadHelper . JoinableTaskFactory . SwitchToMainThreadAsync ( ) ;
484+ action ( ) ;
485+ }
486+ #endregion
487+
488+ }
489+
490+ internal interface IUserRunSettingsService
491+ {
492+ IXPathNavigable AddFCCRunSettings ( IBuiltInRunSettingsTemplate builtInRunSettingsTemplate , IRunSettingsTemplateReplacements replacements , IXPathNavigable inputRunSettingDocument ) ;
493+ ( bool Suitable , bool SpecifiedMsCodeCoverage ) CheckUserRunSettingsSuitability ( IEnumerable < string > userRunSettingsFiles , bool useMsCodeCoverage ) ;
494+ }
495+
496+ [ Export ( typeof ( IUserRunSettingsService ) ) ]
497+ internal class UserRunSettingsService : IUserRunSettingsService
498+ {
499+ private IBuiltInRunSettingsTemplate builtInRunSettingsTemplate ;
500+
501+ public ( bool Suitable , bool SpecifiedMsCodeCoverage ) CheckUserRunSettingsSuitability ( IEnumerable < string > userRunSettingsFiles , bool useMsCodeCoverage )
502+ {
503+ var specifiedMsCodeCoverage = false ;
504+ foreach ( var userRunSettingsFile in userRunSettingsFiles )
505+ {
506+ var ( suitable , projectSpecifiedMsCodeCoverage ) = ValidateUserRunSettings ( File . ReadAllText ( userRunSettingsFile ) , useMsCodeCoverage ) ;
507+ if ( ! suitable )
508+ {
509+ return ( false , false ) ;
510+ }
511+ if ( projectSpecifiedMsCodeCoverage )
512+ {
513+ specifiedMsCodeCoverage = true ;
514+ }
515+ }
516+
517+ return ( true , specifiedMsCodeCoverage ) ;
518+ }
519+
520+ private static ( bool Suitable , bool SpecifiedMsCodeCoverage ) ValidateUserRunSettings ( string runSettings , bool useMsCodeCoverage )
521+ {
522+ try
523+ {
524+ var runSettingsDoc = XDocument . Parse ( runSettings ) ;
525+ var dataCollectorsElement = runSettingsDoc . GetStrictDescendant ( "RunSettings/DataCollectionRunSettings/DataCollectors" ) ;
526+ if ( dataCollectorsElement == null )
527+ {
528+ return ( useMsCodeCoverage , false ) ;
529+ }
530+
531+ var msDataCollectorElement = RunSettingsHelper . FindMsDataCollector ( dataCollectorsElement ) ;
532+
533+ if ( msDataCollectorElement == null )
534+ {
535+ return ( useMsCodeCoverage , false ) ;
536+ }
537+
538+ if ( HasCoberturaFormat ( msDataCollectorElement ) )
539+ {
540+ return ( true , true ) ;
541+ }
542+
543+ return ( useMsCodeCoverage , true ) ;
544+ }
545+ catch
546+ {
547+ return ( false , false ) ;
548+ }
549+ }
550+
551+ private static bool HasCoberturaFormat ( XElement msDataCollectorElement )
552+ {
553+ var formatElement = msDataCollectorElement . GetStrictDescendant ( "Configuration/Format" ) ;
554+ if ( formatElement == null )
555+ {
556+ return false ;
557+ }
558+ return formatElement . Value == "Cobertura" ;
559+ }
560+
561+ public IXPathNavigable AddFCCRunSettings ( IBuiltInRunSettingsTemplate builtInRunSettingsTemplate , IRunSettingsTemplateReplacements replacements , IXPathNavigable inputRunSettingDocument )
562+ {
563+ this . builtInRunSettingsTemplate = builtInRunSettingsTemplate ;
564+ var navigator = inputRunSettingDocument . CreateNavigator ( ) ;
565+ navigator . MoveToFirstChild ( ) ;
566+ var clonedNavigator = navigator . Clone ( ) ;
567+ ConfigureRunConfiguration ( navigator , replacements ) ;
568+ EnsureMsDataCollector ( clonedNavigator , replacements ) ;
569+ return navigator ;
570+ }
571+
572+
504573 private void ConfigureRunConfiguration ( XPathNavigator xpathNavigator , IRunSettingsTemplateReplacements replacements )
505574 {
506575 var movedToRunConfiguration = xpathNavigator . MoveToChild ( "RunConfiguration" , "" ) ;
@@ -630,71 +699,27 @@ private void EnsureCorrectCoberturaFormat(XPathNavigator navigator)
630699 navigator . AppendChild ( "<Configuration><Format>Cobertura</Format></Configuration>" ) ;
631700 }
632701 }
702+ }
633703
634- private bool NotFCCGenerated ( IXPathNavigable inputRunSettingDocument )
635- {
636- var navigator = inputRunSettingDocument . CreateNavigator ( ) ;
637- return navigator . SelectSingleNode ( $ "//{ builtInRunSettingsTemplate . FCCMarkerElementName } ") == null ;
638- }
639- #endregion
640-
641- public void Collect ( IOperation operation , ITestOperation testOperation )
642- {
643- var resultsUris = operation . GetRunSettingsMsDataCollectorResultUri ( ) ;
644- var coberturaFiles = new string [ 0 ] ;
645- if ( resultsUris != null )
646- {
647- coberturaFiles = resultsUris . Select ( uri => uri . LocalPath ) . Where ( f => f . EndsWith ( ".cobertura.xml" ) ) . ToArray ( ) ;
648- }
649-
650- if ( coberturaFiles . Length == 0 )
651- {
652- ThreadHelper . JoinableTaskFactory . Run ( async ( ) =>
653- {
654- await CombinedLogAsync ( "No cobertura files for ms code coverage." ) ;
655- } ) ;
656- }
657-
658- fccEngine . RunAndProcessReport ( coberturaFiles , ( ) =>
659- {
660- ThreadHelper . JoinableTaskFactory . Run ( async ( ) =>
661- {
662- List < ICoverageProject > coverageProjects = await testOperation . GetCoverageProjectsAsync ( ) ;
663- await projectRunSettingsGenerator . RemoveGeneratedProjectSettingsAsync ( coverageProjects ) ;
664- } ) ;
665- } ) ;
666- }
667-
668- public void StopCoverage ( )
669- {
670- fccEngine . StopCoverage ( ) ;
671- }
672-
673- #region Logging
674- private async Task CombinedLogAsync ( string message )
675- {
676- await CombinedLogAsync ( ( ) =>
677- {
678- logger . Log ( message ) ;
679- reportGeneratorUtil . LogCoverageProcess ( message ) ;
680- } ) ;
681- }
682-
683- private async Task CombinedLogAsync ( Action action )
684- {
685- await ThreadHelper . JoinableTaskFactory . SwitchToMainThreadAsync ( ) ;
686- action ( ) ;
687- }
688- #endregion
689-
704+ internal interface IProjectRunSettingsGenerator
705+ {
706+ string GeneratedProjectRunSettingsFilePath ( ICoverageProject coverageProject ) ;
707+ Task RemoveGeneratedProjectSettingsAsync ( IEnumerable < ICoverageProject > coverageProjects ) ;
708+ Task < List < string > > WriteProjectsRunSettingsAsync ( List < ( string projectRunSettings , string projectRunSettingsFilePath , Guid projectGuid , string customTemplatePath ) > projectsRunSettingsWriteDetails ) ;
690709 }
691710
692- internal class ProjectRunSettingsGenerator
711+ [ Export ( typeof ( IProjectRunSettingsGenerator ) ) ]
712+ internal class ProjectRunSettingsGenerator : IProjectRunSettingsGenerator
693713 {
694714 private readonly IServiceProvider serviceProvider ;
695715 private const string fccGeneratedRunSettingsSuffix = "fcc-mscodecoverage-generated" ;
696716
697- public ProjectRunSettingsGenerator ( IServiceProvider serviceProvider )
717+
718+ [ ImportingConstructor ]
719+ public ProjectRunSettingsGenerator (
720+ [ Import ( typeof ( SVsServiceProvider ) ) ]
721+ IServiceProvider serviceProvider
722+ )
698723 {
699724 this . serviceProvider = serviceProvider ;
700725 }
0 commit comments