File: EditorConfigParsing\EditorConfigFileParserTests.cs
Web Access
Project: src\src\Workspaces\CoreTest\Microsoft.CodeAnalysis.Workspaces.UnitTests.csproj (Microsoft.CodeAnalysis.Workspaces.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 Microsoft.CodeAnalysis.EditorConfig;
using Microsoft.CodeAnalysis.EditorConfig.Parsing;
using Microsoft.CodeAnalysis.Text;
using Xunit;
 
namespace Microsoft.CodeAnalysis.UnitTests.EditorConfigParsing;
 
public sealed class EditorConfigFileParserTests
{
    internal static EditorConfigFile<EditorConfigOption> CreateParseResults(string editorconfigFilePath, params (string headerText, TextSpan span, bool isGlobal)[] sections)
    {
        var list = new List<EditorConfigOption>();
        foreach (var (headerText, span, isGlobal) in sections)
        {
            var section = new Section(editorconfigFilePath, isGlobal, span, headerText, $"[{headerText}]");
            var parseResult = new EditorConfigOption<object?>(section, Span: null, Value: null);
            list.Add(parseResult);
        }
 
        return new EditorConfigFile<EditorConfigOption>(editorconfigFilePath, [.. list]);
    }
 
    [Fact]
    internal void TestGetBestSection()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*.cs", TextSpan.FromBounds(10, 19), false),
            ("*.vb", TextSpan.FromBounds(20, 29), false),
            ("*.{cs,vb}", TextSpan.FromBounds(30, 39), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false));
 
        Assert.True(parseResults.TryGetSectionForLanguage(Language.CSharp, out var section));
        Assert.Equal(10, section?.Span.Start);
        Assert.Equal("*.cs", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForLanguage(Language.VisualBasic, out section));
        Assert.Equal(20, section?.Span.Start);
        Assert.Equal("*.vb", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForLanguage((Language.CSharp | Language.VisualBasic), out section));
        Assert.Equal(30, section?.Span.Start);
        Assert.Equal("*.{cs,vb}", section?.Text);
    }
 
    [Fact]
    internal void TestNoBestSection()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*.vb", TextSpan.FromBounds(20, 29), false),
            ("*.{cs,vb}", TextSpan.FromBounds(30, 39), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*", TextSpan.FromBounds(60, 69), false),
            ("*.{cs,csx}", TextSpan.FromBounds(70, 79), false));
 
        Assert.False(parseResults.TryGetSectionForLanguage(Language.CSharp, out _));
    }
 
    [Fact]
    internal void TestGetBestSectionWithDifferMatchCriteria()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*.vb", TextSpan.FromBounds(20, 29), false),
            ("*.{cs,vb}", TextSpan.FromBounds(30, 39), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*", TextSpan.FromBounds(60, 69), false),
            ("*.{cs,csx}", TextSpan.FromBounds(70, 79), false));
 
        Assert.True(parseResults.TryGetSectionForLanguage(Language.CSharp, SectionMatch.ExactLanguageMatchWithOthers, out var section));
        Assert.Equal(70, section?.Span.Start);
        Assert.Equal("*.{cs,csx}", section?.Text);
    }
 
    [Fact]
    internal void TestGetBestSectionWithAnyPattern()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*.vb", TextSpan.FromBounds(20, 29), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*", TextSpan.FromBounds(60, 69), false),
            ("*.{cs,csx}", TextSpan.FromBounds(70, 79), false));
 
        Assert.True(parseResults.TryGetSectionForLanguage(Language.CSharp, SectionMatch.Any, out var section));
        Assert.Equal(70, section?.Span.Start);
        Assert.Equal("*.{cs,csx}", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForLanguage(Language.VisualBasic, SectionMatch.Any, out section));
        Assert.Equal(20, section?.Span.Start);
        Assert.Equal("*.vb", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForLanguage((Language.CSharp | Language.VisualBasic), SectionMatch.Any, out section));
        Assert.Equal(40, section?.Span.Start);
        Assert.Equal("*.{cs,csx,vb,vbx}", section?.Text);
    }
 
    [Fact]
    internal void TestGetBestSectionForFile()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*.cs", TextSpan.FromBounds(10, 19), false),
            ("*.vb", TextSpan.FromBounds(20, 29), false),
            ("*.{cs,vb}", TextSpan.FromBounds(30, 39), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*", TextSpan.FromBounds(60, 69), false),
            ("*.{cs,csx}", TextSpan.FromBounds(70, 79), false));
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\CSharp\Program.cs", out var section));
        Assert.Equal(10, section?.Span.Start);
        Assert.Equal("*.cs", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\VisualBasic\Program.vb", out section));
        Assert.Equal(20, section?.Span.Start);
        Assert.Equal("*.vb", section?.Text);
    }
 
    [Fact]
    internal void TestGetBestSectionForFilePatternWithDefaults()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("sources/**/*.cs", TextSpan.FromBounds(10, 19), false),
            ("sources/**/*.vb", TextSpan.FromBounds(20, 29), false),
            ("*.{cs,vb}", TextSpan.FromBounds(30, 39), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*", TextSpan.FromBounds(60, 69), false),
            ("*.{cs,csx}", TextSpan.FromBounds(70, 79), false));
 
        Assert.False(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\CSharp\Program.cs", out _));
        Assert.False(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\VisualBasic\Program.vb", out _));
    }
 
    [Fact]
    internal void TestGetBestSectionForFilePattern()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("sources/**/*.cs", TextSpan.FromBounds(10, 19), false),
            ("sources/**/*.vb", TextSpan.FromBounds(20, 29), false),
            ("*.{cs,vb}", TextSpan.FromBounds(30, 39), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*", TextSpan.FromBounds(60, 69), false),
            ("*.{cs,csx}", TextSpan.FromBounds(70, 79), false));
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\CSharp\Program.cs", SectionMatch.Any, out var section));
        Assert.Equal(70, section?.Span.Start);
        Assert.Equal("*.{cs,csx}", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\VisualBasic\Program.vb", SectionMatch.Any, out section));
        Assert.Equal(40, section?.Span.Start);
        Assert.Equal("*.{cs,csx,vb,vbx}", section?.Text);
    }
 
    [Fact]
    internal void TestGetBestSectionForFilePatternTie()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*.{cs,csx,vbx}", TextSpan.FromBounds(30, 39), false),
            ("*.{cs,csx,vb,vbx}", TextSpan.FromBounds(40, 49), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*", TextSpan.FromBounds(60, 69), false));
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\CSharp\Program.cs", SectionMatch.Any, out var section));
        Assert.Equal(30, section?.Span.Start);
        Assert.Equal("*.{cs,csx,vbx}", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\VisualBasic\Program.vb", SectionMatch.Any, out section));
        Assert.Equal(40, section?.Span.Start);
        Assert.Equal("*.{cs,csx,vb,vbx}", section?.Text);
    }
 
    [Fact]
    internal void TestGetBestSectionForSuperetFilePatternTie()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*.*b", TextSpan.FromBounds(30, 39), false),
            ("*.*b", TextSpan.FromBounds(80, 89), false),
            ("*.*b", TextSpan.FromBounds(130, 139), false),
            ("*.*s", TextSpan.FromBounds(40, 49), false),
            ("*.*s", TextSpan.FromBounds(90, 99), false),
            ("*.*s", TextSpan.FromBounds(120, 129), false),
            ("*s", TextSpan.FromBounds(50, 59), false),
            ("*s", TextSpan.FromBounds(100, 109), false),
            ("*", TextSpan.FromBounds(60, 69), false),
            ("*b", TextSpan.FromBounds(70, 79), false),
            ("*b", TextSpan.FromBounds(110, 119), false));
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\CSharp\Program.cs", SectionMatch.Any, out var section));
        Assert.Equal(120, section?.Span.Start);
        Assert.Equal("*.*s", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\VisualBasic\Program.vb", SectionMatch.Any, out section));
        Assert.Equal(130, section?.Span.Start);
        Assert.Equal("*.*b", section?.Text);
    }
 
    [Fact]
    internal void TestGetBestSectionWithSplat()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*s", TextSpan.FromBounds(100, 109), false),
            ("*", TextSpan.FromBounds(60, 69), false));
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\CSharp\Program.cs", SectionMatch.Any, out var section));
        Assert.Equal(100, section?.Span.Start);
        Assert.Equal("*s", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\VisualBasic\Program.vb", SectionMatch.Any, out section));
        Assert.Equal(60, section?.Span.Start);
        Assert.Equal("*", section?.Text);
    }
 
    [Fact]
    internal void TestGetBestSectionWithGlobalSection()
    {
        var parseResults = CreateParseResults(@"C:\dev\.editorconfig",
            (string.Empty, TextSpan.FromBounds(0, 9), true),
            ("*s", TextSpan.FromBounds(100, 109), false));
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\CSharp\Program.cs", SectionMatch.Any, out var section));
        Assert.Equal(100, section?.Span.Start);
        Assert.Equal("*s", section?.Text);
 
        Assert.True(parseResults.TryGetSectionForFilePath(@"C:\dev\sources\VisualBasic\Program.vb", SectionMatch.Any, out section));
        Assert.Equal(0, section?.Span.Start);
        Assert.Equal(string.Empty, section?.Text);
    }
}