Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Immutable;
using Microsoft.CodeAnalysis.LanguageServer.BrokeredServices;
using Microsoft.CodeAnalysis.LanguageServer.HostWorkspace;
using Microsoft.CodeAnalysis.Remote.ProjectSystem;
Expand Down Expand Up @@ -58,11 +59,106 @@ public async Task CreateProjectAndBatch()
Assert.Equal("Folder", Assert.Single(additionalDocument.Folders));
}

[Fact]
public async Task LogProjectLoadWithCapabilities()
{
var capturingLogger = new CapturingLoggerProvider();
var loggerFactory = new LoggerFactory([capturingLogger]);
var (exportProvider, _) = await LanguageServerTestComposition.CreateExportProviderAsync(
loggerFactory, includeDevKitComponents: false, MefCacheDirectory.Path, []);
using var _ = exportProvider;

await exportProvider.GetExportedValue<ServiceBrokerFactory>().CreateAsync();

var workspaceFactory = exportProvider.GetExportedValue<LanguageServerWorkspaceFactory>();
var workspaceProjectFactoryServiceInstance = (WorkspaceProjectFactoryService)exportProvider
.GetExportedValues<IExportedBrokeredService>()
.Single(service => service.Descriptor == WorkspaceProjectFactoryServiceDescriptor.ServiceDescriptor);

await using var brokeredServiceFactory = new BrokeredServiceProxy<IWorkspaceProjectFactoryService>(
workspaceProjectFactoryServiceInstance);

var workspaceProjectFactoryService = await brokeredServiceFactory.GetServiceAsync();

// Test with capabilities
var projectPath = MakeAbsolutePath("TestProject.csproj");
using var workspaceProject = await workspaceProjectFactoryService.CreateAndAddProjectAsync(
new WorkspaceProjectCreationInfo(
LanguageNames.CSharp,
"DisplayName",
FilePath: projectPath,
new Dictionary<string, string>(),
ProjectCapabilities: ImmutableArray.Create("CSharp", "Test", "Managed")),
CancellationToken.None);

// Verify the log message includes capabilities
var logMessage = Assert.Single(capturingLogger.LogMessages, m => m.Contains(projectPath));
Assert.Contains("with capabilities: CSharp, Test, Managed", logMessage);

// Dispose project so we can create another one
workspaceProject.Dispose();
capturingLogger.LogMessages.Clear();

// Test without capabilities (backward compatibility)
var projectPath2 = MakeAbsolutePath("TestProject2.csproj");
using var workspaceProject2 = await workspaceProjectFactoryService.CreateAndAddProjectAsync(
new WorkspaceProjectCreationInfo(
LanguageNames.CSharp,
"DisplayName2",
FilePath: projectPath2,
new Dictionary<string, string>()),
CancellationToken.None);

// Verify the log message does NOT include capabilities
var logMessage2 = Assert.Single(capturingLogger.LogMessages, m => m.Contains(projectPath2));
Assert.DoesNotContain("with capabilities:", logMessage2);
Assert.Contains("loaded by C# Dev Kit", logMessage2);
}

private static string MakeAbsolutePath(string relativePath)
{
if (OperatingSystem.IsWindows())
return Path.Combine("Z:\\", relativePath);
else
return Path.Combine("//", relativePath);
}

private sealed class CapturingLoggerProvider : ILoggerProvider
{
public List<string> LogMessages { get; } = new();

public ILogger CreateLogger(string categoryName)
{
return new CapturingLogger(this);
}

public void Dispose()
{
}

private sealed class CapturingLogger(CapturingLoggerProvider provider) : ILogger
{
public IDisposable BeginScope<TState>(TState state) where TState : notnull
{
return new NoOpDisposable();
}

public bool IsEnabled(LogLevel logLevel)
{
return true;
}

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
provider.LogMessages.Add(formatter(state, exception));
}

private sealed class NoOpDisposable : IDisposable
{
public void Dispose()
{
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ Task IExportedBrokeredService.InitializeAsync(CancellationToken cancellationToke

public async Task<IWorkspaceProject> CreateAndAddProjectAsync(WorkspaceProjectCreationInfo creationInfo, CancellationToken _)
{
_logger.LogInformation(string.Format(LanguageServerResources.Project_0_loaded_by_CSharp_Dev_Kit, creationInfo.FilePath));
var capabilitiesString = creationInfo.ProjectCapabilities.IsDefaultOrEmpty
? string.Empty
: $" with capabilities: {string.Join(", ", creationInfo.ProjectCapabilities)}";
_logger.LogInformation(string.Format(LanguageServerResources.Project_0_loaded_by_CSharp_Dev_Kit_1, creationInfo.FilePath, capabilitiesString));
VSCodeRequestTelemetryLogger.ReportProjectLoadStarted();
try
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@
<value>Project {0} loaded by C# Dev Kit</value>
<comment>The placeholder is a name of a file</comment>
</data>
<data name="Project_0_loaded_by_CSharp_Dev_Kit_1" xml:space="preserve">
<value>Project {0} loaded by C# Dev Kit{1}</value>
<comment>The first placeholder is a name of a file, the second placeholder is optional capabilities information</comment>
</data>
<data name="Running_tests" xml:space="preserve">
<value>Running tests...</value>
</data>
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading