diff --git a/FineCodeCoverage/Core/Coverlet/CoverletUtil.cs b/FineCodeCoverage/Core/Coverlet/CoverletUtil.cs index 4beb7e35..e87c6523 100644 --- a/FineCodeCoverage/Core/Coverlet/CoverletUtil.cs +++ b/FineCodeCoverage/Core/Coverlet/CoverletUtil.cs @@ -212,7 +212,8 @@ public static bool RunCoverlet(CoverageProject project, bool throwError = false) coverletSettings.Add($@"--output ""{ project.CoverageOutputFile }"""); - coverletSettings.Add($@"--targetargs ""test """"{project.TestDllFile}"""" --nologo --blame --results-directory """"{project.CoverageOutputFolder}"""" --diag """"{project.CoverageOutputFolder}/diagnostics.log"""" """); + var runSettings = !string.IsNullOrWhiteSpace(project.RunSettingsFile) ? $@"--settings """"{project.RunSettingsFile}""""" : default; + coverletSettings.Add($@"--targetargs ""test """"{project.TestDllFile}"""" --nologo --blame {runSettings} --results-directory """"{project.CoverageOutputFolder}"""" --diag """"{project.CoverageOutputFolder}/diagnostics.log"""" """); Logger.Log($"{title} Arguments {Environment.NewLine}{string.Join($"{Environment.NewLine}", coverletSettings)}"); diff --git a/FineCodeCoverage/Core/Model/CoverageProject.cs b/FineCodeCoverage/Core/Model/CoverageProject.cs index ed00c016..4ee1670b 100644 --- a/FineCodeCoverage/Core/Model/CoverageProject.cs +++ b/FineCodeCoverage/Core/Model/CoverageProject.cs @@ -28,6 +28,7 @@ internal class CoverageProject public bool HasExcludeFromCodeCoverageAssemblyAttribute { get; set; } public string AssemblyName { get; set; } public bool Is64Bit { get; set; } + public string RunSettingsFile { get; set; } public CoverageProject Step(string stepName, Action action) { diff --git a/FineCodeCoverage/Core/OpenCover/OpenCoverUtil.cs b/FineCodeCoverage/Core/OpenCover/OpenCoverUtil.cs index ed4b1768..f92a7775 100644 --- a/FineCodeCoverage/Core/OpenCover/OpenCoverUtil.cs +++ b/FineCodeCoverage/Core/OpenCover/OpenCoverUtil.cs @@ -284,7 +284,8 @@ public static bool RunOpenCover(CoverageProject project, bool throwError = false //filters.Add($@"-[{nameOnlyOfDll}]*"); } - opencoverSettings.Add($@" ""-targetargs:\""{project.TestDllFile}\"""" "); + var runSettings = !string.IsNullOrWhiteSpace(project.RunSettingsFile) ? $@"/Settings:\""{project.RunSettingsFile}\""" : default; + opencoverSettings.Add($@" ""-targetargs:\""{project.TestDllFile}\"" {runSettings}"" "); opencoverSettings.Add($@" ""-output:{ project.CoverageOutputFile }"" "); diff --git a/FineCodeCoverage/FineCodeCoverage.csproj b/FineCodeCoverage/FineCodeCoverage.csproj index a5fd6071..9b7dd3d6 100644 --- a/FineCodeCoverage/FineCodeCoverage.csproj +++ b/FineCodeCoverage/FineCodeCoverage.csproj @@ -75,6 +75,7 @@ + diff --git a/FineCodeCoverage/Impl/RunSettingsRetriever.cs b/FineCodeCoverage/Impl/RunSettingsRetriever.cs new file mode 100644 index 00000000..2362a88a --- /dev/null +++ b/FineCodeCoverage/Impl/RunSettingsRetriever.cs @@ -0,0 +1,72 @@ +using System.Reflection; +using System.Threading.Tasks; + +namespace FineCodeCoverage.Impl +{ + internal class RunSettingsRetriever + { + private object userSettings; + + public async Task GetRunSettingsFileAsync(object userSettings, object testContainer) + { + this.userSettings = userSettings; + + var runSettingsFile = GetDefaultRunSettingsFilePath(); + var projectRunSettingsFile = await GetProjectRunSettingFileAsync(testContainer); + + if (!string.IsNullOrEmpty(projectRunSettingsFile)) + { + return projectRunSettingsFile; + } + + return runSettingsFile; + } + + private string GetAndUpdateSolutionRunSettingsFilePath() + { + return userSettings.GetType().GetMethod("GetAndUpdateSolutionRunSettingsFilePath", BindingFlags.Public | BindingFlags.Instance).Invoke(userSettings, new object[] { }) as string; + } + + private string LastRunSettingsFilePath() + { + return userSettings.GetType().GetProperty("LastRunSettingsFilePath", BindingFlags.Public | BindingFlags.Instance).GetValue(userSettings) as string; + } + + private bool AutomaticallyDetectRunSettings() + { + return (bool)userSettings.GetType().GetProperty("AutomaticallyDetectRunSettings", BindingFlags.Public | BindingFlags.Instance).GetValue(userSettings); + } + + private string GetDefaultRunSettingsFilePath() + { + string settingsFilePath = GetAndUpdateSolutionRunSettingsFilePath(); + var lastRunSettingsFilePath = LastRunSettingsFilePath(); + + if (!string.IsNullOrEmpty(lastRunSettingsFilePath)) + { + return lastRunSettingsFilePath; + } + + if (!AutomaticallyDetectRunSettings() || string.IsNullOrEmpty(settingsFilePath)) + { + return null; + } + + return settingsFilePath; + } + + private static async Task GetProjectRunSettingFileAsync(object container) + { + var projectDataProperty = container.GetType().GetProperty("ProjectData"); + + if (projectDataProperty != null) + { + var projectData = projectDataProperty.GetValue(container); + var projectRunSettingsFile = await (projectData.GetType().GetMethod("GetBuildPropertyAsync", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(projectData, new object[] { "RunSettingsFilePath", (string)null }) as Task); + return projectRunSettingsFile; + } + + return null; + } + } +} diff --git a/FineCodeCoverage/Impl/TestContainerDiscoverer.cs b/FineCodeCoverage/Impl/TestContainerDiscoverer.cs index 06986045..a827e7a0 100644 --- a/FineCodeCoverage/Impl/TestContainerDiscoverer.cs +++ b/FineCodeCoverage/Impl/TestContainerDiscoverer.cs @@ -124,6 +124,7 @@ private void StopCoverageProcess() } } + [SuppressMessage("Usage", "VSTHRD102:Implement internal logic asynchronously")] private void OperationState_StateChanged(object sender, OperationStateChangedEventArgs e) { try @@ -150,6 +151,8 @@ private void OperationState_StateChanged(object sender, OperationStateChangedEve var operationType = e.Operation.GetType(); var darkMode = CurrentTheme.Equals("Dark", StringComparison.OrdinalIgnoreCase); var testConfiguration = (operationType.GetProperty("Configuration") ?? operationType.GetProperty("Configuration", BindingFlags.Instance | BindingFlags.NonPublic)).GetValue(e.Operation); + var userRunSettings = testConfiguration.GetType().GetProperty("UserRunSettings", BindingFlags.Instance | BindingFlags.Public).GetValue(testConfiguration); + var runSettingsRetriever = new RunSettingsRetriever(); var testContainers = ((IEnumerable)testConfiguration.GetType().GetProperty("Containers").GetValue(testConfiguration)).ToArray(); var projects = new List(); @@ -165,6 +168,7 @@ private void OperationState_StateChanged(object sender, OperationStateChangedEve project.TestDllFile = containerType.GetProperty("Source").GetValue(container).ToString(); project.Is64Bit = containerType.GetProperty("TargetPlatform").GetValue(container).ToString().ToLower().Equals("x64"); project.ProjectFile = containerDataType.GetProperty("ProjectFilePath", BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic).GetValue(containerData).ToString(); + project.RunSettingsFile = ThreadHelper.JoinableTaskFactory.Run(() => runSettingsRetriever.GetRunSettingsFileAsync(userRunSettings, container)); try {