diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx
index c9089ed8449e6..d0b08a3fe8e1c 100644
--- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx
+++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx
@@ -147,6 +147,9 @@
Failed: {0}, Passed: {1}, Skipped: {2}, Total: {3}, Duration: {4}
+
+ Failed to read .runsettings file at {0}:{1}
+
Found {0} tests in {1}
@@ -162,6 +165,9 @@
Running tests...
+
+ .runsettings file does not exist at {0}
+
Show C# logs
@@ -192,4 +198,7 @@
There were problems loading your projects. See log for details.
+
+ Using .runsettings file at {0}
+
\ No newline at end of file
diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs
index 514032d5445ca..49eb7fa9504b6 100644
--- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs
+++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/RunTestsHandler.cs
@@ -7,6 +7,7 @@
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.LanguageServer.Handler.Testing;
+using Microsoft.Extensions.Logging;
using Microsoft.TestPlatform.VsTestConsole.TranslationLayer;
using Roslyn.Utilities;
using LSP = Microsoft.VisualStudio.LanguageServer.Protocol;
@@ -17,11 +18,13 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Testing;
[Method(RunTestsMethodName)]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
-internal class RunTestsHandler(DotnetCliHelper dotnetCliHelper, TestDiscoverer testDiscoverer, TestRunner testRunner, ServerConfiguration serverConfiguration)
+internal class RunTestsHandler(DotnetCliHelper dotnetCliHelper, TestDiscoverer testDiscoverer, TestRunner testRunner, ServerConfiguration serverConfiguration, ILoggerFactory loggerFactory)
: ILspServiceDocumentRequestHandler
{
private const string RunTestsMethodName = "textDocument/runTests";
+ private readonly ILogger _logger = loggerFactory.CreateLogger();
+
public bool MutatesSolutionState => false;
public bool RequiresLSPSolution => true;
@@ -59,11 +62,13 @@ public async Task HandleRequestAsync(RunTestsParams req
}
});
- var testCases = await testDiscoverer.DiscoverTestsAsync(request.Range, context.Document, projectOutputPath, progress, vsTestConsoleWrapper, cancellationToken);
+ var runSettingsPath = request.RunSettingsPath;
+ var runSettings = await GetRunSettingsAsync(runSettingsPath, progress, cancellationToken);
+ var testCases = await testDiscoverer.DiscoverTestsAsync(request.Range, context.Document, projectOutputPath, runSettings, progress, vsTestConsoleWrapper, cancellationToken);
if (!testCases.IsEmpty)
{
var clientLanguageServerManager = context.GetRequiredLspService();
- await testRunner.RunTestsAsync(testCases, progress, vsTestConsoleWrapper, request.AttachDebugger, clientLanguageServerManager, cancellationToken);
+ await testRunner.RunTestsAsync(testCases, progress, vsTestConsoleWrapper, request.AttachDebugger, runSettings, clientLanguageServerManager, cancellationToken);
}
return progress.GetValues() ?? Array.Empty();
@@ -160,4 +165,33 @@ private static TraceLevel GetTraceLevel(ServerConfiguration serverConfiguration)
_ => throw new InvalidOperationException($"Unexpected log level {serverConfiguration.MinimumLogLevel}"),
};
}
+
+ private async Task GetRunSettingsAsync(string? runSettingsPath, BufferedProgress progress, CancellationToken cancellationToken)
+ {
+ if (string.IsNullOrEmpty(runSettingsPath))
+ {
+ return null;
+ }
+
+ try
+ {
+ var contents = await File.ReadAllTextAsync(runSettingsPath, cancellationToken);
+ var message = string.Format(LanguageServerResources.Using_runsettings_file_at_0, runSettingsPath);
+ progress.Report(new(LanguageServerResources.Discovering_tests, message, Progress: null));
+ _logger.LogTrace($".runsettings:{Environment.NewLine}{contents}");
+ return contents;
+ }
+ catch (FileNotFoundException)
+ {
+ var message = string.Format(LanguageServerResources.Runsettings_file_does_not_exist_at_0, runSettingsPath);
+ progress.Report(new(LanguageServerResources.Discovering_tests, message, Progress: null));
+ }
+ catch (Exception ex)
+ {
+ var message = string.Format(LanguageServerResources.Failed_to_read_runsettings_file_at_0_1, runSettingsPath, ex);
+ progress.Report(new(LanguageServerResources.Discovering_tests, message, Progress: null));
+ }
+
+ return null;
+ }
}
diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs
index a91d4021570c5..3aea99770153b 100644
--- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs
+++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestDiscoverer.cs
@@ -34,6 +34,7 @@ public async Task> DiscoverTestsAsync(
LSP.Range range,
Document document,
string projectOutputPath,
+ string? runSettings,
BufferedProgress progress,
VsTestConsoleWrapper vsTestConsoleWrapper,
CancellationToken cancellationToken)
@@ -56,8 +57,7 @@ public async Task> DiscoverTestsAsync(
var stopwatch = SharedStopwatch.StartNew();
// The async APIs for vs test are broken (current impl ends up just hanging), so we must use the sync API instead.
- // TODO - run settings. https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1799066/
- var discoveryTask = Task.Run(() => vsTestConsoleWrapper.DiscoverTests(SpecializedCollections.SingletonEnumerable(projectOutputPath), discoverySettings: null, discoveryHandler), cancellationToken);
+ var discoveryTask = Task.Run(() => vsTestConsoleWrapper.DiscoverTests(SpecializedCollections.SingletonEnumerable(projectOutputPath), discoverySettings: runSettings, discoveryHandler), cancellationToken);
cancellationToken.Register(() => vsTestConsoleWrapper.CancelDiscovery());
await discoveryTask;
diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.cs
index 13a31f98e2f45..2e9bcf7be20a7 100644
--- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.cs
+++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/Testing/TestRunner.cs
@@ -23,7 +23,6 @@ internal partial class TestRunner(ILoggerFactory loggerFactory)
/// A default value for run settings. While the vstest console included with newer SDKs does
/// support passing in a null run settings value, the vstest console in older SDKs (.net 6 for example)
/// will throw if we pass a null value. So for our default we hardcode an empty XML configuration.
- /// TODO - Support configuring run settings - https://github.com/dotnet/vscode-csharp/issues/5719
///
private const string DefaultRunSettings = "";
private readonly ILogger _logger = loggerFactory.CreateLogger();
@@ -33,6 +32,7 @@ public async Task RunTestsAsync(
BufferedProgress progress,
VsTestConsoleWrapper vsTestConsoleWrapper,
bool attachDebugger,
+ string? runSettings,
IClientLanguageServerManager clientLanguageServerManager,
CancellationToken cancellationToken)
{
@@ -44,7 +44,7 @@ public async Task RunTestsAsync(
var handler = new TestRunHandler(progress, initialProgress, _logger);
- var runTask = Task.Run(() => RunTests(testCases, progress, vsTestConsoleWrapper, handler, attachDebugger, clientLanguageServerManager), cancellationToken);
+ var runTask = Task.Run(() => RunTests(testCases, progress, vsTestConsoleWrapper, handler, attachDebugger, runSettings, clientLanguageServerManager), cancellationToken);
cancellationToken.Register(() => vsTestConsoleWrapper.CancelTestRun());
await runTask;
}
@@ -55,17 +55,19 @@ private static void RunTests(
VsTestConsoleWrapper vsTestConsoleWrapper,
TestRunHandler handler,
bool attachDebugger,
+ string? runSettings,
IClientLanguageServerManager clientLanguageServerManager)
{
+ runSettings ??= DefaultRunSettings;
if (attachDebugger)
{
// When we want to debug tests we need to use a custom test launcher so that we get called back with the process to attach to.
- vsTestConsoleWrapper.RunTestsWithCustomTestHost(testCases, runSettings: DefaultRunSettings, handler, new DebugTestHostLauncher(progress, clientLanguageServerManager));
+ vsTestConsoleWrapper.RunTestsWithCustomTestHost(testCases, runSettings: runSettings, handler, new DebugTestHostLauncher(progress, clientLanguageServerManager));
}
else
{
// The async APIs for vs test are broken (current impl ends up just hanging), so we must use the sync API instead.
- vsTestConsoleWrapper.RunTests(testCases, runSettings: DefaultRunSettings, handler);
+ vsTestConsoleWrapper.RunTests(testCases, runSettings: runSettings, handler);
}
}
}
diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf
index 097363e96e766..0d4a916601a68 100644
--- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf
+++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf
@@ -52,6 +52,11 @@
Failed: {0}, Passed: {1}, Skipped: {2}, Total: {3}, Duration: {4}
+
+
+ Failed to read .runsettings file at {0}:{1}
+
+
Found {0} tests in {1}
@@ -77,6 +82,11 @@
Running tests...
+
+
+ .runsettings file does not exist at {0}
+
+
Show C# logs
@@ -127,6 +137,11 @@
There were problems loading your projects. See log for details.
+
+
+ Using .runsettings file at {0}
+
+