From db9b35380b7c0a7efd780cf162d93beefd540080 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 17 Sep 2023 18:10:33 -0700 Subject: [PATCH 01/15] Bump up to v2.5.2-pre --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 0ef106d..c96c975 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.5.1", + "version": "2.5.2-pre.{height}", "nuGetPackageVersion": { "semVer": 2.0 }, From 341f5a68fe82161be226c324b09232295e23c6d7 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Tue, 19 Sep 2023 20:21:49 -0700 Subject: [PATCH 02/15] Remove signing --- Directory.build.props | 2 -- src/signing.snk | Bin 596 -> 0 bytes 2 files changed, 2 deletions(-) delete mode 100644 src/signing.snk diff --git a/Directory.build.props b/Directory.build.props index a8fa64d..be27ab5 100644 --- a/Directory.build.props +++ b/Directory.build.props @@ -14,8 +14,6 @@ https://github.com/xunit/visualstudio.xunit embedded latest - true - $(MSBuildThisFileDirectory)src/signing.snk diff --git a/src/signing.snk b/src/signing.snk deleted file mode 100644 index 93641b9761c08f6b592aba340776edc14a5ec27d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50096cE(Dt0>WA|Wnbz%&ycnCnTa1xtc3tp~ zhTtJYaomZ7PajL1N+yX-0+eNhhjF}hkL@5g5`gWZBdPXE;9p3yAms4k3_^n4a2}Xf z5xg_Cx#p`sud8ggjv@}?xZza=bKpOU)@8s^#y`AMS=5!(vBnT2?{@8+9=k^$?ODm$ zWzI_^s25nW&CvR}S&P!2&ZB4N_L#Bxt@EFD=y5Fj=s4UxLB%ePo^~{;)v(Tyx_B6H;!$eo`L}NQ8Hjnl$HRmpx7?cObLFYs zB*ORoG(%TSO@WQSzsG^hUUVV}m&v62&_vu^YSumrlYBl~dZs@`S2y_v zlAg!IY~H)v;BzX&THDP^!87KeV^ZJ&J87PMX}O^B)9Oop7vK5U_XVQg`9v;vM9Px^ zoj3JO}ZN;?jXV=KovW8!n$BBD25zO*C8fL3H5eJ^OCXCEAGC@JE zZfPW78wpVX&NicmbZ!=5_AN&=L3C7_9Gqvg`l2~J$2vW>MD8WY4XIy3@l)ze%64QI i@n`^|4l~$$Df`THrXhhM*WhbjYjkP&G#gZfW1qZXj4Ag3 From 15208e0fc5a6f413ca5149377cb285b24ee5ccae Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Tue, 19 Sep 2023 20:38:24 -0700 Subject: [PATCH 03/15] #384: Built-in reporters missing after ILRepack --- src/xunit.runner.visualstudio/VsTestRunner.cs | 27 ++++++++++++++++++- .../test.testcasefilter.csproj | 24 +++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/xunit.runner.visualstudio/VsTestRunner.cs b/src/xunit.runner.visualstudio/VsTestRunner.cs index 4f94f96..76d78d7 100644 --- a/src/xunit.runner.visualstudio/VsTestRunner.cs +++ b/src/xunit.runner.visualstudio/VsTestRunner.cs @@ -617,13 +617,14 @@ public static IReadOnlyList GetAvailableRunnerReporters( IReadOnlyList sources) { var result = new List(); + var adapterAssembly = typeof(VsTestRunner).Assembly; // We need to combine the source folders with our folder to find all potential runners var folders = sources .Select(s => Path.GetDirectoryName(Path.GetFullPath(s))) .WhereNotNull() - .Concat(new[] { Path.GetDirectoryName(typeof(VsTestRunner).Assembly.GetLocalCodeBase()) }) + .Concat(new[] { Path.GetDirectoryName(adapterAssembly.GetLocalCodeBase()) }) .Distinct(); foreach (var folder in folders) @@ -635,6 +636,30 @@ public static IReadOnlyList GetAvailableRunnerReporters( logger.LogWarning(message); } + // Look for runners that might be embedded in ourselves (because of ILRepack). This is what the code + // in RunnerReporterUtility.GetAvailableRunnerReporters does after it finds a target assembly. + foreach (var type in adapterAssembly.GetTypes()) + { + if (type is null || type.IsAbstract || !type.GetInterfaces().Any(t => t == typeof(IRunnerReporter))) + continue; + + try + { + var ctor = type.GetConstructor(new Type[0]); + if (ctor == null) + { + logger?.LogWarning($"Type '{type.FullName ?? type.Name}' in the adapter assembly appears to be a runner reporter, but does not have an empty constructor."); + continue; + } + + result.Add((IRunnerReporter)ctor.Invoke(new object[0])); + } + catch (Exception ex) + { + logger?.LogWarning($"Exception thrown while inspecting type '{type.FullName ?? type.Name}' in the adapter assembly:{Environment.NewLine}{ex}"); + } + } + return result; } diff --git a/test/test.testcasefilter/test.testcasefilter.csproj b/test/test.testcasefilter/test.testcasefilter.csproj index f52d5ce..af715a1 100644 --- a/test/test.testcasefilter/test.testcasefilter.csproj +++ b/test/test.testcasefilter/test.testcasefilter.csproj @@ -8,4 +8,28 @@ + + + + + + + + + + From 39744757ae187cf4455c4a6b7905328c9670d2f6 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 24 Sep 2023 15:37:40 -0700 Subject: [PATCH 04/15] Use 'is null' and 'is not null' --- .../Sinks/VsDiscoverySink.cs | 10 +++---- .../Sinks/VsExecutionSink.cs | 14 ++++----- .../Utility/AssemblyExtensions.cs | 2 +- .../AssemblyHelper_Desktop.cs | 4 +-- .../AssemblyHelper_NetCoreApp.cs | 12 ++++---- .../DependencyContextAssemblyCache.cs | 30 +++++++++---------- .../Utility/ExceptionExtensions.cs | 2 +- .../Utility/Guard.cs | 2 +- .../Utility/LoggerHelper.cs | 20 ++++++------- .../Utility/RunSettings.cs | 14 ++++----- .../Utility/TestCaseFilter.cs | 6 ++-- src/xunit.runner.visualstudio/VsTestRunner.cs | 24 +++++++-------- 12 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/xunit.runner.visualstudio/Sinks/VsDiscoverySink.cs b/src/xunit.runner.visualstudio/Sinks/VsDiscoverySink.cs index 07de6d3..8eca04d 100644 --- a/src/xunit.runner.visualstudio/Sinks/VsDiscoverySink.cs +++ b/src/xunit.runner.visualstudio/Sinks/VsDiscoverySink.cs @@ -86,7 +86,7 @@ public void Dispose() result.CodeFilePath = descriptor.SourceFileName; result.LineNumber = descriptor.SourceLineNumber.GetValueOrDefault(); - if (addTraitThunk != null) + if (addTraitThunk is not null) { var traits = descriptor.Traits; @@ -106,7 +106,7 @@ public void Dispose() static string Escape(string value) { - if (value == null) + if (value is null) return string.Empty; return Truncate(value.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t")); @@ -138,7 +138,7 @@ public int Finish() #else var property = testCaseType.GetProperty("Traits"); #endif - if (property == null) + if (property is null) return null; #if NETCOREAPP @@ -146,7 +146,7 @@ public int Finish() #else var method = property.PropertyType.GetMethod("Add", new[] { typeof(string), typeof(string) }); #endif - if (method == null) + if (method is null) return null; var thisParam = Expression.Parameter(testCaseType, "this"); @@ -210,7 +210,7 @@ private void SendExistingTestCases() foreach (var descriptor in descriptors) { var vsTestCase = CreateVsTestCase(source, descriptor, logger, testPlatformContext); - if (vsTestCase != null && testCaseFilter.MatchTestCase(vsTestCase)) + if (vsTestCase is not null && testCaseFilter.MatchTestCase(vsTestCase)) { if (discoveryOptions.GetInternalDiagnosticMessagesOrDefault()) logger.LogWithSource(source, "Discovered test case '{0}' (ID = '{1}', VS FQN = '{2}')", descriptor.DisplayName, descriptor.UniqueID, vsTestCase.FullyQualifiedName); diff --git a/src/xunit.runner.visualstudio/Sinks/VsExecutionSink.cs b/src/xunit.runner.visualstudio/Sinks/VsExecutionSink.cs index ccff00f..0732495 100644 --- a/src/xunit.runner.visualstudio/Sinks/VsExecutionSink.cs +++ b/src/xunit.runner.visualstudio/Sinks/VsExecutionSink.cs @@ -114,7 +114,7 @@ void HandleTestFailed(MessageHandlerArgs args) { var testFailed = args.Message; var result = MakeVsTestResult(TestOutcome.Failed, testFailed); - if (result != null) + if (result is not null) { result.ErrorMessage = ExceptionUtility.CombineMessages(testFailed); result.ErrorStackTrace = ExceptionUtility.CombineStackTraces(testFailed); @@ -131,7 +131,7 @@ void HandleTestPassed(MessageHandlerArgs args) { var testPassed = args.Message; var result = MakeVsTestResult(TestOutcome.Passed, testPassed); - if (result != null) + if (result is not null) TryAndReport("RecordResult (Pass)", testPassed.TestCase, () => recorder.RecordResult(result)); else logger.LogWarning(testPassed.TestCase, "(Pass) Could not find VS test case for {0} (ID = {1})", testPassed.TestCase.DisplayName, testPassed.TestCase.UniqueID); @@ -143,7 +143,7 @@ void HandleTestSkipped(MessageHandlerArgs args) { var testSkipped = args.Message; var result = MakeVsTestResult(TestOutcome.Skipped, testSkipped); - if (result != null) + if (result is not null) TryAndReport("RecordResult (Skip)", testSkipped.TestCase, () => recorder.RecordResult(result)); else logger.LogWarning(testSkipped.TestCase, "(Skip) Could not find VS test case for {0} (ID = {1})", testSkipped.TestCase.DisplayName, testSkipped.TestCase.UniqueID); @@ -155,7 +155,7 @@ void HandleTestCaseStarting(MessageHandlerArgs args) { var testCaseStarting = args.Message; var vsTestCase = FindTestCase(testCaseStarting.TestCase); - if (vsTestCase != null) + if (vsTestCase is not null) TryAndReport("RecordStart", testCaseStarting.TestCase, () => recorder.RecordStart(vsTestCase)); else logger.LogWarning(testCaseStarting.TestCase, "(Starting) Could not find VS test case for {0} (ID = {1})", testCaseStarting.TestCase.DisplayName, testCaseStarting.TestCase.UniqueID); @@ -167,7 +167,7 @@ void HandleTestCaseFinished(MessageHandlerArgs args) { var testCaseFinished = args.Message; var vsTestCase = FindTestCase(testCaseFinished.TestCase); - if (vsTestCase != null) + if (vsTestCase is not null) TryAndReport("RecordEnd", testCaseFinished.TestCase, () => recorder.RecordEnd(vsTestCase, GetAggregatedTestOutcome(testCaseFinished))); else logger.LogWarning(testCaseFinished.TestCase, "(Finished) Could not find VS test case for {0} (ID = {1})", testCaseFinished.TestCase.DisplayName, testCaseFinished.TestCase.UniqueID); @@ -243,7 +243,7 @@ void WriteError( foreach (var testCase in testCases) { var result = MakeVsTestResult(TestOutcome.Failed, testCase, testCase.DisplayName); - if (result != null) + if (result is not null) { result.ErrorMessage = $"[{failureName}]: {ExceptionUtility.CombineMessages(failureInfo)}"; result.ErrorStackTrace = ExceptionUtility.CombineStackTraces(failureInfo); @@ -275,7 +275,7 @@ void WriteError( string? errorMessage = null) { var vsTestCase = FindTestCase(testCase); - if (vsTestCase == null) + if (vsTestCase is null) return null; var result = new VsTestResult(vsTestCase) diff --git a/src/xunit.runner.visualstudio/Utility/AssemblyExtensions.cs b/src/xunit.runner.visualstudio/Utility/AssemblyExtensions.cs index 5cf731d..3da9779 100644 --- a/src/xunit.runner.visualstudio/Utility/AssemblyExtensions.cs +++ b/src/xunit.runner.visualstudio/Utility/AssemblyExtensions.cs @@ -8,7 +8,7 @@ internal static class AssemblyExtensions { #if NETFRAMEWORK string? codeBase = assembly.CodeBase; - if (codeBase == null) + if (codeBase is null) return null; if (!codeBase.StartsWith("file:///")) diff --git a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_Desktop.cs b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_Desktop.cs index ad6f1c8..d3be0d9 100644 --- a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_Desktop.cs +++ b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_Desktop.cs @@ -56,9 +56,9 @@ public void Dispose() => var path = Path.Combine(directory, assemblyName); result = ResolveAndLoadAssembly(path, out var resolvedAssemblyPath); - if (internalDiagnosticsMessageSink != null) + if (internalDiagnosticsMessageSink is not null) { - if (result == null) + if (result is null) internalDiagnosticsMessageSink.OnMessage(new _DiagnosticMessage($"[AssemblyHelper_Desktop.LoadAssembly] Resolution for '{assemblyName}' failed, passed down to next resolver")); else internalDiagnosticsMessageSink.OnMessage(new _DiagnosticMessage($"[AssemblyHelper_Desktop.LoadAssembly] Resolved '{assemblyName}' to '{resolvedAssemblyPath}'")); diff --git a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_NetCoreApp.cs b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_NetCoreApp.cs index 460e8a1..ba9dab3 100644 --- a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_NetCoreApp.cs +++ b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/AssemblyHelper_NetCoreApp.cs @@ -33,21 +33,21 @@ public AssemblyHelper( } var assembly = LoadFromAssemblyPath(assemblyFileName); - if (assembly == null) + if (assembly is null) { internalDiagnosticsMessageSink?.OnMessage(new _DiagnosticMessage($"[AssemblyHelper_NetCoreApp..ctor] Assembly file could not be loaded: '{assemblyFileName}'")); return; } var dependencyContext = DependencyContext.Load(assembly); - if (dependencyContext == null) + if (dependencyContext is null) { internalDiagnosticsMessageSink?.OnMessage(new _DiagnosticMessage($"[AssemblyHelper_NetCoreApp..ctor] Assembly file does not contain dependency manifest: '{assemblyFileName}'")); return; } var assemblyFolder = Path.GetDirectoryName(assemblyFileName); - if (assemblyFolder == null) + if (assemblyFolder is null) { internalDiagnosticsMessageSink?.OnMessage(new _DiagnosticMessage($"[AssemblyHelper_NetCoreApp..ctor] Assembly file does not have an associated folder to watch: '{assemblyFileName}'")); return; @@ -61,7 +61,7 @@ public AssemblyHelper( /// public void Dispose() { - if (assemblyCache != null) + if (assemblyCache is not null) Default.Resolving -= OnResolving; } @@ -74,7 +74,7 @@ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) { var result = default(IntPtr); - if (assemblyCache != null) + if (assemblyCache is not null) result = assemblyCache.LoadUnmanagedLibrary(unmanagedDllName, LoadUnmanagedDllFromPath); if (result == default) @@ -87,7 +87,7 @@ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) AssemblyLoadContext context, AssemblyName name) { - if (assemblyCache == null || name.Name == null) + if (assemblyCache is null || name.Name is null) return null; return assemblyCache.LoadManagedDll(name.Name, LoadFromAssemblyPath); diff --git a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/DependencyContextAssemblyCache.cs b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/DependencyContextAssemblyCache.cs index b41c995..7398ba9 100644 --- a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/DependencyContextAssemblyCache.cs +++ b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/DependencyContextAssemblyCache.cs @@ -64,13 +64,13 @@ public DependencyContextAssemblyCache( .Select(lib => compatibleRuntimes .Select(runtime => Tuple.Create(lib, lib.RuntimeAssemblyGroups.FirstOrDefault(libGroup => string.Equals(libGroup.Runtime, runtime)))) - .FirstOrDefault(tuple => tuple.Item2?.AssetPaths != null) + .FirstOrDefault(tuple => tuple.Item2?.AssetPaths is not null) ) .WhereNotNull() - .Where(tuple => tuple.Item2 != null) + .Where(tuple => tuple.Item2 is not null) .SelectMany(tuple => tuple.Item2!.AssetPaths - .Where(x => x != null) + .WhereNotNull() .Select(path => Tuple.Create(Path.GetFileNameWithoutExtension(path), Tuple.Create(tuple.Item1, tuple.Item2))) ) .ToDictionaryIgnoringDuplicateKeys(tuple => tuple.Item1, tuple => tuple.Item2, StringComparer.OrdinalIgnoreCase); @@ -85,13 +85,13 @@ public DependencyContextAssemblyCache( .Select(lib => compatibleRuntimes .Select(runtime => Tuple.Create(lib, lib.NativeLibraryGroups.FirstOrDefault(libGroup => string.Equals(libGroup.Runtime, runtime)))) - .FirstOrDefault(tuple => tuple.Item2?.AssetPaths != null) + .FirstOrDefault(tuple => tuple.Item2?.AssetPaths is not null) ) .WhereNotNull() - .Where(tuple => tuple.Item2 != null) + .Where(tuple => tuple.Item2 is not null) .SelectMany(tuple => tuple.Item2!.AssetPaths - .Where(x => x != null) + .WhereNotNull() .Select(path => Tuple.Create(Path.GetFileName(path), Tuple.Create(tuple.Item1, tuple.Item2))) ) .ToDictionaryIgnoringDuplicateKeys(tuple => tuple.Item1, tuple => tuple.Item2, StringComparer.OrdinalIgnoreCase); @@ -160,9 +160,9 @@ IEnumerable GetUnmanagedDllFormats() result = tupleResult.Item2; managedAssemblyCache[assemblyName] = result; - if (internalDiagnosticsMessageSink != null) + if (internalDiagnosticsMessageSink is not null) { - if (result == null) + if (result is null) internalDiagnosticsMessageSink.OnMessage(new _DiagnosticMessage($"[DependencyContextAssemblyCache.LoadManagedDll] Resolution for '{assemblyName}' failed, passed down to next resolver")); else internalDiagnosticsMessageSink.OnMessage(new _DiagnosticMessage($"[DependencyContextAssemblyCache.LoadManagedDll] Resolved '{assemblyName}' to '{resolvedAssemblyPath}'")); @@ -186,15 +186,15 @@ public IntPtr LoadUnmanagedLibrary( needDiagnostics = true; } - if (resolvedAssemblyPath != null) + if (resolvedAssemblyPath is not null) result = unmanagedAssemblyLoader(resolvedAssemblyPath); - if (needDiagnostics && internalDiagnosticsMessageSink != null) + if (needDiagnostics && internalDiagnosticsMessageSink is not null) if (result != default) internalDiagnosticsMessageSink.OnMessage(new _DiagnosticMessage($"[DependencyContextAssemblyCache.LoadUnmanagedLibrary] Resolved '{unmanagedLibraryName}' to '{resolvedAssemblyPath}'")); else { - if (resolvedAssemblyPath != null) + if (resolvedAssemblyPath is not null) internalDiagnosticsMessageSink.OnMessage(new _DiagnosticMessage($"[DependencyContextAssemblyCache.LoadUnmanagedLibrary] Resolving '{unmanagedLibraryName}', found assembly path '{resolvedAssemblyPath}' but the assembly would not load")); internalDiagnosticsMessageSink.OnMessage(new _DiagnosticMessage($"[DependencyContextAssemblyCache.LoadUnmanagedLibrary] Resolution for '{unmanagedLibraryName}' failed, passed down to next resolver")); @@ -217,7 +217,7 @@ public IntPtr LoadUnmanagedLibrary( if (fileSystem.File.Exists(resolvedAssemblyPath)) { var assembly = managedAssemblyLoader(resolvedAssemblyPath); - if (assembly != null) + if (assembly is not null) return Tuple.Create(resolvedAssemblyPath, assembly); } } @@ -234,12 +234,12 @@ public IntPtr LoadUnmanagedLibrary( if (assemblyResolver.TryResolveAssemblyPaths(wrapper, assemblies)) { var resolvedAssemblyPath = assemblies.FirstOrDefault(a => string.Equals(assemblyName, Path.GetFileNameWithoutExtension(a), StringComparison.OrdinalIgnoreCase)); - if (resolvedAssemblyPath != null) + if (resolvedAssemblyPath is not null) { resolvedAssemblyPath = Path.GetFullPath(resolvedAssemblyPath); var assembly = managedAssemblyLoader(resolvedAssemblyPath); - if (assembly != null) + if (assembly is not null) return Tuple.Create(resolvedAssemblyPath, assembly); internalDiagnosticsMessageSink?.OnMessage(new _DiagnosticMessage($"[DependencyContextAssemblyCache.ResolveManagedAssembly] Resolving '{assemblyName}', found assembly path '{resolvedAssemblyPath}' but the assembly would not load")); @@ -274,7 +274,7 @@ public IntPtr LoadUnmanagedLibrary( if (assemblyResolver.TryResolveAssemblyPaths(wrapper, assemblies)) { var resolvedAssemblyPath = assemblies.FirstOrDefault(a => string.Equals(formattedUnmanagedDllName, Path.GetFileName(a), StringComparison.OrdinalIgnoreCase)); - if (resolvedAssemblyPath != null) + if (resolvedAssemblyPath is not null) return Path.GetFullPath(resolvedAssemblyPath); internalDiagnosticsMessageSink?.OnMessage(new _DiagnosticMessage($"[DependencyContextAssemblyCache.ResolveUnmanagedLibrary] Found a resolved path, but could not map a filename in [{string.Join(",", assemblies.OrderBy(k => k, StringComparer.OrdinalIgnoreCase).Select(k => $"'{k}'"))}]")); diff --git a/src/xunit.runner.visualstudio/Utility/ExceptionExtensions.cs b/src/xunit.runner.visualstudio/Utility/ExceptionExtensions.cs index f21f28a..d444ad8 100644 --- a/src/xunit.runner.visualstudio/Utility/ExceptionExtensions.cs +++ b/src/xunit.runner.visualstudio/Utility/ExceptionExtensions.cs @@ -22,7 +22,7 @@ public static Exception Unwrap(this Exception ex) { while (true) { - if (ex is not TargetInvocationException tiex || tiex.InnerException == null) + if (ex is not TargetInvocationException tiex || tiex.InnerException is null) return ex; ex = tiex.InnerException; diff --git a/src/xunit.runner.visualstudio/Utility/Guard.cs b/src/xunit.runner.visualstudio/Utility/Guard.cs index d012898..ca6be1c 100644 --- a/src/xunit.runner.visualstudio/Utility/Guard.cs +++ b/src/xunit.runner.visualstudio/Utility/Guard.cs @@ -23,7 +23,7 @@ public static T ArgumentNotNull( [CallerArgumentExpression(nameof(argValue))] string? argName = null) where T : class { - if (argValue == null) + if (argValue is null) throw new ArgumentNullException(argName?.TrimStart('@')); return argValue; diff --git a/src/xunit.runner.visualstudio/Utility/LoggerHelper.cs b/src/xunit.runner.visualstudio/Utility/LoggerHelper.cs index 5f1e248..ca7b508 100644 --- a/src/xunit.runner.visualstudio/Utility/LoggerHelper.cs +++ b/src/xunit.runner.visualstudio/Utility/LoggerHelper.cs @@ -21,7 +21,7 @@ public void Log( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Informational, null, string.Format(format, args)); } @@ -30,7 +30,7 @@ public void Log( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Informational, testCase.TestMethod.TestClass.TestCollection.TestAssembly.Assembly.AssemblyPath, string.Format(format, args)); } @@ -39,7 +39,7 @@ public void LogWithSource( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Informational, source, string.Format(format, args)); } @@ -47,7 +47,7 @@ public void LogError( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Error, null, string.Format(format, args)); } @@ -56,7 +56,7 @@ public void LogError( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Error, testCase.TestMethod.TestClass.TestCollection.TestAssembly.Assembly.AssemblyPath, string.Format(format, args)); } @@ -65,7 +65,7 @@ public void LogErrorWithSource( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Error, source, string.Format(format, args)); } @@ -73,7 +73,7 @@ public void LogWarning( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Warning, null, string.Format(format, args)); } @@ -82,7 +82,7 @@ public void LogWarning( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Warning, testCase.TestMethod.TestClass.TestCollection.TestAssembly.Assembly.AssemblyPath, string.Format(format, args)); } @@ -91,7 +91,7 @@ public void LogWarningWithSource( string format, params object?[] args) { - if (InnerLogger != null) + if (InnerLogger is not null) SendMessage(InnerLogger, TestMessageLevel.Warning, source, string.Format(format, args)); } @@ -101,7 +101,7 @@ void SendMessage( string? assemblyName, string message) { - var assemblyText = assemblyName == null ? "" : $"{Path.GetFileNameWithoutExtension(assemblyName)}: "; + var assemblyText = assemblyName is null ? "" : $"{Path.GetFileNameWithoutExtension(assemblyName)}: "; logger.SendMessage(level, $"[xUnit.net {Stopwatch.Elapsed:hh\\:mm\\:ss\\.ff}] {assemblyText}{message}"); } } diff --git a/src/xunit.runner.visualstudio/Utility/RunSettings.cs b/src/xunit.runner.visualstudio/Utility/RunSettings.cs index c8a4e6d..7776396 100644 --- a/src/xunit.runner.visualstudio/Utility/RunSettings.cs +++ b/src/xunit.runner.visualstudio/Utility/RunSettings.cs @@ -58,17 +58,17 @@ public static RunSettings Parse(string? settingsXml) { var result = new RunSettings(); - if (settingsXml != null) + if (settingsXml is not null) { try { var runSettingsElement = System.Xml.Linq.XDocument.Parse(settingsXml)?.Element("RunSettings"); - if (runSettingsElement != null) + if (runSettingsElement is not null) { // Custom settings for xUnit.net var xunitElement = runSettingsElement.Element("xUnit"); - if (xunitElement != null) + if (xunitElement is not null) { var appDomainString = xunitElement.Element(Constants.Xunit.AppDomain)?.Value; if (Enum.TryParse(appDomainString, ignoreCase: true, out var appDomain)) @@ -119,7 +119,7 @@ public static RunSettings Parse(string? settingsXml) result.PreEnumerateTheories = preEnumerateTheories; var reporterSwitchString = xunitElement.Element(Constants.Xunit.ReporterSwitch)?.Value; - if (reporterSwitchString != null) + if (reporterSwitchString is not null) result.ReporterSwitch = reporterSwitchString; var shadowCopyString = xunitElement.Element(Constants.Xunit.ShadowCopy)?.Value; @@ -133,7 +133,7 @@ public static RunSettings Parse(string? settingsXml) // Standard settings from VSTest, which can override the user's configured values var runConfigurationElement = runSettingsElement.Element("RunConfiguration"); - if (runConfigurationElement != null) + if (runConfigurationElement is not null) { var collectSourceInformationString = runConfigurationElement.Element(Constants.RunConfiguration.CollectSourceInformation)?.Value; if (bool.TryParse(collectSourceInformationString, out var collectSourceInformation)) @@ -158,7 +158,7 @@ public static RunSettings Parse(string? settingsXml) } var targetFrameworkVersionString = runConfigurationElement.Element(Constants.RunConfiguration.TargetFrameworkVersion)?.Value; - if (targetFrameworkVersionString != null) + if (targetFrameworkVersionString is not null) result.TargetFrameworkVersion = targetFrameworkVersionString; // These values are holdovers that we inappropriately shoved into RunConfiguration. The documentation will @@ -172,7 +172,7 @@ public static RunSettings Parse(string? settingsXml) result.NoAutoReporters = noAutoReporters; var reporterSwitchString = runConfigurationElement.Element(Constants.RunConfiguration.ReporterSwitch)?.Value; - if (reporterSwitchString != null) + if (reporterSwitchString is not null) result.ReporterSwitch = reporterSwitchString; } } diff --git a/src/xunit.runner.visualstudio/Utility/TestCaseFilter.cs b/src/xunit.runner.visualstudio/Utility/TestCaseFilter.cs index dcdb0e0..d10cfa4 100644 --- a/src/xunit.runner.visualstudio/Utility/TestCaseFilter.cs +++ b/src/xunit.runner.visualstudio/Utility/TestCaseFilter.cs @@ -50,7 +50,7 @@ public bool MatchTestCase(TestCase testCase) // Had an error while getting filter, match no testcase to ensure discovered test list is empty return false; } - else if (filterExpression == null) + else if (filterExpression is null) { // No filter specified, keep every testcase return true; @@ -155,7 +155,7 @@ bool GetTestCaseFilterExpressionFromDiscoveryContext( List GetSupportedPropertyNames() { // Returns the set of well-known property names usually used with the Test Plugins (Used Test Traits + DisplayName + FullyQualifiedName) - if (supportedPropertyNames == null) + if (supportedPropertyNames is null) { supportedPropertyNames = knownTraits.ToList(); supportedPropertyNames.Add(DisplayNameString); @@ -168,7 +168,7 @@ List GetSupportedPropertyNames() static IEnumerable> GetTraits(TestCase testCase) { var traitProperty = TestProperty.Find("TestObject.Traits"); - if (traitProperty != null) + if (traitProperty is not null) return testCase.GetPropertyValue(traitProperty, Enumerable.Empty>().ToArray()); return Enumerable.Empty>(); diff --git a/src/xunit.runner.visualstudio/VsTestRunner.cs b/src/xunit.runner.visualstudio/VsTestRunner.cs index 76d78d7..8e8dbf8 100644 --- a/src/xunit.runner.visualstudio/VsTestRunner.cs +++ b/src/xunit.runner.visualstudio/VsTestRunner.cs @@ -158,7 +158,7 @@ void ITestExecutor.RunTests( IRunContext? runContext, IFrameworkHandle? frameworkHandle) { - if (sources == null) + if (sources is null) return; var stopwatch = Stopwatch.StartNew(); @@ -187,7 +187,7 @@ void ITestExecutor.RunTests( IRunContext? runContext, IFrameworkHandle? frameworkHandle) { - if (tests == null) + if (tests is null) return; var stopwatch = Stopwatch.StartNew(); @@ -330,7 +330,7 @@ static bool IsXunitTestAssembly(string assemblyFileName) return IsXunitPackageReferenced(assemblyFileName); #else var assemblyFolder = Path.GetDirectoryName(assemblyFileName); - if (assemblyFolder == null) + if (assemblyFolder is null) return false; return File.Exists(Path.Combine(assemblyFolder, "xunit.dll")) @@ -350,7 +350,7 @@ static bool IsXunitPackageReferenced(string assemblyFileName) using var stream = new MemoryStream(Encoding.UTF8.GetBytes(File.ReadAllText(depsFile))); var context = new DependencyContextJsonReader().Read(stream); var xunitLibrary = context.RuntimeLibraries.Where(lib => lib.Name.Equals("xunit") || lib.Name.Equals("xunit.core")).FirstOrDefault(); - return xunitLibrary != null; + return xunitLibrary is not null; } catch { @@ -430,7 +430,7 @@ void RunTestsInAssembly( using var controller = new XunitFrontController(appDomain, assemblyFileName, shadowCopy: shadowCopy, diagnosticMessageSink: diagnosticMessageSink); var testCasesMap = new Dictionary(); var testCases = new List(); - if (runInfo.TestCases == null || !runInfo.TestCases.Any()) + if (runInfo.TestCases is null || !runInfo.TestCases.Any()) { // Discover tests var assemblyDiscoveredInfo = default(AssemblyDiscoveredInfo); @@ -448,7 +448,7 @@ void RunTestsInAssembly( runInfo.Assembly ); - if (assemblyDiscoveredInfo == null || assemblyDiscoveredInfo.DiscoveredTestCases == null || !assemblyDiscoveredInfo.DiscoveredTestCases.Any()) + if (assemblyDiscoveredInfo is null || assemblyDiscoveredInfo.DiscoveredTestCases is null || !assemblyDiscoveredInfo.DiscoveredTestCases.Any()) { if (configuration.InternalDiagnosticMessagesOrDefault) logger.LogWarning("Skipping '{0}' since no tests were found during discovery [execution].", assemblyFileName); @@ -459,14 +459,14 @@ void RunTestsInAssembly( // Filter tests var traitNames = new HashSet(assemblyDiscoveredInfo.DiscoveredTestCases.SelectMany(testCase => testCase.TraitNames)); var filter = new TestCaseFilter(runContext, logger, assemblyDiscoveredInfo.AssemblyFileName, traitNames); - var filteredTestCases = assemblyDiscoveredInfo.DiscoveredTestCases.Where(dtc => dtc.VSTestCase != null && filter.MatchTestCase(dtc.VSTestCase)).ToList(); + var filteredTestCases = assemblyDiscoveredInfo.DiscoveredTestCases.Where(dtc => dtc.VSTestCase is not null && filter.MatchTestCase(dtc.VSTestCase)).ToList(); foreach (var filteredTestCase in filteredTestCases) { var uniqueID = filteredTestCase.UniqueID; if (testCasesMap.ContainsKey(uniqueID)) logger.LogWarning(filteredTestCase.TestCase, "Skipping test case with duplicate ID '{0}' ('{1}' and '{2}')", uniqueID, testCasesMap[uniqueID].DisplayName, filteredTestCase.VSTestCase?.DisplayName); - else if (filteredTestCase.VSTestCase != null) + else if (filteredTestCase.VSTestCase is not null) { testCasesMap.Add(uniqueID, filteredTestCase.VSTestCase); testCases.Add(filteredTestCase.TestCase); @@ -494,7 +494,7 @@ void RunTestsInAssembly( var deserializedTestCasesByUniqueId = controller.BulkDeserialize(serializations); - if (deserializedTestCasesByUniqueId == null) + if (deserializedTestCasesByUniqueId is null) logger.LogErrorWithSource(assemblyFileName, "Received null response from BulkDeserialize"); else { @@ -505,7 +505,7 @@ void RunTestsInAssembly( var kvp = deserializedTestCasesByUniqueId[idx]; var vsTestCase = runInfo.TestCases[idx]; - if (kvp.Value == null) + if (kvp.Value is null) { logger.LogErrorWithSource(assemblyFileName, "Test case {0} failed to deserialize: {1}", vsTestCase.DisplayName, kvp.Key); } @@ -646,7 +646,7 @@ public static IReadOnlyList GetAvailableRunnerReporters( try { var ctor = type.GetConstructor(new Type[0]); - if (ctor == null) + if (ctor is null) { logger?.LogWarning($"Type '{type.FullName ?? type.Name}' in the adapter assembly appears to be a runner reporter, but does not have an empty constructor."); continue; @@ -678,7 +678,7 @@ static IList GetVsTestCases( for (var idx = 0; idx < descriptors.Count; ++idx) { var testCase = new DiscoveredTestCase(source, descriptors[idx], testCases[idx], logger, testPlatformContext); - if (testCase.VSTestCase != null) + if (testCase.VSTestCase is not null) results.Add(testCase); } From 85864c89881560adb668f59b137e06f3dc544554 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 24 Sep 2023 17:28:57 -0700 Subject: [PATCH 05/15] Copy (and simplify) VisualStudioSourceInformationProvider from xunit.runner.utility --- .../Utility/AppDomainManager.cs | 73 +++++++++++ .../Utility/DiaSessionWrapper.cs | 52 ++++++++ .../Utility/DiaSessionWrapperHelper.cs | 114 ++++++++++++++++++ .../Utility/DictionaryExtensions.cs | 7 ++ .../Utility/Guard.cs | 35 ++++++ .../VisualStudioSourceInformationProvider.cs | 45 +++++++ src/xunit.runner.visualstudio/VsTestRunner.cs | 8 +- .../xunit.runner.visualstudio.csproj | 45 ++----- 8 files changed, 343 insertions(+), 36 deletions(-) create mode 100644 src/xunit.runner.visualstudio/Utility/AppDomainManager.cs create mode 100644 src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs create mode 100644 src/xunit.runner.visualstudio/Utility/DiaSessionWrapperHelper.cs create mode 100644 src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs diff --git a/src/xunit.runner.visualstudio/Utility/AppDomainManager.cs b/src/xunit.runner.visualstudio/Utility/AppDomainManager.cs new file mode 100644 index 0000000..96722ca --- /dev/null +++ b/src/xunit.runner.visualstudio/Utility/AppDomainManager.cs @@ -0,0 +1,73 @@ +#if NETFRAMEWORK + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.ExceptionServices; +using System.Security; +using System.Security.Permissions; +using Xunit.Internal; + +namespace Xunit.Runner.VisualStudio; + +class AppDomainManager +{ + readonly AppDomain appDomain; + + public AppDomainManager(string assemblyFileName) + { + Guard.ArgumentNotNullOrEmpty(assemblyFileName); + + assemblyFileName = Path.GetFullPath(assemblyFileName); + Guard.FileExists(assemblyFileName); + + var applicationBase = Path.GetDirectoryName(assemblyFileName); + var applicationName = Guid.NewGuid().ToString(); + var setup = new AppDomainSetup + { + ApplicationBase = applicationBase, + ApplicationName = applicationName, + ShadowCopyFiles = "true", + ShadowCopyDirectories = applicationBase, + CachePath = Path.Combine(Path.GetTempPath(), applicationName) + }; + + appDomain = AppDomain.CreateDomain(Path.GetFileNameWithoutExtension(assemblyFileName), AppDomain.CurrentDomain.Evidence, setup, new PermissionSet(PermissionState.Unrestricted)); + } + + public TObject? CreateObject( + AssemblyName assemblyName, + string typeName, + params object[] args) + where TObject : class + { + try + { + return appDomain.CreateInstanceAndUnwrap(assemblyName.FullName, typeName, false, BindingFlags.Default, null, args, null, null) as TObject; + } + catch (TargetInvocationException ex) + { + ExceptionDispatchInfo.Capture(ex.InnerException ?? ex).Throw(); + return default; // Will never reach here, but the compiler doesn't know that + } + } + + public virtual void Dispose() + { + if (appDomain is not null) + { + var cachePath = appDomain.SetupInformation.CachePath; + + try + { + AppDomain.Unload(appDomain); + + if (cachePath is not null) + Directory.Delete(cachePath, true); + } + catch { } + } + } +} + +#endif diff --git a/src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs b/src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs new file mode 100644 index 0000000..f94ce89 --- /dev/null +++ b/src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Navigation; + +namespace Xunit.Runner.VisualStudio.Utility; + +// This class wraps DiaSession, and uses DiaSessionWrapperHelper to discover when a test is an async test +// (since that requires special handling by DIA). The wrapper helper needs to exist in a separate AppDomain +// so that we can do discovery without locking the assembly under test (for .NET Framework). +class DiaSessionWrapper : IDisposable +{ +#if NETFRAMEWORK + readonly AppDomainManager? appDomainManager; +#endif + readonly DiaSessionWrapperHelper? helper; + readonly DiaSession session; + + public DiaSessionWrapper(string assemblyFileName) + { + session = new DiaSession(assemblyFileName); + +#if NETFRAMEWORK + var adapterFileName = typeof(DiaSessionWrapperHelper).Assembly.GetLocalCodeBase(); + if (adapterFileName is not null) + { + appDomainManager = new AppDomainManager(assemblyFileName); + helper = appDomainManager.CreateObject(typeof(DiaSessionWrapperHelper).Assembly.GetName(), typeof(DiaSessionWrapperHelper).FullName!, adapterFileName); + } +#else + helper = new DiaSessionWrapperHelper(assemblyFileName); +#endif + } + + public INavigationData? GetNavigationData( + string typeName, + string methodName) + { + if (helper is null) + return null; + + helper.Normalize(ref typeName, ref methodName); + return session.GetNavigationDataForMethod(typeName, methodName); + } + + public void Dispose() + { + session.Dispose(); +#if NETFRAMEWORK + appDomainManager?.Dispose(); +#endif + } +} diff --git a/src/xunit.runner.visualstudio/Utility/DiaSessionWrapperHelper.cs b/src/xunit.runner.visualstudio/Utility/DiaSessionWrapperHelper.cs new file mode 100644 index 0000000..dfc706a --- /dev/null +++ b/src/xunit.runner.visualstudio/Utility/DiaSessionWrapperHelper.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using Xunit.Sdk; + +namespace Xunit.Runner.VisualStudio.Utility; + +class DiaSessionWrapperHelper : LongLivedMarshalByRefObject +{ + readonly Assembly? assembly; + readonly Dictionary typeNameMap; + + public DiaSessionWrapperHelper(string assemblyFileName) + { + try + { +#if NETFRAMEWORK + assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFileName); + var assemblyDirectory = Path.GetDirectoryName(assemblyFileName); + + if (assemblyDirectory is not null) + AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (sender, args) => + { + try + { + // Try to load it normally + var name = AppDomain.CurrentDomain.ApplyPolicy(args.Name); + return Assembly.ReflectionOnlyLoad(name); + } + catch + { + try + { + // If a normal implicit load fails, try to load it from the directory that + // the test assembly lives in + return Assembly.ReflectionOnlyLoadFrom( + Path.Combine( + assemblyDirectory, + new AssemblyName(args.Name).Name + ".dll" + ) + ); + } + catch + { + // If all else fails, say we couldn't find it + return null; + } + } + }; +#else + assembly = Assembly.Load(new AssemblyName { Name = Path.GetFileNameWithoutExtension(assemblyFileName) }); +#endif + } + catch { } + + if (assembly is not null) + { + Type?[]? types = null; + + try + { + types = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + types = ex.Types; + } + catch { } // Ignore anything other than ReflectionTypeLoadException + + if (types is not null) + typeNameMap = + types + .WhereNotNull() + .Where(t => !string.IsNullOrEmpty(t.FullName)) + .ToDictionaryIgnoringDuplicateKeys(k => k.FullName!); + } + + typeNameMap ??= new(); + } + + public void Normalize( + ref string typeName, + ref string methodName) + { + try + { + if (assembly is null) + return; + + if (typeNameMap.TryGetValue(typeName, out var type) && type is not null) + { + var method = type.GetMethod(methodName); + if (method is not null && method.DeclaringType is not null && method.DeclaringType.FullName is not null) + { + // DiaSession only ever wants you to ask for the declaring type + typeName = method.DeclaringType.FullName; + + // See if this is an async method by looking for [AsyncStateMachine] on the method, + // which means we need to pass the state machine's "MoveNext" method. + var stateMachineType = method.GetCustomAttribute()?.StateMachineType; + if (stateMachineType is not null && stateMachineType.FullName is not null) + { + typeName = stateMachineType.FullName; + methodName = "MoveNext"; + } + } + } + } + catch { } + } +} diff --git a/src/xunit.runner.visualstudio/Utility/DictionaryExtensions.cs b/src/xunit.runner.visualstudio/Utility/DictionaryExtensions.cs index f59b126..4c44213 100644 --- a/src/xunit.runner.visualstudio/Utility/DictionaryExtensions.cs +++ b/src/xunit.runner.visualstudio/Utility/DictionaryExtensions.cs @@ -3,6 +3,13 @@ static class DictionaryExtensions { + public static Dictionary ToDictionaryIgnoringDuplicateKeys( + this IEnumerable inputValues, + Func keySelector, + IEqualityComparer? comparer = null) + where TKey : notnull => + ToDictionaryIgnoringDuplicateKeys(inputValues, keySelector, x => x, comparer); + public static Dictionary ToDictionaryIgnoringDuplicateKeys( this IEnumerable inputValues, Func keySelector, diff --git a/src/xunit.runner.visualstudio/Utility/Guard.cs b/src/xunit.runner.visualstudio/Utility/Guard.cs index ca6be1c..235e68f 100644 --- a/src/xunit.runner.visualstudio/Utility/Guard.cs +++ b/src/xunit.runner.visualstudio/Utility/Guard.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Runtime.CompilerServices; namespace Xunit.Internal; @@ -49,4 +50,38 @@ public static T ArgumentNotNullOrEmpty( return argValue; } + + /// + /// Ensures that an argument is valid. + /// + /// The exception message to use when the argument is not valid + /// The validity test value + /// The name of the argument + /// The argument value as a non-null value + /// Thrown when the argument is not valid + public static void ArgumentValid( + string message, + bool test, + string? argName = null) + { + if (!test) + throw new ArgumentException(message, argName); + } + + /// + /// Ensures that a filename argument is not null or empty, and that the file exists on disk. + /// + /// The file name value + /// The name of the argument + /// The file name as a non-null value + /// Thrown when the argument is null, empty, or not on disk + public static string FileExists( + [NotNull] string? fileName, + [CallerArgumentExpression(nameof(fileName))] string? argName = null) + { + ArgumentNotNullOrEmpty(fileName, argName); + ArgumentValid($"File not found: {fileName}", File.Exists(fileName), argName?.TrimStart('@')); + + return fileName; + } } diff --git a/src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs b/src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs new file mode 100644 index 0000000..c969677 --- /dev/null +++ b/src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs @@ -0,0 +1,45 @@ +using Xunit.Abstractions; +using Xunit.Runner.VisualStudio.Utility; +using Xunit.Sdk; + +namespace Xunit.Runner.VisualStudio; + +/// +/// An implementation of that will provide source information +/// when running inside of Visual Studio (via the DiaSession class). +/// +public class VisualStudioSourceInformationProvider : LongLivedMarshalByRefObject, ISourceInformationProvider +{ + static readonly SourceInformation EmptySourceInformation = new(); + + readonly DiaSessionWrapper session; + + /// + /// Initializes a new instance of the class. + /// + /// The assembly file name. + public VisualStudioSourceInformationProvider(string assemblyFileName) + { + session = new DiaSessionWrapper(assemblyFileName); + } + + /// + public ISourceInformation GetSourceInformation(ITestCase testCase) + { + var navData = session.GetNavigationData(testCase.TestMethod.TestClass.Class.Name, testCase.TestMethod.Method.Name); + if (navData is null || navData.FileName is null) + return EmptySourceInformation; + + return new SourceInformation + { + FileName = navData.FileName, + LineNumber = navData.MinLineNumber + }; + } + + /// + public void Dispose() + { + session.Dispose(); + } +} diff --git a/src/xunit.runner.visualstudio/VsTestRunner.cs b/src/xunit.runner.visualstudio/VsTestRunner.cs index 8e8dbf8..02fa944 100644 --- a/src/xunit.runner.visualstudio/VsTestRunner.cs +++ b/src/xunit.runner.visualstudio/VsTestRunner.cs @@ -240,8 +240,9 @@ void DiscoverTests( var diagnosticSink = DiagnosticMessageSink.ForDiagnostics(logger, fileName, assembly.Configuration.DiagnosticMessagesOrDefault); var appDomain = assembly.Configuration.AppDomain ?? AppDomainDefaultBehavior; - using var framework = new XunitFrontController(appDomain, assembly.AssemblyFilename, shadowCopy: shadowCopy, diagnosticMessageSink: MessageSinkAdapter.Wrap(diagnosticSink)); - if (!DiscoverTestsInSource(framework, logger, testPlatformContext, runSettings, visitorFactory, visitComplete, assembly)) + using var sourceInformationProvider = new VisualStudioSourceInformationProvider(assembly.AssemblyFilename); + using var controller = new XunitFrontController(appDomain, assembly.AssemblyFilename, shadowCopy: shadowCopy, sourceInformationProvider: sourceInformationProvider, diagnosticMessageSink: MessageSinkAdapter.Wrap(diagnosticSink)); + if (!DiscoverTestsInSource(controller, logger, testPlatformContext, runSettings, visitorFactory, visitComplete, assembly)) break; } } @@ -427,7 +428,8 @@ void RunTestsInAssembly( var diagnosticSink = DiagnosticMessageSink.ForDiagnostics(logger, assemblyDisplayName, runInfo.Assembly.Configuration.DiagnosticMessagesOrDefault); var diagnosticMessageSink = MessageSinkAdapter.Wrap(diagnosticSink); - using var controller = new XunitFrontController(appDomain, assemblyFileName, shadowCopy: shadowCopy, diagnosticMessageSink: diagnosticMessageSink); + using var sourceInformationProvider = new VisualStudioSourceInformationProvider(assemblyFileName); + using var controller = new XunitFrontController(appDomain, assemblyFileName, shadowCopy: shadowCopy, sourceInformationProvider: sourceInformationProvider, diagnosticMessageSink: diagnosticMessageSink); var testCasesMap = new Dictionary(); var testCases = new List(); if (runInfo.TestCases is null || !runInfo.TestCases.Any()) diff --git a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj index 7f8728b..849367d 100644 --- a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj +++ b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj @@ -1,25 +1,16 @@ - xUnit.net Runner for Visual Studio ($(TargetFramework)) true - Xunit.Runner.VisualStudio - net462;net6.0 - true - build + xunit.runner.visualstudio.testadapter + xunit.runner.visualstudio.dotnetcore.testadapter + xUnit.net Runner for Visual Studio ($(TargetFramework)) true $(NoWarn);CS0436 enable - - - - xunit.runner.visualstudio.testadapter - $(DefineConstants);NETFRAMEWORK - - - - xunit.runner.visualstudio.dotnetcore.testadapter - $(DefineConstants);NETCOREAPP + Xunit.Runner.VisualStudio + net462;net6.0 + true @@ -70,29 +61,21 @@ - + $([System.IO.Path]::Combine($(TargetDir), "merged", "$(TargetFileName)")) - + - + - + @@ -108,15 +91,11 @@ - + - + From 1c51d513e6479ba76856ce976433478bf75818ed Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 24 Sep 2023 18:27:45 -0700 Subject: [PATCH 06/15] Latest dependencies --- Versions.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Versions.props b/Versions.props index f508f52..d3ab9e9 100644 --- a/Versions.props +++ b/Versions.props @@ -9,8 +9,8 @@ 3.6.133 5.0.0 1.0.0-alpha.160 - 1.3.0 - 2.5.1 + 1.4.0-pre.1 + 2.5.2-pre.4 From 2dd69895010eaff737e38e567f7f792996cd3ba4 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sat, 30 Sep 2023 18:34:25 -0700 Subject: [PATCH 07/15] Undo the assembly merge from #383 --- src/xunit.runner.visualstudio/VsTestRunner.cs | 24 ----------- .../xunit.runner.visualstudio.desktop.props | 10 +++++ ...xunit.runner.visualstudio.dotnetcore.props | 10 +++++ .../xunit.runner.visualstudio.csproj | 42 +------------------ .../xunit.runner.visualstudio.nuspec | 4 +- test/test.harness/test.harness.csproj | 4 ++ .../test.testcasefilter.csproj | 29 +++---------- 7 files changed, 33 insertions(+), 90 deletions(-) diff --git a/src/xunit.runner.visualstudio/VsTestRunner.cs b/src/xunit.runner.visualstudio/VsTestRunner.cs index 02fa944..c6f90fb 100644 --- a/src/xunit.runner.visualstudio/VsTestRunner.cs +++ b/src/xunit.runner.visualstudio/VsTestRunner.cs @@ -638,30 +638,6 @@ public static IReadOnlyList GetAvailableRunnerReporters( logger.LogWarning(message); } - // Look for runners that might be embedded in ourselves (because of ILRepack). This is what the code - // in RunnerReporterUtility.GetAvailableRunnerReporters does after it finds a target assembly. - foreach (var type in adapterAssembly.GetTypes()) - { - if (type is null || type.IsAbstract || !type.GetInterfaces().Any(t => t == typeof(IRunnerReporter))) - continue; - - try - { - var ctor = type.GetConstructor(new Type[0]); - if (ctor is null) - { - logger?.LogWarning($"Type '{type.FullName ?? type.Name}' in the adapter assembly appears to be a runner reporter, but does not have an empty constructor."); - continue; - } - - result.Add((IRunnerReporter)ctor.Invoke(new object[0])); - } - catch (Exception ex) - { - logger?.LogWarning($"Exception thrown while inspecting type '{type.FullName ?? type.Name}' in the adapter assembly:{Environment.NewLine}{ex}"); - } - } - return result; } diff --git a/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.desktop.props b/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.desktop.props index fe1ba8e..75d06f0 100644 --- a/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.desktop.props +++ b/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.desktop.props @@ -11,6 +11,16 @@ PreserveNewest False + + xunit.runner.reporters.net452.dll + PreserveNewest + False + + + xunit.runner.utility.net452.dll + PreserveNewest + False + diff --git a/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.dotnetcore.props b/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.dotnetcore.props index 7aa92d6..410a253 100644 --- a/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.dotnetcore.props +++ b/src/xunit.runner.visualstudio/build/xunit.runner.visualstudio.dotnetcore.props @@ -6,6 +6,16 @@ PreserveNewest False + + xunit.runner.reporters.netcoreapp10.dll + PreserveNewest + False + + + xunit.runner.utility.netcoreapp10.dll + PreserveNewest + False + diff --git a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj index 849367d..291bac6 100644 --- a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj +++ b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj @@ -22,7 +22,7 @@ - + @@ -56,47 +56,9 @@ Configuration=$(Configuration); GitCommitId=$(GitCommitId); PackageVersion=$(PackageVersion); + XunitVersion=$(XunitVersion); - - - - $([System.IO.Path]::Combine($(TargetDir), "merged", "$(TargetFileName)")) - - - - - - - - - - - - - - - - - - - - $([System.IO.Path]::Combine($(NuGetPackageRoot), "ilrepack.msbuild.task", $(ILRepackVersion), "tools", "ilrepack.exe")) - mono $(ILRepackExe) - $([System.IO.Path]::Combine($(TargetDir), "premerge", "$(TargetFileName)")) - $([System.IO.Path]::Combine($(TargetDir), "merged", "$(TargetFileName)")) - - - - - - - - - - - - diff --git a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec index 7f66020..f72bccf 100644 --- a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec +++ b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec @@ -27,10 +27,10 @@ - + - + diff --git a/test/test.harness/test.harness.csproj b/test/test.harness/test.harness.csproj index 26ad271..ce95c80 100644 --- a/test/test.harness/test.harness.csproj +++ b/test/test.harness/test.harness.csproj @@ -4,6 +4,10 @@ net462;net472;net6.0 + + + + diff --git a/test/test.testcasefilter/test.testcasefilter.csproj b/test/test.testcasefilter/test.testcasefilter.csproj index af715a1..7ba0296 100644 --- a/test/test.testcasefilter/test.testcasefilter.csproj +++ b/test/test.testcasefilter/test.testcasefilter.csproj @@ -5,31 +5,12 @@ - + - - - - - - - - - + + + + From af96d96e2cf2f15ce18a21df462553053558d8e0 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 8 Oct 2023 12:15:45 -0700 Subject: [PATCH 08/15] Latest dependencies --- Versions.props | 4 ++-- .../Utility/AssemblyResolution/_DiagnosticMessage.cs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Versions.props b/Versions.props index d3ab9e9..2242e26 100644 --- a/Versions.props +++ b/Versions.props @@ -9,8 +9,8 @@ 3.6.133 5.0.0 1.0.0-alpha.160 - 1.4.0-pre.1 - 2.5.2-pre.4 + 1.4.0-pre.9 + 2.5.2-pre.6 diff --git a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/_DiagnosticMessage.cs b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/_DiagnosticMessage.cs index 4885036..d242b0d 100644 --- a/src/xunit.runner.visualstudio/Utility/AssemblyResolution/_DiagnosticMessage.cs +++ b/src/xunit.runner.visualstudio/Utility/AssemblyResolution/_DiagnosticMessage.cs @@ -1,8 +1,9 @@ using Xunit.Abstractions; +using Xunit.Sdk; namespace Xunit; -class _DiagnosticMessage : IDiagnosticMessage +class _DiagnosticMessage : LongLivedMarshalByRefObject, IDiagnosticMessage { /// /// Initializes a new instance of the class. From 9d2800688c5a5007fdb9f0f073c9a4b749e62ef4 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Sun, 8 Oct 2023 14:23:12 -0700 Subject: [PATCH 09/15] Add /.vscode/tasks.json for builds inside VS Code --- .vscode/tasks.json | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 .vscode/tasks.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..86468ad --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,49 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "process", + "command": "dotnet", + "args": [ + "run", + "--project", + "tools/builder", + "--no-launch-profile", + "--", + "--configuration", + "Debug", + "Build" + ], + "options": { + "cwd": "${workspaceRoot}" + }, + "group": "build", + "presentation": { + "focus": true + }, + "problemMatcher": "$msCompile" + }, + { + "label": "Pre-PR Build", + "type": "process", + "command": "dotnet", + "args": [ + "run", + "--project", + "tools/builder", + "--no-launch-profile", + "--", + "BuildAll" + ], + "options": { + "cwd": "${workspaceRoot}" + }, + "group": "build", + "presentation": { + "focus": true + }, + "problemMatcher": "$msCompile" + }, + ] +} From 9b843e136f0d5a385846b88ccfae89d667c6093b Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Tue, 10 Oct 2023 12:42:28 -0700 Subject: [PATCH 10/15] Add Microsoft.TestPlatform.ObjectModel as a dependency in the nuspec for .NET Framework --- Versions.props | 6 +++--- .../xunit.runner.visualstudio.csproj | 2 +- .../xunit.runner.visualstudio.nuspec | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Versions.props b/Versions.props index 2242e26..9f66ef9 100644 --- a/Versions.props +++ b/Versions.props @@ -3,11 +3,11 @@ 2.0.13 6.0.11 - 17.7.0 + 17.7.2 1.1.1 - 17.7.0 + $(MicrosoftNetTestSdkVersion) 3.6.133 - 5.0.0 + 5.1.0 1.0.0-alpha.160 1.4.0-pre.9 2.5.2-pre.6 diff --git a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj index 291bac6..3b30558 100644 --- a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj +++ b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.csproj @@ -55,8 +55,8 @@ Configuration=$(Configuration); GitCommitId=$(GitCommitId); + MicrosoftTestPlatformObjectModelVersion=$(MicrosoftTestPlatformObjectModelVersion); PackageVersion=$(PackageVersion); - XunitVersion=$(XunitVersion); diff --git a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec index f72bccf..2fdf8d3 100644 --- a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec +++ b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec @@ -16,7 +16,9 @@ true - + + + From b56611bde0cdc1513d5420f4a066b63df0de7870 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Thu, 12 Oct 2023 16:59:55 -0700 Subject: [PATCH 11/15] v2.5.2 --- Versions.props | 4 ++-- version.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Versions.props b/Versions.props index 9f66ef9..abd9b26 100644 --- a/Versions.props +++ b/Versions.props @@ -9,8 +9,8 @@ 3.6.133 5.1.0 1.0.0-alpha.160 - 1.4.0-pre.9 - 2.5.2-pre.6 + 1.4.0 + 2.5.2 diff --git a/version.json b/version.json index c96c975..05b5c0c 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.5.2-pre.{height}", + "version": "2.5.2", "nuGetPackageVersion": { "semVer": 2.0 }, From ce0f849c747ee27ba6c947e71e483f730293a0fd Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Thu, 12 Oct 2023 19:01:21 -0700 Subject: [PATCH 12/15] Bump up to v2.5.3-pre --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 05b5c0c..68e37d6 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.5.2", + "version": "2.5.3-pre.{height}", "nuGetPackageVersion": { "semVer": 2.0 }, From 32b7c99f6023cc12552833c740ca2a2fce3bdbd6 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Thu, 12 Oct 2023 17:50:19 -0700 Subject: [PATCH 13/15] Incorrect URL for Git repository in .nuspec file --- src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec index 2fdf8d3..6549723 100644 --- a/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec +++ b/src/xunit.runner.visualstudio/xunit.runner.visualstudio.nuspec @@ -13,7 +13,7 @@ https://xunit.net/releases/visualstudio/$PackageVersion$ Visual Studio 2022+ Test Explorer runner for the xUnit.net framework. Capable of running xUnit.net v1.9.2 and v2.0+ tests. Supports .NET 4.6.2 or later, and .NET 6 or later. Copyright (C) .NET Foundation - + true From 48d5ef68535d44fc58641a51c6844da6e4e3f7b7 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Thu, 12 Oct 2023 18:27:33 -0700 Subject: [PATCH 14/15] Add diagnostic messages around DiaSession failures --- .../Utility/DiaSessionWrapper.cs | 55 ++++++++++++++----- .../VisualStudioSourceInformationProvider.cs | 7 ++- src/xunit.runner.visualstudio/VsTestRunner.cs | 4 +- 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs b/src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs index f94ce89..461ec67 100644 --- a/src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs +++ b/src/xunit.runner.visualstudio/Utility/DiaSessionWrapper.cs @@ -1,6 +1,8 @@ using System; using Microsoft.VisualStudio.TestPlatform.ObjectModel; using Microsoft.VisualStudio.TestPlatform.ObjectModel.Navigation; +using Xunit.Abstractions; +using Xunit.Internal; namespace Xunit.Runner.VisualStudio.Utility; @@ -13,38 +15,65 @@ class DiaSessionWrapper : IDisposable readonly AppDomainManager? appDomainManager; #endif readonly DiaSessionWrapperHelper? helper; - readonly DiaSession session; + readonly DiaSession? session; + readonly DiagnosticMessageSink diagnosticMessageSink; - public DiaSessionWrapper(string assemblyFileName) + public DiaSessionWrapper( + string assemblyFileName, + DiagnosticMessageSink diagnosticMessageSink) { - session = new DiaSession(assemblyFileName); + this.diagnosticMessageSink = Guard.ArgumentNotNull(diagnosticMessageSink); -#if NETFRAMEWORK - var adapterFileName = typeof(DiaSessionWrapperHelper).Assembly.GetLocalCodeBase(); - if (adapterFileName is not null) + try + { + session = new DiaSession(assemblyFileName); + } + catch (Exception ex) { - appDomainManager = new AppDomainManager(assemblyFileName); - helper = appDomainManager.CreateObject(typeof(DiaSessionWrapperHelper).Assembly.GetName(), typeof(DiaSessionWrapperHelper).FullName!, adapterFileName); + diagnosticMessageSink.OnMessage(new DiagnosticMessage($"Exception creating DiaSession: {ex}")); } + + try + { +#if NETFRAMEWORK + var adapterFileName = typeof(DiaSessionWrapperHelper).Assembly.GetLocalCodeBase(); + if (adapterFileName is not null) + { + appDomainManager = new AppDomainManager(assemblyFileName); + helper = appDomainManager.CreateObject(typeof(DiaSessionWrapperHelper).Assembly.GetName(), typeof(DiaSessionWrapperHelper).FullName!, adapterFileName); + } #else - helper = new DiaSessionWrapperHelper(assemblyFileName); + helper = new DiaSessionWrapperHelper(assemblyFileName); #endif + } + catch (Exception ex) + { + diagnosticMessageSink.OnMessage(new DiagnosticMessage($"Exception creating DiaSessionWrapperHelper: {ex}")); + } } public INavigationData? GetNavigationData( string typeName, string methodName) { - if (helper is null) + if (session is null || helper is null) return null; - helper.Normalize(ref typeName, ref methodName); - return session.GetNavigationDataForMethod(typeName, methodName); + try + { + helper.Normalize(ref typeName, ref methodName); + return session.GetNavigationDataForMethod(typeName, methodName); + } + catch (Exception ex) + { + diagnosticMessageSink.OnMessage(new DiagnosticMessage($"Exception getting source mapping for {typeName}.{methodName}: {ex}")); + return null; + } } public void Dispose() { - session.Dispose(); + session?.Dispose(); #if NETFRAMEWORK appDomainManager?.Dispose(); #endif diff --git a/src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs b/src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs index c969677..d80e26f 100644 --- a/src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs +++ b/src/xunit.runner.visualstudio/Utility/VisualStudioSourceInformationProvider.cs @@ -18,9 +18,12 @@ public class VisualStudioSourceInformationProvider : LongLivedMarshalByRefObject /// Initializes a new instance of the class. /// /// The assembly file name. - public VisualStudioSourceInformationProvider(string assemblyFileName) + /// The message sink to send internal diagnostic messages to. + public VisualStudioSourceInformationProvider( + string assemblyFileName, + DiagnosticMessageSink diagnosticMessageSink) { - session = new DiaSessionWrapper(assemblyFileName); + session = new DiaSessionWrapper(assemblyFileName, diagnosticMessageSink); } /// diff --git a/src/xunit.runner.visualstudio/VsTestRunner.cs b/src/xunit.runner.visualstudio/VsTestRunner.cs index c6f90fb..4c79e6c 100644 --- a/src/xunit.runner.visualstudio/VsTestRunner.cs +++ b/src/xunit.runner.visualstudio/VsTestRunner.cs @@ -240,7 +240,7 @@ void DiscoverTests( var diagnosticSink = DiagnosticMessageSink.ForDiagnostics(logger, fileName, assembly.Configuration.DiagnosticMessagesOrDefault); var appDomain = assembly.Configuration.AppDomain ?? AppDomainDefaultBehavior; - using var sourceInformationProvider = new VisualStudioSourceInformationProvider(assembly.AssemblyFilename); + using var sourceInformationProvider = new VisualStudioSourceInformationProvider(assembly.AssemblyFilename, diagnosticSink); using var controller = new XunitFrontController(appDomain, assembly.AssemblyFilename, shadowCopy: shadowCopy, sourceInformationProvider: sourceInformationProvider, diagnosticMessageSink: MessageSinkAdapter.Wrap(diagnosticSink)); if (!DiscoverTestsInSource(controller, logger, testPlatformContext, runSettings, visitorFactory, visitComplete, assembly)) break; @@ -428,7 +428,7 @@ void RunTestsInAssembly( var diagnosticSink = DiagnosticMessageSink.ForDiagnostics(logger, assemblyDisplayName, runInfo.Assembly.Configuration.DiagnosticMessagesOrDefault); var diagnosticMessageSink = MessageSinkAdapter.Wrap(diagnosticSink); - using var sourceInformationProvider = new VisualStudioSourceInformationProvider(assemblyFileName); + using var sourceInformationProvider = new VisualStudioSourceInformationProvider(assemblyFileName, diagnosticSink); using var controller = new XunitFrontController(appDomain, assemblyFileName, shadowCopy: shadowCopy, sourceInformationProvider: sourceInformationProvider, diagnosticMessageSink: diagnosticMessageSink); var testCasesMap = new Dictionary(); var testCases = new List(); From 6b60a9e56a82a4010e2c65481cfa40c227f97fd5 Mon Sep 17 00:00:00 2001 From: Brad Wilson Date: Thu, 12 Oct 2023 19:02:31 -0700 Subject: [PATCH 15/15] v2.5.3 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 68e37d6..b71b6a3 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.5.3-pre.{height}", + "version": "2.5.3", "nuGetPackageVersion": { "semVer": 2.0 },