From 6e31a218445c5c100256b7e76a01328eba0fcae8 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 10:01:39 +0000 Subject: [PATCH 01/11] Change to culture formatted date to match test explorer. TestContainerDiscover logs coverage starting with run count. Move Logger/ILogger inside a namespace --- FineCodeCoverageTests/FCCEngine_Tests.cs | 10 +- .../TestContainerDiscovery_Tests.cs | 7 +- SharedProject/Core/AppDataFolder.cs | 1 + .../CoverageToolOutputManager.cs | 1 + ...overletConsoleDotnetToolsGlobalExecutor.cs | 1 + ...CoverletConsoleDotnetToolsLocalExecutor.cs | 1 + .../Coverlet/Console/CoverletConsoleUtil.cs | 1 + .../Console/DotNetToolListCoverlet.cs | 1 + .../CoverletDataCollectorUtil.cs | 1 + .../DataCollectorSettingsBuilder.cs | 3 +- .../DataCollectorSettingsBuilderFactory.cs | 1 + SharedProject/Core/FCCEngine.cs | 13 +- .../Core/Initialization/Initializer.cs | 1 + .../ProjectFileReferencedProjectsHelper.cs | 3 +- SharedProject/Core/Model/SettingsMerger.cs | 1 + .../MsCodeCoverageRunSettingsService.cs | 4 +- SharedProject/Core/OpenCover/OpenCoverUtil.cs | 1 + .../ReportGenerator/ReportGeneratorUtil.cs | 4 +- SharedProject/Core/SourceFileOpener.cs | 1 + .../FileSystemInfoDeleteExtensions.cs | 3 +- .../Utilities/ProcessResponseProcessor.cs | 3 +- .../Management/BufferLineCoverage.cs | 1 + .../Management/BufferLineCoverageFactory.cs | 1 + .../ContainingCodeTrackedLinesBuilder.cs | 1 + SharedProject/Impl/ILogger.cs | 21 +- SharedProject/Impl/Logger.cs | 246 +++++++++--------- SharedProject/Impl/NowForLog.cs | 22 ++ SharedProject/Impl/StatusMarkerProvider.cs | 11 + .../TestContainerDiscoverer.cs | 14 +- .../TestOperationFactory.cs | 4 +- .../TestOperationStateInvocationManager.cs | 4 +- SharedProject/Options/AppOptionsProvider.cs | 1 + SharedProject/SharedProject.projitems | 2 + 33 files changed, 224 insertions(+), 166 deletions(-) create mode 100644 SharedProject/Impl/NowForLog.cs create mode 100644 SharedProject/Impl/StatusMarkerProvider.cs diff --git a/FineCodeCoverageTests/FCCEngine_Tests.cs b/FineCodeCoverageTests/FCCEngine_Tests.cs index ed49628f..0e36593f 100644 --- a/FineCodeCoverageTests/FCCEngine_Tests.cs +++ b/FineCodeCoverageTests/FCCEngine_Tests.cs @@ -11,6 +11,7 @@ using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Engine.MsTestPlatform; using FineCodeCoverage.Engine.ReportGenerator; +using FineCodeCoverage.Impl; using FineCodeCoverage.Options; using FineCodeCoverage.Output; using Moq; @@ -105,13 +106,6 @@ public void SetUp() mockAppOptionsProvider.Setup(x => x.Get()).Returns(mockedAppOptions.Object); } - [Test] - public async Task Should_Log_Starting_When_Initialized_Async() - { - await ReloadInitializedCoverage_Async(); - VerifyLogsReloadCoverageStatus(ReloadCoverageStatus.Start); - } - [Test] public async Task Should_Prepare_For_Coverage_Suitable_CoverageProjects_Async() { @@ -319,7 +313,7 @@ public async Task Should_Cancel_Existing_ReloadCoverage_When_ReloadCoverage_Asyn private void VerifyLogsReloadCoverageStatus(ReloadCoverageStatus reloadCoverageStatus) { - mocker.Verify(l => l.Log(fccEngine.GetLogReloadCoverageStatusMessage(reloadCoverageStatus))); + mocker.Verify(l => l.Log(StatusMarkerProvider.Get(reloadCoverageStatus.ToString()))); } private async Task StopCoverage_Async() diff --git a/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs b/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs index 57bc602f..6890e120 100644 --- a/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs +++ b/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs @@ -10,11 +10,10 @@ using FineCodeCoverage.Engine.MsTestPlatform.CodeCoverage; using FineCodeCoverage.Impl; using FineCodeCoverage.Options; -using Microsoft.Build.Evaluation; using Microsoft.VisualStudio.TestWindow.Extensibility; using Moq; using NUnit.Framework; -using static System.Windows.Forms.VisualStyles.VisualStyleElement; +using FineCodeCoverage.Output; namespace Test { @@ -60,7 +59,7 @@ public void Should_Return_True_For_All_Other_States_If_Was_Initialized_When_Test public void Should_Log_When_Cannot_Invoke(TestOperationStates testOperationState) { testOperationStateInvocationManager.CanInvoke(testOperationState); - mocker.Verify(logger => logger.Log($"Skipping {testOperationState} as FCC not initialized")); + mocker.Verify(logger => logger.Log($"Skipping {testOperationState} as FCC not initialized")); } } @@ -379,7 +378,7 @@ public void Should_Handle_Any_Exception_In_OperationState_Changed_Handler_Loggin var exception = new Exception(); mocker.GetMock().Setup(engine => engine.StopCoverage()).Throws(exception); RaiseTestExecutionCancelling(); - mocker.Verify(logger => logger.Log("Error processing unit test events", exception)); + mocker.Verify(logger => logger.Log("Error processing unit test events", exception)); } [TestCase(true)] diff --git a/SharedProject/Core/AppDataFolder.cs b/SharedProject/Core/AppDataFolder.cs index 2b06fd9b..5b56ce4c 100644 --- a/SharedProject/Core/AppDataFolder.cs +++ b/SharedProject/Core/AppDataFolder.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine { diff --git a/SharedProject/Core/CoverageToolOutput/CoverageToolOutputManager.cs b/SharedProject/Core/CoverageToolOutput/CoverageToolOutputManager.cs index 76597aac..73399c3a 100644 --- a/SharedProject/Core/CoverageToolOutput/CoverageToolOutputManager.cs +++ b/SharedProject/Core/CoverageToolOutput/CoverageToolOutputManager.cs @@ -5,6 +5,7 @@ using System.Linq; using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; using SharedProject.Core.CoverageToolOutput; namespace FineCodeCoverage.Engine diff --git a/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsGlobalExecutor.cs b/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsGlobalExecutor.cs index 5b4d2b71..897f5bea 100644 --- a/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsGlobalExecutor.cs +++ b/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsGlobalExecutor.cs @@ -1,6 +1,7 @@ using System.ComponentModel.Composition; using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.Coverlet { diff --git a/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsLocalExecutor.cs b/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsLocalExecutor.cs index 1323dae5..0524c562 100644 --- a/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsLocalExecutor.cs +++ b/SharedProject/Core/Coverlet/Console/CoverletConsoleDotnetToolsLocalExecutor.cs @@ -1,6 +1,7 @@ using System.ComponentModel.Composition; using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.Coverlet { diff --git a/SharedProject/Core/Coverlet/Console/CoverletConsoleUtil.cs b/SharedProject/Core/Coverlet/Console/CoverletConsoleUtil.cs index fe2239c5..97cdbdee 100644 --- a/SharedProject/Core/Coverlet/Console/CoverletConsoleUtil.cs +++ b/SharedProject/Core/Coverlet/Console/CoverletConsoleUtil.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.Coverlet { diff --git a/SharedProject/Core/Coverlet/Console/DotNetToolListCoverlet.cs b/SharedProject/Core/Coverlet/Console/DotNetToolListCoverlet.cs index 9f4c7dbb..dd2ac6ba 100644 --- a/SharedProject/Core/Coverlet/Console/DotNetToolListCoverlet.cs +++ b/SharedProject/Core/Coverlet/Console/DotNetToolListCoverlet.cs @@ -3,6 +3,7 @@ using System.ComponentModel.Composition; using System.Linq; using FineCodeCoverage.Core.Utilities; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.Coverlet { diff --git a/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs b/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs index 296b80d9..bd9b3a7b 100644 --- a/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs +++ b/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs @@ -10,6 +10,7 @@ using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Core.Utilities.VsThreading; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; using Microsoft.VisualStudio.Shell; using Task = System.Threading.Tasks.Task; diff --git a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs index f56f0431..99af1d52 100644 --- a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs +++ b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; -using System.IO; using System.Linq; using System.Xml.Linq; -using FineCodeCoverage.Options; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.Coverlet { diff --git a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs index 3111e53f..2af1f21f 100644 --- a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs +++ b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs @@ -1,5 +1,6 @@ using System.ComponentModel.Composition; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.Coverlet { diff --git a/SharedProject/Core/FCCEngine.cs b/SharedProject/Core/FCCEngine.cs index fb40e0ee..afd9bce5 100644 --- a/SharedProject/Core/FCCEngine.cs +++ b/SharedProject/Core/FCCEngine.cs @@ -9,6 +9,7 @@ using FineCodeCoverage.Engine.MsTestPlatform; using FineCodeCoverage.Engine.MsTestPlatform.CodeCoverage; using FineCodeCoverage.Engine.ReportGenerator; +using FineCodeCoverage.Impl; using FineCodeCoverage.Options; using FineCodeCoverage.Output; @@ -105,13 +106,10 @@ IDisposeAwareTaskRunner disposeAwareTaskRunner this.msCodeCoverageRunSettingsService = msCodeCoverageRunSettingsService; } - internal string GetLogReloadCoverageStatusMessage(ReloadCoverageStatus reloadCoverageStatus) - { - return $"================================== {reloadCoverageStatus.ToString().ToUpper()} =================================="; - } + private void LogReloadCoverageStatus(ReloadCoverageStatus reloadCoverageStatus) { - logger.Log(GetLogReloadCoverageStatusMessage(reloadCoverageStatus)); + logger.Log(StatusMarkerProvider.Get(reloadCoverageStatus.ToString())); } public void Initialize(CancellationToken cancellationToken) @@ -292,7 +290,7 @@ private void CoverageTaskCompletion(System.Threading.Tasks.Task t, case System.Threading.Tasks.TaskStatus.Faulted: var innerException = t.Exception.InnerExceptions[0]; logger.Log( - GetLogReloadCoverageStatusMessage(ReloadCoverageStatus.Error), + StatusMarkerProvider.Get(ReloadCoverageStatus.Error.ToString()), innerException ); reportGeneratorUtil.LogCoverageProcess("An exception occurred. See the FCC Output Pane"); @@ -360,9 +358,6 @@ public void ReloadCoverage(Func CreateAsync(ITestOperation test private readonly IAppOptionsProvider appOptionsProvider; private readonly ICoverageToolOutputManager coverageOutputManager; private readonly IShimCopier shimCopier; - private readonly ILogger logger; + private readonly Output.ILogger logger; private readonly IReportGeneratorUtil reportGeneratorUtil; private IFCCEngine fccEngine; @@ -94,7 +94,7 @@ public MsCodeCoverageRunSettingsService( IUserRunSettingsService userRunSettingsService, ITemplatedRunSettingsService templatedRunSettingsService, IShimCopier shimCopier, - ILogger logger, + Output.ILogger logger, IReportGeneratorUtil reportGeneratorUtil ) { diff --git a/SharedProject/Core/OpenCover/OpenCoverUtil.cs b/SharedProject/Core/OpenCover/OpenCoverUtil.cs index 8de723da..edc61d1e 100644 --- a/SharedProject/Core/OpenCover/OpenCoverUtil.cs +++ b/SharedProject/Core/OpenCover/OpenCoverUtil.cs @@ -7,6 +7,7 @@ using System.ComponentModel.Composition; using FineCodeCoverage.Core.Utilities; using System.Threading; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.OpenCover { diff --git a/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs b/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs index 72136e97..c6d9f6c1 100644 --- a/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs +++ b/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs @@ -19,6 +19,7 @@ using ReportGeneratorPlugins; using System.Threading; using System.Xml.Linq; +using FineCodeCoverage.Impl; namespace FineCodeCoverage.Engine.ReportGenerator { @@ -1767,7 +1768,8 @@ private string GetDummyReportToProcess() public void LogCoverageProcess(string message) { - eventAggregator.SendMessage(new InvokeScriptMessage(CoverageLogJSFunctionName, message)); + message = $"{NowForLog.Get()} : {message}"; + eventAggregator.SendMessage(new InvokeScriptMessage(CoverageLogJSFunctionName, message)); logs.Add(message); } diff --git a/SharedProject/Core/SourceFileOpener.cs b/SharedProject/Core/SourceFileOpener.cs index 89417c43..c85c4090 100644 --- a/SharedProject/Core/SourceFileOpener.cs +++ b/SharedProject/Core/SourceFileOpener.cs @@ -4,6 +4,7 @@ using EnvDTE; using EnvDTE80; using FineCodeCoverage.Engine.Cobertura; +using FineCodeCoverage.Output; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Threading; diff --git a/SharedProject/Core/Utilities/FileSystemInfoDeleteExtensions.cs b/SharedProject/Core/Utilities/FileSystemInfoDeleteExtensions.cs index 53381b66..1d3c3ebf 100644 --- a/SharedProject/Core/Utilities/FileSystemInfoDeleteExtensions.cs +++ b/SharedProject/Core/Utilities/FileSystemInfoDeleteExtensions.cs @@ -1,4 +1,5 @@ -using System; +using FineCodeCoverage.Output; +using System; using System.IO; namespace FineCodeCoverage.Core.Utilities diff --git a/SharedProject/Core/Utilities/ProcessResponseProcessor.cs b/SharedProject/Core/Utilities/ProcessResponseProcessor.cs index 2ed26c9e..d9ce5fc8 100644 --- a/SharedProject/Core/Utilities/ProcessResponseProcessor.cs +++ b/SharedProject/Core/Utilities/ProcessResponseProcessor.cs @@ -1,4 +1,5 @@ -using System; +using FineCodeCoverage.Output; +using System; using System.ComponentModel.Composition; namespace FineCodeCoverage.Core.Utilities diff --git a/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverage.cs b/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverage.cs index d234cc84..3c5f8037 100644 --- a/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverage.cs +++ b/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverage.cs @@ -7,6 +7,7 @@ using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Impl; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; diff --git a/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverageFactory.cs b/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverageFactory.cs index 854c8aba..ca8babbb 100644 --- a/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverageFactory.cs +++ b/SharedProject/Editor/DynamicCoverage/Management/BufferLineCoverageFactory.cs @@ -6,6 +6,7 @@ using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Impl; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Editor.DynamicCoverage { diff --git a/SharedProject/Editor/DynamicCoverage/TrackedLinesImpl/Construction/ContainingCodeTrackedLinesBuilder.cs b/SharedProject/Editor/DynamicCoverage/TrackedLinesImpl/Construction/ContainingCodeTrackedLinesBuilder.cs index 158662fe..539ab940 100644 --- a/SharedProject/Editor/DynamicCoverage/TrackedLinesImpl/Construction/ContainingCodeTrackedLinesBuilder.cs +++ b/SharedProject/Editor/DynamicCoverage/TrackedLinesImpl/Construction/ContainingCodeTrackedLinesBuilder.cs @@ -5,6 +5,7 @@ using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Editor.DynamicCoverage.TrackedLinesImpl.Construction; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; using Microsoft.VisualStudio.Text; namespace FineCodeCoverage.Editor.DynamicCoverage diff --git a/SharedProject/Impl/ILogger.cs b/SharedProject/Impl/ILogger.cs index b19f57b6..cd33ff6d 100644 --- a/SharedProject/Impl/ILogger.cs +++ b/SharedProject/Impl/ILogger.cs @@ -1,13 +1,16 @@ using System.Collections.Generic; -public interface ILogger +namespace FineCodeCoverage.Output { - void Log(IEnumerable message); - void Log(IEnumerable message); - void Log(params object[] message); - void Log(params string[] message); - void LogWithoutTitle(IEnumerable message); - void LogWithoutTitle(IEnumerable message); - void LogWithoutTitle(params object[] message); - void LogWithoutTitle(params string[] message); + public interface ILogger + { + void Log(IEnumerable message); + void Log(IEnumerable message); + void Log(params object[] message); + void Log(params string[] message); + void LogWithoutTitle(IEnumerable message); + void LogWithoutTitle(IEnumerable message); + void LogWithoutTitle(params object[] message); + void LogWithoutTitle(params string[] message); + } } \ No newline at end of file diff --git a/SharedProject/Impl/Logger.cs b/SharedProject/Impl/Logger.cs index 594fc1f2..bac5fbd8 100644 --- a/SharedProject/Impl/Logger.cs +++ b/SharedProject/Impl/Logger.cs @@ -1,164 +1,168 @@ using System; using System.Linq; -using FineCodeCoverage; using System.Diagnostics; using System.Collections.Generic; using Microsoft.VisualStudio.Shell; -using System.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.Shell.Interop; using System.ComponentModel.Composition; using Microsoft; using Task = System.Threading.Tasks.Task; using EnvDTE80; +using FineCodeCoverage.Impl; -interface IShowFCCOutputPane +namespace FineCodeCoverage.Output { - Task ShowAsync(); -} -[Export(typeof(IShowFCCOutputPane))] -[Export(typeof(ILogger))] -public class Logger : ILogger, IShowFCCOutputPane -{ - private IVsOutputWindowPane _pane; - private IVsOutputWindow _outputWindow; - private DTE2 dte; - private readonly IServiceProvider _serviceProvider; - private Guid fccPaneGuid = Guid.Parse("3B3C775A-0050-445D-9022-0230957805B2"); - - [ImportingConstructor] - public Logger( - [Import(typeof(SVsServiceProvider))] - IServiceProvider serviceProvider - ) + interface IShowFCCOutputPane { - this._serviceProvider = serviceProvider; - staticLogger = this; + Task ShowAsync(); } - - private async Task SetPaneAsync() + [Export(typeof(IShowFCCOutputPane))] + [Export(typeof(ILogger))] + public class Logger : ILogger, IShowFCCOutputPane { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - _outputWindow = (IVsOutputWindow)_serviceProvider.GetService(typeof(SVsOutputWindow)); - Assumes.Present(_outputWindow); - dte = (DTE2)_serviceProvider.GetService(typeof(EnvDTE.DTE)); - Assumes.Present(dte); - - // Create a new pane. - _outputWindow.CreatePane( - ref fccPaneGuid, - "FCC", - Convert.ToInt32(true), - Convert.ToInt32(false)); // do not clear with solution otherwise will not get initialize methods - - // Retrieve the new pane. - _outputWindow.GetPane(ref fccPaneGuid, out IVsOutputWindowPane pane); - _pane = pane; - } - - private void LogImpl(object[] message, bool withTitle) - { - try + private IVsOutputWindowPane _pane; + private IVsOutputWindow _outputWindow; + private DTE2 dte; + private readonly IServiceProvider _serviceProvider; + private Guid fccPaneGuid = Guid.Parse("3B3C775A-0050-445D-9022-0230957805B2"); + + [ImportingConstructor] + public Logger( + [Import(typeof(SVsServiceProvider))] + IServiceProvider serviceProvider + ) { - var logTime = DateTime.Now; - var messageList = new List(message?.Select(x => x?.ToString()?.Trim(' ', '\r', '\n')).Where(x => !string.IsNullOrWhiteSpace(x))); + this._serviceProvider = serviceProvider; + staticLogger = this; + } - if (!messageList.Any()) - { - return; - } + private async Task SetPaneAsync() + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + _outputWindow = (IVsOutputWindow)_serviceProvider.GetService(typeof(SVsOutputWindow)); + Assumes.Present(_outputWindow); + dte = (DTE2)_serviceProvider.GetService(typeof(EnvDTE.DTE)); + Assumes.Present(dte); + + // Create a new pane. + _outputWindow.CreatePane( + ref fccPaneGuid, + "FCC", + Convert.ToInt32(true), + Convert.ToInt32(false)); // do not clear with solution otherwise will not get initialize methods + + // Retrieve the new pane. + _outputWindow.GetPane(ref fccPaneGuid, out IVsOutputWindowPane pane); + _pane = pane; + } - ThreadHelper.JoinableTaskFactory.Run(async () => + private void LogImpl(object[] message, bool withTitle) + { + try { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + //var logTime = DateTime.Now; + var logTime = NowForLog.Get(); + var messageList = new List(message?.Select(x => x?.ToString()?.Trim(' ', '\r', '\n')).Where(x => !string.IsNullOrWhiteSpace(x))); - if(_pane == null) - { - await SetPaneAsync(); - } - - if(_pane == null) + if (!messageList.Any()) { return; } - var logs = string.Join(Environment.NewLine, messageList); - - if (withTitle) + ThreadHelper.JoinableTaskFactory.Run(async () => { - _pane.OutputStringThreadSafe($"{Vsix.Name} {logTime}: {logs}{Environment.NewLine}"); - } - else - { - _pane.OutputStringThreadSafe($"{logs}{Environment.NewLine}"); - } - }); + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + + if (_pane == null) + { + await SetPaneAsync(); + } + + if (_pane == null) + { + return; + } + + var logs = string.Join(Environment.NewLine, messageList); + + if (withTitle) + { + //_pane.OutputStringThreadSafe($"{Vsix.Name} {logTime}: {logs}{Environment.NewLine}"); + _pane.OutputStringThreadSafe($"{logTime}: {logs}{Environment.NewLine}"); + } + else + { + _pane.OutputStringThreadSafe($"{logs}{Environment.NewLine}"); + } + }); + } + catch (Exception ex) + { + Debug.Write(ex); + } } - catch (Exception ex) + + private static Logger staticLogger; + public static void Log(params string[] message) { - Debug.Write(ex); + (staticLogger as ILogger).Log(message); } - } - - private static Logger staticLogger; - public static void Log(params string[] message) - { - (staticLogger as ILogger).Log(message); - } - - public void Log(params object[] message) - { - LogImpl(message, true); - } - - void ILogger.Log(params string[] message) - { - LogImpl(message, true); - } - public void Log(IEnumerable message) - { - LogImpl(message.ToArray(), true); - } + public void Log(params object[] message) + { + LogImpl(message, true); + } - public void Log(IEnumerable message) - { - LogImpl(message.ToArray(), true); - } + void ILogger.Log(params string[] message) + { + LogImpl(message, true); + } - public void LogWithoutTitle(params object[] message) - { - LogImpl(message, false); - } + public void Log(IEnumerable message) + { + LogImpl(message.ToArray(), true); + } - public void LogWithoutTitle(params string[] message) - { - LogImpl(message, false); - } + public void Log(IEnumerable message) + { + LogImpl(message.ToArray(), true); + } - public void LogWithoutTitle(IEnumerable message) - { - LogImpl(message.ToArray(), false); - } + public void LogWithoutTitle(params object[] message) + { + LogImpl(message, false); + } - public void LogWithoutTitle(IEnumerable message) - { - LogImpl(message.ToArray(), false); - } + public void LogWithoutTitle(params string[] message) + { + LogImpl(message, false); + } - public async Task ShowAsync() - { - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + public void LogWithoutTitle(IEnumerable message) + { + LogImpl(message.ToArray(), false); + } - if (_pane == null) + public void LogWithoutTitle(IEnumerable message) { - await SetPaneAsync(); + LogImpl(message.ToArray(), false); } - if (_pane != null) + public async Task ShowAsync() { - EnvDTE.Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput); - window.Activate(); - _pane.Activate(); + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + + if (_pane == null) + { + await SetPaneAsync(); + } + + if (_pane != null) + { + EnvDTE.Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput); + window.Activate(); + _pane.Activate(); + } } } } \ No newline at end of file diff --git a/SharedProject/Impl/NowForLog.cs b/SharedProject/Impl/NowForLog.cs new file mode 100644 index 00000000..b481cb7c --- /dev/null +++ b/SharedProject/Impl/NowForLog.cs @@ -0,0 +1,22 @@ +using System; +using System.Globalization; +using System.Text; + +namespace FineCodeCoverage.Output +{ + internal static class NowForLog + { + public static string Get() + { + var stringBuilder = new StringBuilder(); + DateTime now = DateTime.Now; + stringBuilder.Append('['); + stringBuilder.Append(now.ToString("d", CultureInfo.CurrentCulture)); + stringBuilder.Append(' '); + stringBuilder.Append(now.ToString("h:mm:ss.fff tt", CultureInfo.CurrentCulture)); + stringBuilder.Append(']'); + stringBuilder.Append(' '); + return stringBuilder.ToString(); + } + } +} diff --git a/SharedProject/Impl/StatusMarkerProvider.cs b/SharedProject/Impl/StatusMarkerProvider.cs new file mode 100644 index 00000000..9ad35eb1 --- /dev/null +++ b/SharedProject/Impl/StatusMarkerProvider.cs @@ -0,0 +1,11 @@ +namespace FineCodeCoverage.Output +{ + internal static class StatusMarkerProvider + { + internal static string Get(string status = "") + { + status = status == "" ? "" : $" {status} "; + return $"=================================={status.ToUpper()}=================================="; + } + } +} diff --git a/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs b/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs index cee62a97..0c892a7b 100644 --- a/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs +++ b/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs @@ -14,6 +14,7 @@ using System.Threading; using FineCodeCoverage.Core.Initialization; using FineCodeCoverage.Core.Utilities; +using FineCodeCoverage.Output; namespace FineCodeCoverage.Impl { @@ -29,7 +30,7 @@ internal class TestContainerDiscoverer : ITestContainerDiscoverer private readonly IFCCEngine fccEngine; private readonly ITestOperationStateInvocationManager testOperationStateInvocationManager; private readonly ITestOperationFactory testOperationFactory; - private readonly ILogger logger; + private readonly Output.ILogger logger; private readonly IAppOptionsProvider appOptionsProvider; private readonly IReportGeneratorUtil reportGeneratorUtil; private readonly IMsCodeCoverageRunSettingsService msCodeCoverageRunSettingsService; @@ -39,6 +40,7 @@ internal class TestContainerDiscoverer : ITestContainerDiscoverer private MsCodeCoverageCollectionStatus msCodeCoverageCollectionStatus; private bool runningInParallel; private IAppOptions settings; + private int coverageRunNumber = 1; internal Task initializeTask; @@ -58,7 +60,7 @@ public TestContainerDiscoverer ITestOperationStateInvocationManager testOperationStateInvocationManager, IPackageLoader packageLoader, ITestOperationFactory testOperationFactory, - ILogger logger, + Output.ILogger logger, IAppOptionsProvider appOptionsProvider, IReportGeneratorUtil reportGeneratorUtil, IMsCodeCoverageRunSettingsService msCodeCoverageRunSettingsService, @@ -94,6 +96,12 @@ private bool CoverageDisabled(IAppOptions settings) return !settings.Enabled && settings.DisabledNoCoverage; } + private void LogCoverageStarting() + { + CombinedLog(StatusMarkerProvider.Get($"Coverage Starting - {coverageRunNumber++}")); + reportGeneratorUtil.LogCoverageProcess("Full details in FCC Output Pane"); + } + private async Task TestExecutionStartingAsync(IOperation operation) { this.eventAggregator.SendMessage(new TestExecutionStartingMessage()); @@ -108,7 +116,7 @@ private async Task TestExecutionStartingAsync(IOperation operation) reportGeneratorUtil.EndOfCoverageRun(); return; } - + LogCoverageStarting(); msCodeCoverageCollectionStatus = await msCodeCoverageRunSettingsService.IsCollectingAsync(testOperationFactory.Create(operation)); if (msCodeCoverageCollectionStatus == MsCodeCoverageCollectionStatus.NotCollecting) { diff --git a/SharedProject/Impl/TestContainerDiscovery/TestOperationFactory.cs b/SharedProject/Impl/TestContainerDiscovery/TestOperationFactory.cs index 03215c39..12e04155 100644 --- a/SharedProject/Impl/TestContainerDiscovery/TestOperationFactory.cs +++ b/SharedProject/Impl/TestContainerDiscovery/TestOperationFactory.cs @@ -11,13 +11,13 @@ internal class TestOperationFactory : ITestOperationFactory { private readonly ICoverageProjectFactory coverageProjectFactory; private readonly IRunSettingsRetriever runSettingsRetriever; - private readonly ILogger logger; + private readonly Output.ILogger logger; [ImportingConstructor] public TestOperationFactory( ICoverageProjectFactory coverageProjectFactory, IRunSettingsRetriever runSettingsRetriever, - ILogger logger + Output.ILogger logger ) { this.coverageProjectFactory = coverageProjectFactory; diff --git a/SharedProject/Impl/TestContainerDiscovery/TestOperationStateInvocationManager.cs b/SharedProject/Impl/TestContainerDiscovery/TestOperationStateInvocationManager.cs index 9b0cd802..3e0edf16 100644 --- a/SharedProject/Impl/TestContainerDiscovery/TestOperationStateInvocationManager.cs +++ b/SharedProject/Impl/TestContainerDiscovery/TestOperationStateInvocationManager.cs @@ -8,13 +8,13 @@ namespace FineCodeCoverage.Impl internal class TestOperationStateInvocationManager : ITestOperationStateInvocationManager { private readonly IInitializeStatusProvider initializeStatusProvider; - private readonly ILogger logger; + private readonly Output.ILogger logger; private bool initializedWhenTestExecutionStarting; [ImportingConstructor] public TestOperationStateInvocationManager( IInitializeStatusProvider initializeStatusProvider, - ILogger logger + Output.ILogger logger ) { this.initializeStatusProvider = initializeStatusProvider; diff --git a/SharedProject/Options/AppOptionsProvider.cs b/SharedProject/Options/AppOptionsProvider.cs index 005fa566..5be2ad0f 100644 --- a/SharedProject/Options/AppOptionsProvider.cs +++ b/SharedProject/Options/AppOptionsProvider.cs @@ -2,6 +2,7 @@ using System.ComponentModel.Composition; using System.Reflection; using FineCodeCoverage.Core.Utilities; +using FineCodeCoverage.Output; using Microsoft.VisualStudio.Settings; namespace FineCodeCoverage.Options diff --git a/SharedProject/SharedProject.projitems b/SharedProject/SharedProject.projitems index 99505aa7..db733619 100644 --- a/SharedProject/SharedProject.projitems +++ b/SharedProject/SharedProject.projitems @@ -378,7 +378,9 @@ + + From cecb7026887343025cc7752bc57dc38aa1cf3d55 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 10:21:17 +0000 Subject: [PATCH 02/11] remove unnecessary method --- .../MsCodeCoverageRunSettingsService.cs | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs b/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs index 98f4af9c..376bc460 100644 --- a/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs +++ b/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs @@ -266,13 +266,11 @@ private async Task ProcessTemplateGenerationResultAsync(IProjectRunSettingsFromT private async Task CollectingWithTemplateAsync(IProjectRunSettingsFromTemplateResult generationResult, List coverageProjectsForShim) { coverageProjectsForShim.AddRange(generationResult.CoverageProjectsWithFCCMsTestAdapter); - await CombinedLogAsync(() => - { - var leadingMessage = generationResult.CustomTemplatePaths.Any() ? $"{msCodeCoverageMessage} - custom template paths" : msCodeCoverageMessage; - var loggerMessages = new List { leadingMessage }.Concat(generationResult.CustomTemplatePaths.Distinct()); - logger.Log(loggerMessages); - reportGeneratorUtil.LogCoverageProcess(msCodeCoverageMessage); - }); + await threadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + var leadingMessage = generationResult.CustomTemplatePaths.Any() ? $"{msCodeCoverageMessage} - custom template paths" : msCodeCoverageMessage; + var loggerMessages = new List { leadingMessage }.Concat(generationResult.CustomTemplatePaths.Distinct()); + logger.Log(loggerMessages); + reportGeneratorUtil.LogCoverageProcess(msCodeCoverageMessage); collectionStatus = MsCodeCoverageCollectionStatus.Collecting; } @@ -369,27 +367,17 @@ public void StopCoverage() #region Logging private async Task CombinedLogAsync(string message) - { - await CombinedLogAsync(() => - { - logger.Log(message); - reportGeneratorUtil.LogCoverageProcess(message); - }); - } - - private async Task CombinedLogAsync(Action action) { await threadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - action(); + logger.Log(message); + reportGeneratorUtil.LogCoverageProcess(message); } - private Task CombinedLogExceptionAsync(Exception ex, string reason) + private async Task CombinedLogExceptionAsync(Exception ex, string reason) { - return CombinedLogAsync(() => - { - logger.Log(reason, ex.ToString()); - reportGeneratorUtil.LogCoverageProcess(reason); - }); + await threadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + logger.Log(reason, ex.ToString()); + reportGeneratorUtil.LogCoverageProcess(reason); } #endregion From 97eeb80839e5dcc32fc4ac61af9f74464f3684d2 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 11:19:15 +0000 Subject: [PATCH 03/11] missing ILogger qualifications from previous commit --- FineCodeCoverageTests/AppOptionsProvider_Tests.cs | 1 + FineCodeCoverageTests/CoverageProject_Settings_Tests.cs | 1 + .../CoverageToolOutputManager_Tests.cs | 1 + FineCodeCoverageTests/CoverletConsole_Tests.cs | 1 + .../CoverletDataCollectorUtil_RunAsync_Tests.cs | 1 + FineCodeCoverageTests/DotNetToolList_Tests.cs | 1 + .../Editor/DynamicCoverage/BufferLineCoverage_Tests.cs | 1 + .../DynamicCoverage/ContainingCodeTrackedLinesBuilder_Tests.cs | 1 + FineCodeCoverageTests/Initializer_Tests.cs | 1 + .../MsCodeCoverageRunSettingsService_Collect_Tests.cs | 3 +-- .../MsCodeCoverageRunSettingsService_IsCollecting_Tests.cs | 1 + FineCodeCoverageTests/ProcessResponseProcessor_Tests.cs | 1 + 12 files changed, 12 insertions(+), 2 deletions(-) diff --git a/FineCodeCoverageTests/AppOptionsProvider_Tests.cs b/FineCodeCoverageTests/AppOptionsProvider_Tests.cs index 8dabaec3..add5da48 100644 --- a/FineCodeCoverageTests/AppOptionsProvider_Tests.cs +++ b/FineCodeCoverageTests/AppOptionsProvider_Tests.cs @@ -4,6 +4,7 @@ using AutoMoq; using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; using Microsoft.VisualStudio.Settings; using Moq; using NUnit.Framework; diff --git a/FineCodeCoverageTests/CoverageProject_Settings_Tests.cs b/FineCodeCoverageTests/CoverageProject_Settings_Tests.cs index 5da78298..357ad396 100644 --- a/FineCodeCoverageTests/CoverageProject_Settings_Tests.cs +++ b/FineCodeCoverageTests/CoverageProject_Settings_Tests.cs @@ -2,6 +2,7 @@ using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; using FineCodeCoverageTests.TestHelpers; using Moq; using NUnit.Framework; diff --git a/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs b/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs index 38981f3a..6cd90416 100644 --- a/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs +++ b/FineCodeCoverageTests/CoverageToolOutput_Tests/CoverageToolOutputManager_Tests.cs @@ -5,6 +5,7 @@ using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Engine; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; using Moq; using NUnit.Framework; using SharedProject.Core.CoverageToolOutput; diff --git a/FineCodeCoverageTests/CoverletConsole_Tests.cs b/FineCodeCoverageTests/CoverletConsole_Tests.cs index 62a6b734..e8821f96 100644 --- a/FineCodeCoverageTests/CoverletConsole_Tests.cs +++ b/FineCodeCoverageTests/CoverletConsole_Tests.cs @@ -9,6 +9,7 @@ using FineCodeCoverage.Engine.Coverlet; using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; using Moq; using NUnit.Framework; diff --git a/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs b/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs index 537d6192..575f0dc0 100644 --- a/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs +++ b/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs @@ -10,6 +10,7 @@ using FineCodeCoverage.Engine.Coverlet; using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; using Moq; using NUnit.Framework; diff --git a/FineCodeCoverageTests/DotNetToolList_Tests.cs b/FineCodeCoverageTests/DotNetToolList_Tests.cs index 36c6ffc3..95807cc4 100644 --- a/FineCodeCoverageTests/DotNetToolList_Tests.cs +++ b/FineCodeCoverageTests/DotNetToolList_Tests.cs @@ -2,6 +2,7 @@ using AutoMoq; using FineCodeCoverage.Core.Utilities; using FineCodeCoverage.Engine.Coverlet; +using FineCodeCoverage.Output; using NUnit.Framework; namespace FineCodeCoverageTests diff --git a/FineCodeCoverageTests/Editor/DynamicCoverage/BufferLineCoverage_Tests.cs b/FineCodeCoverageTests/Editor/DynamicCoverage/BufferLineCoverage_Tests.cs index 9908aee9..42d09185 100644 --- a/FineCodeCoverageTests/Editor/DynamicCoverage/BufferLineCoverage_Tests.cs +++ b/FineCodeCoverageTests/Editor/DynamicCoverage/BufferLineCoverage_Tests.cs @@ -6,6 +6,7 @@ using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Impl; using FineCodeCoverage.Options; +using FineCodeCoverage.Output; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Editor; using Moq; diff --git a/FineCodeCoverageTests/Editor/DynamicCoverage/ContainingCodeTrackedLinesBuilder_Tests.cs b/FineCodeCoverageTests/Editor/DynamicCoverage/ContainingCodeTrackedLinesBuilder_Tests.cs index 5a5a55f2..13746f5e 100644 --- a/FineCodeCoverageTests/Editor/DynamicCoverage/ContainingCodeTrackedLinesBuilder_Tests.cs +++ b/FineCodeCoverageTests/Editor/DynamicCoverage/ContainingCodeTrackedLinesBuilder_Tests.cs @@ -3,6 +3,7 @@ using FineCodeCoverage.Editor.DynamicCoverage; using FineCodeCoverage.Editor.DynamicCoverage.TrackedLinesImpl.Construction; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; using FineCodeCoverageTests.TestHelpers; using Microsoft.VisualStudio.Text; using Moq; diff --git a/FineCodeCoverageTests/Initializer_Tests.cs b/FineCodeCoverageTests/Initializer_Tests.cs index 613d081f..3895ab15 100644 --- a/FineCodeCoverageTests/Initializer_Tests.cs +++ b/FineCodeCoverageTests/Initializer_Tests.cs @@ -8,6 +8,7 @@ using FineCodeCoverage.Core.Initialization; using FineCodeCoverage.Engine; using FineCodeCoverage.Engine.Model; +using FineCodeCoverage.Output; using Moq; using NUnit.Framework; diff --git a/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_Collect_Tests.cs b/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_Collect_Tests.cs index a1019c17..d8af43ba 100644 --- a/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_Collect_Tests.cs +++ b/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_Collect_Tests.cs @@ -18,7 +18,6 @@ namespace FineCodeCoverageTests.MsCodeCoverage { - internal class MsCodeCoverageRunSettingsService_Test_Execution_Not_Finished_Tests { [Test] @@ -126,7 +125,7 @@ public async Task Should_Not_Throw_If_No_Results_Async() public async Task Should_Combined_Log_When_No_Cobertura_Files_Async() { await RunAndProcessReportAsync(null, Array.Empty()); - autoMocker.Verify(logger => logger.Log("No cobertura files for ms code coverage.")); + autoMocker.Verify(logger => logger.Log("No cobertura files for ms code coverage.")); autoMocker.Verify( reportGenerator => reportGenerator.LogCoverageProcess("No cobertura files for ms code coverage.") ); diff --git a/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_IsCollecting_Tests.cs b/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_IsCollecting_Tests.cs index 9573963b..d240a3a2 100644 --- a/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_IsCollecting_Tests.cs +++ b/FineCodeCoverageTests/MsCodeCoverage/MsCodeCoverageRunSettingsService_IsCollecting_Tests.cs @@ -15,6 +15,7 @@ using FineCodeCoverage.Core.Utilities; using System.IO; using System; +using FineCodeCoverage.Output; namespace FineCodeCoverageTests.MsCodeCoverage { diff --git a/FineCodeCoverageTests/ProcessResponseProcessor_Tests.cs b/FineCodeCoverageTests/ProcessResponseProcessor_Tests.cs index ce8d7cc4..f03ae0cf 100644 --- a/FineCodeCoverageTests/ProcessResponseProcessor_Tests.cs +++ b/FineCodeCoverageTests/ProcessResponseProcessor_Tests.cs @@ -1,6 +1,7 @@ using System; using AutoMoq; using FineCodeCoverage.Core.Utilities; +using FineCodeCoverage.Output; using NUnit.Framework; namespace Test From 2228f443508b7859781884bff2e42253cc1139df Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 11:29:03 +0000 Subject: [PATCH 04/11] Make ms code coverage the default --- FineCodeCoverageTests/AppOptionsProvider_Tests.cs | 1 + README.md | 6 ++---- .../CodeCoverage/MsCodeCoverageRunSettingsService.cs | 7 +------ SharedProject/Options/AppOptionsPage.cs | 2 +- SharedProject/Options/AppOptionsProvider.cs | 1 + 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/FineCodeCoverageTests/AppOptionsProvider_Tests.cs b/FineCodeCoverageTests/AppOptionsProvider_Tests.cs index add5da48..c983fa50 100644 --- a/FineCodeCoverageTests/AppOptionsProvider_Tests.cs +++ b/FineCodeCoverageTests/AppOptionsProvider_Tests.cs @@ -200,6 +200,7 @@ public void Should_Not_Default_Any_Other_AppOptions_Properties() nameof(IAppOptions.ThresholdForCrapScore), nameof(IAppOptions.ThresholdForNPathComplexity), nameof(IAppOptions.ThresholdForCyclomaticComplexity), + nameof(IAppOptions.RunMsCodeCoverage), nameof(IAppOptions.NamespacedClasses), nameof(IAppOptions.ShowCoverageInOverviewMargin), nameof(IAppOptions.ShowCoveredInOverviewMargin), diff --git a/README.md b/README.md index 263bd889..bff50711 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ When not using Microsoft.TestingPlatform you have added test adapters through nu Fine Code Coverage provides code coverage using one of 3 different coverage tools. In previous releases there were two coverage tools being utilised, OpenCover and Coverlet that will be referred to as 'old coverage'. Microsoft now provides a free coverage solution that you can choose to use by setting the Visual Studio Fine Code Coverage enumeration option RunMsCodeCoverage. This will probably be the preferred coverage -tool for most developers. It is currently in Beta. +tool for most developers. With the old coverage it was possible for FCC to provide an abstraction over each tool's exclusion / inclusion options. This abstraction does not work for MS code coverage. Thus you will find that there are separate configuration options for Ms coverage vs old coverage and options that are common to the two. @@ -109,8 +109,6 @@ The old coverage was based upon every test. Ms code coverage is coverage from th ## How to utilize MS Code Coverage with FCC ? -Firstly you need to change the RunMsCodeCoverage option from No. - Ms code coverage requires a [runsettings](https://docs.microsoft.com/en-us/visualstudio/test/configure-unit-tests-by-using-a-dot-runsettings-file?view=vs-2022) file that is configured appropriately for code coverage. This requires that you have the ms code coverage package and have pointed to it with the TestAdaptersPaths element as well as specifying the ms data collector. [Exclusions and inclusions](https://docs.microsoft.com/en-us/visualstudio/test/customizing-code-coverage-analysis?view=vs-2022#include-or-exclude-assemblies-and-members) are also specified in the runsettings. I don't think that the documentation is clear enough on how this works so you may want to look at [this issue](https://github.com/microsoft/vstest/issues/3462). @@ -349,7 +347,7 @@ If you are using option 1) then project and global options will only be used whe | DisabledNoCoverage | Set to false for VS Option Enabled=false to not disable coverage | | RunWhenTestsFail | By default coverage runs when tests fail. Set to false to prevent this. **Cannot be used in conjunction with RunInParallel** | | RunWhenTestsExceed | Specify a value to only run coverage based upon the number of executing tests. **Cannot be used in conjunction with RunInParallel** | -| RunMsCodeCoverage | Change to IfInRunSettings to only collect with configured runsettings. Yes for runsettings generation. | +| RunMsCodeCoverage | Change to IfInRunSettings to only collect with configured runsettings. Yes (default) for runsettings generation. No to use Coverlet or OpenCover. | | IncludeTestAssembly | Specifies whether to report code coverage of the test assembly | | IncludeReferencedProjects | Set to true to add all directly referenced projects to Include. | | IncludeAssemblies | Provide a list of assemblies to include in coverage. The dll name without extension is used for matching. | diff --git a/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs b/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs index 376bc460..a2afed0d 100644 --- a/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs +++ b/SharedProject/Core/MsTestPlatform/CodeCoverage/MsCodeCoverageRunSettingsService.cs @@ -121,12 +121,7 @@ public void Initialize(string appDataFolder, IFCCEngine fccEngine, CancellationT public async Task IsCollectingAsync(ITestOperation testOperation) { await InitializeIsCollectingAsync(testOperation); - if( runMsCodeCoverage == RunMsCodeCoverage.No) - { - logger.Log($"See option {nameof(IAppOptions.RunMsCodeCoverage)} for a better ( Beta ) experience. {FCCGithub.Readme}"); - reportGeneratorUtil.LogCoverageProcess($"See option {nameof(IAppOptions.RunMsCodeCoverage)} for a better ( Beta ) experience. View readme."); - } - else + if( runMsCodeCoverage != RunMsCodeCoverage.No) { await TrySetUpForCollectionAsync(testOperation.SolutionDirectory); } diff --git a/SharedProject/Options/AppOptionsPage.cs b/SharedProject/Options/AppOptionsPage.cs index dfa31db9..d25645fb 100644 --- a/SharedProject/Options/AppOptionsPage.cs +++ b/SharedProject/Options/AppOptionsPage.cs @@ -75,7 +75,7 @@ private static IAppOptionsStorageProvider GetAppOptionsStorageProvider() public bool DisabledNoCoverage { get; set; } [Category(commonRunCategory)] - [Description("Specifies whether or not the ms code coverage is used (BETA). No, IfInRunSettings, Yes")] + [Description("Specifies whether or not the ms code coverage is used. No, IfInRunSettings, Yes ( default )")] //[DisplayName("Run Ms Code Coverage)")] public RunMsCodeCoverage RunMsCodeCoverage { get; set; } diff --git a/SharedProject/Options/AppOptionsProvider.cs b/SharedProject/Options/AppOptionsProvider.cs index 5be2ad0f..a64552f3 100644 --- a/SharedProject/Options/AppOptionsProvider.cs +++ b/SharedProject/Options/AppOptionsProvider.cs @@ -60,6 +60,7 @@ private void AddDefaults(IAppOptions appOptions) appOptions.ThresholdForCrapScore = 15; appOptions.ThresholdForNPathComplexity = 200; appOptions.ThresholdForCyclomaticComplexity = 30; + appOptions.RunMsCodeCoverage = RunMsCodeCoverage.Yes; appOptions.RunSettingsOnly = true; appOptions.RunWhenTestsFail = true; appOptions.ExcludeByAttribute = new[] { "GeneratedCode" }; From 7c80805f1f902e39265c046dddf77b4532a2faee Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 11:31:28 +0000 Subject: [PATCH 05/11] remove commented old code --- SharedProject/Impl/Logger.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/SharedProject/Impl/Logger.cs b/SharedProject/Impl/Logger.cs index bac5fbd8..80e0d556 100644 --- a/SharedProject/Impl/Logger.cs +++ b/SharedProject/Impl/Logger.cs @@ -60,7 +60,6 @@ private void LogImpl(object[] message, bool withTitle) { try { - //var logTime = DateTime.Now; var logTime = NowForLog.Get(); var messageList = new List(message?.Select(x => x?.ToString()?.Trim(' ', '\r', '\n')).Where(x => !string.IsNullOrWhiteSpace(x))); @@ -87,7 +86,6 @@ private void LogImpl(object[] message, bool withTitle) if (withTitle) { - //_pane.OutputStringThreadSafe($"{Vsix.Name} {logTime}: {logs}{Environment.NewLine}"); _pane.OutputStringThreadSafe($"{logTime}: {logs}{Environment.NewLine}"); } else From 3fe7dbdf4623c80963050d727336beddd11ab481 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 11:47:05 +0000 Subject: [PATCH 06/11] file sync header --- SharedProject/Core/FCCEngine.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/SharedProject/Core/FCCEngine.cs b/SharedProject/Core/FCCEngine.cs index afd9bce5..09b70512 100644 --- a/SharedProject/Core/FCCEngine.cs +++ b/SharedProject/Core/FCCEngine.cs @@ -267,6 +267,7 @@ private async System.Threading.Tasks.Task PrepareCoverageProjectsAsync(List Date: Sun, 2 Mar 2025 12:22:25 +0000 Subject: [PATCH 07/11] remove unnecessary duplication of report generator ouput --- SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs b/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs index c6d9f6c1..6fe962fc 100644 --- a/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs +++ b/SharedProject/Core/ReportGenerator/ReportGeneratorUtil.cs @@ -180,8 +180,6 @@ async Task RunAsync(string outputReportType, string inputReports) 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 { @@ -198,7 +196,7 @@ async Task RunAsync(string outputReportType, string inputReports) throw new Exception(result.Output); } - logger.Log($"{title} [reporttype:{outputReportType}]", result.Output); + logger.Log($"{title} [reporttype:{outputReportType}] Output", result.Output); } From 1452682cd3150a98292b7a2578891279b9730798 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 12:31:05 +0000 Subject: [PATCH 08/11] reduce length of tab start message --- .../Impl/TestContainerDiscovery/TestContainerDiscoverer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs b/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs index 0c892a7b..46fc205b 100644 --- a/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs +++ b/SharedProject/Impl/TestContainerDiscovery/TestContainerDiscoverer.cs @@ -98,7 +98,9 @@ private bool CoverageDisabled(IAppOptions settings) private void LogCoverageStarting() { - CombinedLog(StatusMarkerProvider.Get($"Coverage Starting - {coverageRunNumber++}")); + var coverageStartingMessage = $"Coverage Starting - {coverageRunNumber++}"; + logger.Log(StatusMarkerProvider.Get(coverageStartingMessage)); + reportGeneratorUtil.LogCoverageProcess($"-- {coverageStartingMessage} --"); reportGeneratorUtil.LogCoverageProcess("Full details in FCC Output Pane"); } From 2c4cdf7c82617a6866b1c2981cd20d04bcfb4ea9 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 13:08:41 +0000 Subject: [PATCH 09/11] remove duplicate opencover / coverlet message --- SharedProject/Core/CoverageUtilManager.cs | 5 +---- .../DataCollector/DataCollectorSettingsBuilder.cs | 10 +--------- .../DataCollectorSettingsBuilderFactory.cs | 11 +---------- SharedProject/Core/FCCEngine.cs | 1 - 4 files changed, 3 insertions(+), 24 deletions(-) diff --git a/SharedProject/Core/CoverageUtilManager.cs b/SharedProject/Core/CoverageUtilManager.cs index 4078f38d..0dfe7ad6 100644 --- a/SharedProject/Core/CoverageUtilManager.cs +++ b/SharedProject/Core/CoverageUtilManager.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; +using System.ComponentModel.Composition; using System.Threading; using System.Threading.Tasks; using FineCodeCoverage.Engine.Coverlet; using FineCodeCoverage.Engine.Model; using FineCodeCoverage.Engine.OpenCover; -using FineCodeCoverage.Engine.ReportGenerator; namespace FineCodeCoverage.Engine { diff --git a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs index 99af1d52..a941051e 100644 --- a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs +++ b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilder.cs @@ -1,9 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.Composition; using System.Linq; using System.Xml.Linq; -using FineCodeCoverage.Output; namespace FineCodeCoverage.Engine.Coverlet { @@ -13,12 +11,7 @@ internal class DataCollectorSettingsBuilder : IDataCollectorSettingsBuilder private string generatedRunSettingsPath; private string existingRunSettings; private bool runSettingsOnly; - private readonly ILogger logger; - public DataCollectorSettingsBuilder(ILogger logger) - { - this.logger = logger; - } #region Arguments internal string ProjectDll { get; set; } internal string Blame { get; set; } @@ -71,7 +64,6 @@ public string Build() private void GenerateRunSettings() { var runSettingsDocument = existingRunSettings == null ? GenerateFullRunSettings() : GenerateRunSettingsFromExisting(); - logger.Log($"Saving run settings to {generatedRunSettingsPath}"); runSettingsDocument.Save(generatedRunSettingsPath); } diff --git a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs index 2af1f21f..ab99d916 100644 --- a/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs +++ b/SharedProject/Core/Coverlet/DataCollector/DataCollectorSettingsBuilderFactory.cs @@ -1,22 +1,13 @@ using System.ComponentModel.Composition; using FineCodeCoverage.Options; -using FineCodeCoverage.Output; - 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(logger); + return new DataCollectorSettingsBuilder(); } } } diff --git a/SharedProject/Core/FCCEngine.cs b/SharedProject/Core/FCCEngine.cs index 09b70512..1c28e405 100644 --- a/SharedProject/Core/FCCEngine.cs +++ b/SharedProject/Core/FCCEngine.cs @@ -171,7 +171,6 @@ await coverageProject.StepAsync("Run Coverage Tool", async (project) => var coverageTool = coverageUtilManager.CoverageToolName(project); var runCoverToolMessage = $"Run {coverageTool} ({project.ProjectName})"; - logger.Log(runCoverToolMessage); reportGeneratorUtil.LogCoverageProcess(runCoverToolMessage); await coverageUtilManager.RunCoverageAsync(project, vsShutdownLinkedCancellationToken); From e2a8eb3c7ce8a309b56d418c51cf672255756194 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 13:21:07 +0000 Subject: [PATCH 10/11] consistent Output in header - clear that does not come from FCC --- .../CoverletDataCollectorUtil_RunAsync_Tests.cs | 2 +- .../Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs | 2 +- SharedProject/Core/OpenCover/OpenCoverUtil.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs b/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs index 575f0dc0..6f071370 100644 --- a/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs +++ b/FineCodeCoverageTests/CoverletDataCollectorUtil_RunAsync_Tests.cs @@ -280,7 +280,7 @@ public async Task Should_Use_The_ProcessResponseProcessor_Async() mockProcesUtil.Setup(p => p.ExecuteAsync(It.IsAny(), ct).Result).Returns(executeResponse); var mockProcessResponseProcessor = mocker.GetMock(); - var logTitle = "Coverlet Collector Run (TestProject)"; + var logTitle = "Coverlet Collector Run (TestProject) - Output"; mockProcessResponseProcessor.Setup(rp => rp.Process(executeResponse, It.IsAny>(), true, logTitle, It.IsAny())); await coverletDataCollectorUtil.RunAsync(ct); diff --git a/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs b/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs index bd9b3a7b..d7b3032b 100644 --- a/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs +++ b/SharedProject/Core/Coverlet/DataCollector/CoverletDataCollectorUtil.cs @@ -260,7 +260,7 @@ public async Task RunAsync(CancellationToken cancellationToken) // 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(), () => + processResponseProcessor.Process(result, code => code == 0 || code == 1, true, $"{GetLogTitle()} - Output", () => { coverletDataCollectorGeneratedCobertura.CorrectPath(coverageProject.CoverageOutputFolder, coverageProject.CoverageOutputFile); }); diff --git a/SharedProject/Core/OpenCover/OpenCoverUtil.cs b/SharedProject/Core/OpenCover/OpenCoverUtil.cs index edc61d1e..36753453 100644 --- a/SharedProject/Core/OpenCover/OpenCoverUtil.cs +++ b/SharedProject/Core/OpenCover/OpenCoverUtil.cs @@ -97,7 +97,7 @@ public async Task RunOpenCoverAsync(ICoverageProject project, CancellationToken throw new Exception(result.Output); } - logger.Log(title, result.Output); + logger.Log($"{title} - Output", result.Output); } } } From 1aca674d57836b63a4711061a30192d0eee05feb Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sun, 2 Mar 2025 13:42:36 +0000 Subject: [PATCH 11/11] Test that TestContainerDiscoverer logs coverage starting with run number --- .../TestContainerDiscovery_Tests.cs | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs b/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs index 6890e120..d76d22ce 100644 --- a/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs +++ b/FineCodeCoverageTests/TestContainerDiscovery_Tests.cs @@ -13,11 +13,9 @@ using Microsoft.VisualStudio.TestWindow.Extensibility; using Moq; using NUnit.Framework; -using FineCodeCoverage.Output; namespace Test { - internal class TestOperationStateInvocationManager_Tests { private AutoMoqer mocker; @@ -428,5 +426,42 @@ public void Should_MsCodeCoverageRunSettingsService_TestExecutionNotFinishedAsyn mockMsCodeCoverageRunSettingsService.Verify(msCodeCoverageRunSettingsService => msCodeCoverageRunSettingsService.TestExecutionNotFinishedAsync(mockTestOperation.Object)); } + + [Test] + public void Should_Log_Coverage_Starting_With_Run_Number_When_TestExecutionStartingAsync_And_Coverage_Not_Disabled() + { + SetUpOptions(mockAppOptions => + { + mockAppOptions.Setup(o => o.Enabled).Returns(true); + }); + + var operation = new Mock().Object; + RaiseTestExecutionStarting(operation); + + mocker.Verify( + logger => logger.Log("================================== COVERAGE STARTING - 1 ==================================")); + + RaiseTestExecutionStarting(operation); + + mocker.Verify( + logger => logger.Log("================================== COVERAGE STARTING - 2 ==================================")); + } + + [Test] + public void Should_Not_Log_Coverage_Starting_When_Coverage_Disabled() + { + SetUpOptions(mockAppOptions => + { + mockAppOptions.Setup(o => o.Enabled).Returns(false); + mockAppOptions.Setup(o => o.DisabledNoCoverage).Returns(true); + }); + + var operation = new Mock().Object; + RaiseTestExecutionStarting(operation); + + mocker.Verify( + logger => logger.Log("================================== COVERAGE STARTING - 1 =================================="), Times.Never()); + + } } } \ No newline at end of file