File: Options\SolutionAnalyzerConfigOptionsUpdaterTests.cs
Web Access
Project: src\src\LanguageServer\ProtocolUnitTests\Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests.csproj (Microsoft.CodeAnalysis.LanguageServer.Protocol.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// 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.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Options.UnitTests;
 
[UseExportProvider]
public class SolutionAnalyzerConfigOptionsUpdaterTests
{
    private static TestWorkspace CreateWorkspace()
    {
        var workspace = new TestWorkspace(LspTestCompositions.LanguageServerProtocol
            .RemoveParts(typeof(MockFallbackAnalyzerConfigOptionsProvider)));
 
        var updater = (SolutionAnalyzerConfigOptionsUpdater)workspace.ExportProvider.GetExports<IEventListener>().Single(e => e.Value is SolutionAnalyzerConfigOptionsUpdater).Value;
        var listenerProvider = workspace.GetService<MockWorkspaceEventListenerProvider>();
        listenerProvider.EventListeners = [updater];
 
        return workspace;
    }
 
    [Fact]
    public void FlowsGlobalOptionsToWorkspace()
    {
        using var workspace = CreateWorkspace();
 
        var globalOptions = workspace.GetService<IGlobalOptionService>();
 
        // default values:
        Assert.False(globalOptions.GetOption(FormattingOptions2.InsertFinalNewLine));
        Assert.Equal(4, globalOptions.GetOption(FormattingOptions2.IndentationSize, LanguageNames.CSharp));
        Assert.Equal(4, globalOptions.GetOption(FormattingOptions2.IndentationSize, LanguageNames.VisualBasic));
 
        // C# project hasn't been loaded to the workspace yet:
        Assert.Empty(workspace.CurrentSolution.FallbackAnalyzerOptions);
 
        var project = new TestHostProject(workspace, "proj1", LanguageNames.CSharp);
        workspace.AddTestProject(project);
 
        AssertOptionValue(FormattingOptions2.InsertFinalNewLine, LanguageNames.CSharp, "false");
        AssertOptionValue(FormattingOptions2.IndentationSize, LanguageNames.CSharp, "4");
 
        globalOptions.SetGlobalOptions(
        [
            new KeyValuePair<OptionKey2, object?>(FormattingOptions2.InsertFinalNewLine, true),
            new KeyValuePair<OptionKey2, object?>(new OptionKey2(FormattingOptions2.IndentationSize, LanguageNames.CSharp), 3),
            new KeyValuePair<OptionKey2, object?>(new OptionKey2(FormattingOptions2.IndentationSize, LanguageNames.VisualBasic), 5)
        ]);
 
        // editorconfig option set as a global option should flow to the solution snapshot:
        AssertOptionValue(FormattingOptions2.InsertFinalNewLine, LanguageNames.CSharp, "true");
        AssertOptionValue(FormattingOptions2.IndentationSize, LanguageNames.CSharp, "3");
 
        workspace.OnProjectRemoved(project.Id);
 
        // last C# project removed -> fallback options removed:
        Assert.Empty(workspace.CurrentSolution.FallbackAnalyzerOptions);
 
        workspace.AddTestProject(new TestHostProject(workspace, "proj2", LanguageNames.VisualBasic));
 
        AssertOptionValue(FormattingOptions2.InsertFinalNewLine, LanguageNames.VisualBasic, "true");
        AssertOptionValue(FormattingOptions2.IndentationSize, LanguageNames.VisualBasic, "5");
 
        Assert.False(workspace.CurrentSolution.FallbackAnalyzerOptions.TryGetValue(LanguageNames.CSharp, out _));
 
        // VB and C# projects added:
 
        workspace.AddTestProject(new TestHostProject(workspace, "proj3", LanguageNames.CSharp));
 
        AssertOptionValue(FormattingOptions2.InsertFinalNewLine, LanguageNames.VisualBasic, "true");
        AssertOptionValue(FormattingOptions2.InsertFinalNewLine, LanguageNames.CSharp, "true");
        AssertOptionValue(FormattingOptions2.IndentationSize, LanguageNames.VisualBasic, "5");
        AssertOptionValue(FormattingOptions2.IndentationSize, LanguageNames.CSharp, "3");
 
        globalOptions.SetGlobalOption(FormattingOptions2.InsertFinalNewLine, false);
 
        AssertOptionValue(FormattingOptions2.InsertFinalNewLine, LanguageNames.VisualBasic, "false");
        AssertOptionValue(FormattingOptions2.InsertFinalNewLine, LanguageNames.CSharp, "false");
        AssertOptionValue(FormattingOptions2.IndentationSize, LanguageNames.VisualBasic, "5");
        AssertOptionValue(FormattingOptions2.IndentationSize, LanguageNames.CSharp, "3");
 
        void AssertOptionValue(IOption2 option, string language, string expectedValue)
        {
            Assert.True(workspace.CurrentSolution.FallbackAnalyzerOptions.TryGetValue(language, out var fallbackOptions));
            Assert.True(fallbackOptions!.TryGetValue(option.Definition.ConfigName, out var configValue));
            Assert.Equal(expectedValue, configValue);
        }
    }
 
    [Fact]
    public void IgnoresNonEditorConfigOptions()
    {
        using var workspace = CreateWorkspace();
 
        var globalOptions = workspace.GetService<IGlobalOptionService>();
 
        var option = new Option2<bool>("test_option", defaultValue: false, isEditorConfigOption: false);
 
        Assert.False(globalOptions.GetOption(option));
        Assert.Empty(workspace.CurrentSolution.FallbackAnalyzerOptions);
 
        var project = new TestHostProject(workspace, "proj1", LanguageNames.CSharp);
        workspace.AddTestProject(project);
 
        var optionsAfterProjectAdded = workspace.CurrentSolution.FallbackAnalyzerOptions;
 
        Assert.NotEmpty(optionsAfterProjectAdded);
        Assert.False(optionsAfterProjectAdded.ContainsKey("test_option"));
 
        globalOptions.SetGlobalOption(option, true);
 
        Assert.Same(optionsAfterProjectAdded, workspace.CurrentSolution.FallbackAnalyzerOptions);
    }
}