File: Diagnostics\NamingStyles\EditorConfigNamingStyleParserTests.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.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.
 
#nullable disable
 
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.NamingStyles;
using Roslyn.Test.Utilities;
using Xunit;
using static Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles.SymbolSpecification;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.NamingStyles;
 
public class EditorConfigNamingStyleParserTests
{
    private static NamingStylePreferences ParseDictionary(Dictionary<string, string> options)
        => EditorConfigNamingStyleParser.ParseDictionary(new DictionaryAnalyzerConfigOptions(options.ToImmutableDictionary()));
 
    [Fact]
    public static void TestPascalCaseRule()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.methods_and_properties_must_be_pascal_case.severity"] = "warning",
            ["dotnet_naming_rule.methods_and_properties_must_be_pascal_case.symbols"] = "method_and_property_symbols",
            ["dotnet_naming_rule.methods_and_properties_must_be_pascal_case.style"] = "pascal_case_style",
            ["dotnet_naming_symbols.method_and_property_symbols.applicable_kinds"] = "method,property",
            ["dotnet_naming_symbols.method_and_property_symbols.applicable_accessibilities"] = "*",
            ["dotnet_naming_style.pascal_case_style.capitalization"] = "pascal_case"
        };
        var result = ParseDictionary(dictionary);
        Assert.Single(result.NamingRules);
        var namingRule = result.NamingRules.Single();
        Assert.Single(result.NamingStyles);
        var namingStyle = result.NamingStyles.Single();
        Assert.Single(result.SymbolSpecifications);
        var symbolSpec = result.SymbolSpecifications.Single();
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Warn, namingRule.EnforcementLevel);
        Assert.Equal("method_and_property_symbols", symbolSpec.Name);
        var expectedApplicableSymbolKindList = new[]
        {
            new SymbolKindOrTypeKind(MethodKind.Ordinary),
            new SymbolKindOrTypeKind(SymbolKind.Property)
        };
        AssertEx.SetEqual(expectedApplicableSymbolKindList, symbolSpec.ApplicableSymbolKindList);
        Assert.Empty(symbolSpec.RequiredModifierList);
        var expectedApplicableAccessibilityList = new[]
        {
            Accessibility.NotApplicable,
            Accessibility.Public,
            Accessibility.Internal,
            Accessibility.Private,
            Accessibility.Protected,
            Accessibility.ProtectedAndInternal,
            Accessibility.ProtectedOrInternal
        };
        AssertEx.SetEqual(expectedApplicableAccessibilityList, symbolSpec.ApplicableAccessibilityList);
        Assert.Equal("pascal_case_style", namingStyle.Name);
        Assert.Equal("", namingStyle.Prefix);
        Assert.Equal("", namingStyle.Suffix);
        Assert.Equal("", namingStyle.WordSeparator);
        Assert.Equal(Capitalization.PascalCase, namingStyle.CapitalizationScheme);
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/40705")]
    public static void TestPascalCaseRuleWithKeyCapitalization()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.methods_and_properties_must_be_pascal_case.severity"] = "warning",
            ["dotnet_naming_rule.methods_and_properties_must_be_pascal_case.symbols"] = "Method_and_Property_symbols",
            ["dotnet_naming_rule.methods_and_properties_must_be_pascal_case.style"] = "Pascal_Case_style",
            ["dotnet_naming_symbols.method_and_property_symbols.applicable_kinds"] = "method,property",
            ["dotnet_naming_symbols.method_and_property_symbols.applicable_accessibilities"] = "*",
            ["dotnet_naming_style.pascal_case_style.capitalization"] = "pascal_case"
        };
        var result = ParseDictionary(dictionary);
        var namingRule = Assert.Single(result.NamingRules);
        var namingStyle = Assert.Single(result.NamingStyles);
        var symbolSpec = Assert.Single(result.SymbolSpecifications);
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Warn, namingRule.EnforcementLevel);
    }
 
    [Fact]
    public static void TestAsyncMethodsAndLocalFunctionsRule()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.async_methods_must_end_with_async.severity"] = "error",
            ["dotnet_naming_rule.async_methods_must_end_with_async.symbols"] = "method_symbols",
            ["dotnet_naming_rule.async_methods_must_end_with_async.style"] = "end_in_async_style",
            ["dotnet_naming_symbols.method_symbols.applicable_kinds"] = "method,local_function",
            ["dotnet_naming_symbols.method_symbols.required_modifiers"] = "async",
            ["dotnet_naming_style.end_in_async_style.capitalization "] = "pascal_case",
            ["dotnet_naming_style.end_in_async_style.required_suffix"] = "Async",
        };
        var result = ParseDictionary(dictionary);
        Assert.Single(result.NamingRules);
        var namingRule = result.NamingRules.Single();
        Assert.Single(result.NamingStyles);
        var namingStyle = result.NamingStyles.Single();
        Assert.Single(result.SymbolSpecifications);
        var symbolSpec = result.SymbolSpecifications.Single();
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Error, namingRule.EnforcementLevel);
        Assert.Equal("method_symbols", symbolSpec.Name);
        var expectedApplicableSymbolKindList = new[]
        {
            new SymbolKindOrTypeKind(MethodKind.Ordinary),
            new SymbolKindOrTypeKind(MethodKind.LocalFunction)
        };
        AssertEx.SetEqual(expectedApplicableSymbolKindList, symbolSpec.ApplicableSymbolKindList);
        Assert.Single(symbolSpec.RequiredModifierList);
        Assert.Contains(new ModifierKind(ModifierKindEnum.IsAsync), symbolSpec.RequiredModifierList);
        Assert.Equal(
            new[] { Accessibility.NotApplicable, Accessibility.Public, Accessibility.Internal, Accessibility.Private, Accessibility.Protected, Accessibility.ProtectedAndInternal, Accessibility.ProtectedOrInternal },
            symbolSpec.ApplicableAccessibilityList);
        Assert.Equal("end_in_async_style", namingStyle.Name);
        Assert.Equal("", namingStyle.Prefix);
        Assert.Equal("Async", namingStyle.Suffix);
        Assert.Equal("", namingStyle.WordSeparator);
        Assert.Equal(Capitalization.PascalCase, namingStyle.CapitalizationScheme);
    }
 
    [Fact]
    public static void TestRuleWithoutCapitalization()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.async_methods_must_end_with_async.symbols"] = "any_async_methods",
            ["dotnet_naming_rule.async_methods_must_end_with_async.style"] = "end_in_async",
            ["dotnet_naming_rule.async_methods_must_end_with_async.severity"] = "suggestion",
            ["dotnet_naming_symbols.any_async_methods.applicable_kinds"] = "method",
            ["dotnet_naming_symbols.any_async_methods.applicable_accessibilities"] = "*",
            ["dotnet_naming_symbols.any_async_methods.required_modifiers"] = "async",
            ["dotnet_naming_style.end_in_async.required_suffix"] = "Async",
        };
        var result = ParseDictionary(dictionary);
        Assert.Empty(result.NamingStyles);
    }
 
    [Fact]
    public static void TestPublicMembersCapitalizedRule()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.public_members_must_be_capitalized.severity"] = "suggestion",
            ["dotnet_naming_rule.public_members_must_be_capitalized.symbols"] = "public_symbols",
            ["dotnet_naming_rule.public_members_must_be_capitalized.style"] = "first_word_upper_case_style",
            ["dotnet_naming_symbols.public_symbols.applicable_kinds"] = "property,method,field,event,delegate",
            ["dotnet_naming_symbols.public_symbols.applicable_accessibilities"] = "public,internal,protected,protected_internal",
            ["dotnet_naming_style.first_word_upper_case_style.capitalization"] = "first_word_upper",
        };
        var result = ParseDictionary(dictionary);
        Assert.Single(result.NamingRules);
        var namingRule = result.NamingRules.Single();
        Assert.Single(result.NamingStyles);
        var namingStyle = result.NamingStyles.Single();
        Assert.Single(result.SymbolSpecifications);
        var symbolSpec = result.SymbolSpecifications.Single();
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Info, namingRule.EnforcementLevel);
        Assert.Equal("public_symbols", symbolSpec.Name);
        var expectedApplicableSymbolKindList = new[]
        {
            new SymbolKindOrTypeKind(SymbolKind.Property),
            new SymbolKindOrTypeKind(MethodKind.Ordinary),
            new SymbolKindOrTypeKind(SymbolKind.Field),
            new SymbolKindOrTypeKind(SymbolKind.Event),
            new SymbolKindOrTypeKind(TypeKind.Delegate)
        };
        AssertEx.SetEqual(expectedApplicableSymbolKindList, symbolSpec.ApplicableSymbolKindList);
        var expectedApplicableAccessibilityList = new[]
        {
            Accessibility.Public,
            Accessibility.Internal,
            Accessibility.Protected,
            Accessibility.ProtectedOrInternal
        };
        AssertEx.SetEqual(expectedApplicableAccessibilityList, symbolSpec.ApplicableAccessibilityList);
        Assert.Empty(symbolSpec.RequiredModifierList);
        Assert.Equal("first_word_upper_case_style", namingStyle.Name);
        Assert.Equal("", namingStyle.Prefix);
        Assert.Equal("", namingStyle.Suffix);
        Assert.Equal("", namingStyle.WordSeparator);
        Assert.Equal(Capitalization.FirstUpper, namingStyle.CapitalizationScheme);
    }
 
    [Fact]
    public static void TestNonPublicMembersLowerCaseRule()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.non_public_members_must_be_lower_case.severity"] = "incorrect",
            ["dotnet_naming_rule.non_public_members_must_be_lower_case.symbols "] = "non_public_symbols",
            ["dotnet_naming_rule.non_public_members_must_be_lower_case.style   "] = "all_lower_case_style",
            ["dotnet_naming_symbols.non_public_symbols.applicable_kinds  "] = "property,method,field,event,delegate",
            ["dotnet_naming_symbols.non_public_symbols.applicable_accessibilities"] = "private",
            ["dotnet_naming_style.all_lower_case_style.capitalization"] = "all_lower",
        };
        var result = ParseDictionary(dictionary);
        Assert.Single(result.NamingRules);
        var namingRule = result.NamingRules.Single();
        Assert.Single(result.NamingStyles);
        var namingStyle = result.NamingStyles.Single();
        Assert.Single(result.SymbolSpecifications);
        var symbolSpec = result.SymbolSpecifications.Single();
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Hidden, namingRule.EnforcementLevel);
        Assert.Equal("non_public_symbols", symbolSpec.Name);
        var expectedApplicableSymbolKindList = new[]
        {
            new SymbolKindOrTypeKind(SymbolKind.Property),
            new SymbolKindOrTypeKind(MethodKind.Ordinary),
            new SymbolKindOrTypeKind(SymbolKind.Field),
            new SymbolKindOrTypeKind(SymbolKind.Event),
            new SymbolKindOrTypeKind(TypeKind.Delegate)
        };
        AssertEx.SetEqual(expectedApplicableSymbolKindList, symbolSpec.ApplicableSymbolKindList);
        Assert.Single(symbolSpec.ApplicableAccessibilityList);
        Assert.Contains(Accessibility.Private, symbolSpec.ApplicableAccessibilityList);
        Assert.Empty(symbolSpec.RequiredModifierList);
        Assert.Equal("all_lower_case_style", namingStyle.Name);
        Assert.Equal("", namingStyle.Prefix);
        Assert.Equal("", namingStyle.Suffix);
        Assert.Equal("", namingStyle.WordSeparator);
        Assert.Equal(Capitalization.AllLower, namingStyle.CapitalizationScheme);
    }
 
    [Fact]
    public static void TestParametersAndLocalsAreCamelCaseRule()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.parameters_and_locals_are_camel_case.severity"] = "suggestion",
            ["dotnet_naming_rule.parameters_and_locals_are_camel_case.symbols"] = "parameters_and_locals",
            ["dotnet_naming_rule.parameters_and_locals_are_camel_case.style"] = "camel_case_style",
            ["dotnet_naming_symbols.parameters_and_locals.applicable_kinds"] = "parameter,local",
            ["dotnet_naming_style.camel_case_style.capitalization"] = "camel_case",
        };
 
        var result = ParseDictionary(dictionary);
        Assert.Single(result.NamingRules);
        var namingRule = result.NamingRules.Single();
        Assert.Single(result.NamingStyles);
        var namingStyle = result.NamingStyles.Single();
        Assert.Single(result.SymbolSpecifications);
 
        var symbolSpec = result.SymbolSpecifications.Single();
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Info, namingRule.EnforcementLevel);
 
        Assert.Equal("parameters_and_locals", symbolSpec.Name);
        var expectedApplicableSymbolKindList = new[]
        {
            new SymbolKindOrTypeKind(SymbolKind.Parameter),
            new SymbolKindOrTypeKind(SymbolKind.Local),
        };
        AssertEx.SetEqual(expectedApplicableSymbolKindList, symbolSpec.ApplicableSymbolKindList);
        Assert.Equal(
            new[] { Accessibility.NotApplicable, Accessibility.Public, Accessibility.Internal, Accessibility.Private, Accessibility.Protected, Accessibility.ProtectedAndInternal, Accessibility.ProtectedOrInternal },
            symbolSpec.ApplicableAccessibilityList);
        Assert.Empty(symbolSpec.RequiredModifierList);
 
        Assert.Equal("camel_case_style", namingStyle.Name);
        Assert.Equal("", namingStyle.Prefix);
        Assert.Equal("", namingStyle.Suffix);
        Assert.Equal("", namingStyle.WordSeparator);
        Assert.Equal(Capitalization.CamelCase, namingStyle.CapitalizationScheme);
    }
 
    [Fact]
    public static void TestLocalFunctionsAreCamelCaseRule()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.local_functions_are_camel_case.severity"] = "suggestion",
            ["dotnet_naming_rule.local_functions_are_camel_case.symbols"] = "local_functions",
            ["dotnet_naming_rule.local_functions_are_camel_case.style"] = "camel_case_style",
            ["dotnet_naming_symbols.local_functions.applicable_kinds"] = "local_function",
            ["dotnet_naming_style.camel_case_style.capitalization"] = "camel_case",
        };
 
        var result = ParseDictionary(dictionary);
        Assert.Single(result.NamingRules);
        var namingRule = result.NamingRules.Single();
        Assert.Single(result.NamingStyles);
        var namingStyle = result.NamingStyles.Single();
        Assert.Single(result.SymbolSpecifications);
 
        var symbolSpec = result.SymbolSpecifications.Single();
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Info, namingRule.EnforcementLevel);
 
        Assert.Equal("local_functions", symbolSpec.Name);
        var expectedApplicableSymbolKindList = new[] { new SymbolKindOrTypeKind(MethodKind.LocalFunction) };
        AssertEx.SetEqual(expectedApplicableSymbolKindList, symbolSpec.ApplicableSymbolKindList);
        Assert.Equal(
            new[] { Accessibility.NotApplicable, Accessibility.Public, Accessibility.Internal, Accessibility.Private, Accessibility.Protected, Accessibility.ProtectedAndInternal, Accessibility.ProtectedOrInternal },
            symbolSpec.ApplicableAccessibilityList);
        Assert.Empty(symbolSpec.RequiredModifierList);
 
        Assert.Equal("camel_case_style", namingStyle.Name);
        Assert.Equal("", namingStyle.Prefix);
        Assert.Equal("", namingStyle.Suffix);
        Assert.Equal("", namingStyle.WordSeparator);
        Assert.Equal(Capitalization.CamelCase, namingStyle.CapitalizationScheme);
    }
 
    [Fact]
    public static void TestNoRulesAreReturned()
    {
        var dictionary = new Dictionary<string, string>()
        {
            ["dotnet_naming_symbols.non_public_symbols.applicable_kinds  "] = "property,method,field,event,delegate",
            ["dotnet_naming_symbols.non_public_symbols.applicable_accessibilities"] = "private",
            ["dotnet_naming_style.all_lower_case_style.capitalization"] = "all_lower",
        };
        var result = ParseDictionary(dictionary);
        Assert.Empty(result.NamingRules);
        Assert.Empty(result.NamingStyles);
        Assert.Empty(result.SymbolSpecifications);
    }
 
    [Theory]
    [InlineData("property,method", new object[] { SymbolKind.Property, MethodKind.Ordinary })]
    [InlineData("namespace", new object[] { SymbolKind.Namespace })]
    [InlineData("type_parameter", new object[] { SymbolKind.TypeParameter })]
    [InlineData("interface", new object[] { TypeKind.Interface })]
    [InlineData("*", new object[] { SymbolKind.Namespace, TypeKind.Class, TypeKind.Struct, TypeKind.Interface, TypeKind.Enum, SymbolKind.Property, MethodKind.Ordinary, MethodKind.LocalFunction, SymbolKind.Field, SymbolKind.Event, TypeKind.Delegate, SymbolKind.Parameter, SymbolKind.TypeParameter, SymbolKind.Local })]
    [InlineData(null, new object[] { SymbolKind.Namespace, TypeKind.Class, TypeKind.Struct, TypeKind.Interface, TypeKind.Enum, SymbolKind.Property, MethodKind.Ordinary, MethodKind.LocalFunction, SymbolKind.Field, SymbolKind.Event, TypeKind.Delegate, SymbolKind.Parameter, SymbolKind.TypeParameter, SymbolKind.Local })]
    [InlineData("property,method,invalid", new object[] { SymbolKind.Property, MethodKind.Ordinary })]
    [InlineData("invalid", new object[] { })]
    [InlineData("", new object[] { })]
    [WorkItem("https://github.com/dotnet/roslyn/issues/20907")]
    public static void TestApplicableKindsParse(string specification, object[] typeOrSymbolKinds)
    {
        var rule = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.kinds_parse.severity"] = "error",
            ["dotnet_naming_rule.kinds_parse.symbols"] = "kinds",
            ["dotnet_naming_rule.kinds_parse.style"] = "pascal_case",
            ["dotnet_naming_style.pascal_case.capitalization "] = "pascal_case",
        };
 
        if (specification != null)
        {
            rule["dotnet_naming_symbols.kinds.applicable_kinds"] = specification;
        }
 
        var kinds = typeOrSymbolKinds.Select(NamingStylesTestOptionSets.ToSymbolKindOrTypeKind).ToArray();
        var result = ParseDictionary(rule);
        Assert.Equal(kinds, result.SymbolSpecifications.SelectMany(x => x.ApplicableSymbolKindList));
    }
 
    [Theory]
    [InlineData("internal,protected_internal", new[] { Accessibility.Internal, Accessibility.ProtectedOrInternal })]
    [InlineData("friend,protected_friend", new[] { Accessibility.Friend, Accessibility.ProtectedOrFriend })]
    [InlineData("private_protected", new[] { Accessibility.ProtectedAndInternal })]
    [InlineData("local", new[] { Accessibility.NotApplicable })]
    [InlineData("*", new[] { Accessibility.NotApplicable, Accessibility.Public, Accessibility.Internal, Accessibility.Private, Accessibility.Protected, Accessibility.ProtectedAndInternal, Accessibility.ProtectedOrInternal })]
    [InlineData(null, new[] { Accessibility.NotApplicable, Accessibility.Public, Accessibility.Internal, Accessibility.Private, Accessibility.Protected, Accessibility.ProtectedAndInternal, Accessibility.ProtectedOrInternal })]
    [InlineData("internal,protected,invalid", new[] { Accessibility.Internal, Accessibility.Protected })]
    [InlineData("invalid", new Accessibility[] { })]
    [InlineData("", new Accessibility[] { })]
    [WorkItem("https://github.com/dotnet/roslyn/issues/20907")]
    public static void TestApplicableAccessibilitiesParse(string specification, Accessibility[] accessibilities)
    {
        var rule = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.accessibilities_parse.severity"] = "error",
            ["dotnet_naming_rule.accessibilities_parse.symbols"] = "accessibilities",
            ["dotnet_naming_rule.accessibilities_parse.style"] = "pascal_case",
            ["dotnet_naming_style.pascal_case.capitalization "] = "pascal_case",
        };
 
        if (specification != null)
        {
            rule["dotnet_naming_symbols.accessibilities.applicable_accessibilities"] = specification;
        }
 
        var result = ParseDictionary(rule);
        Assert.Equal(accessibilities, result.SymbolSpecifications.SelectMany(x => x.ApplicableAccessibilityList));
    }
 
    [Fact]
    public static void TestRequiredModifiersParse()
    {
        var charpRule = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.modifiers_parse.severity"] = "error",
            ["dotnet_naming_rule.modifiers_parse.symbols"] = "modifiers",
            ["dotnet_naming_rule.modifiers_parse.style"] = "pascal_case",
            ["dotnet_naming_symbols.modifiers.required_modifiers"] = "abstract,static",
            ["dotnet_naming_style.pascal_case.capitalization "] = "pascal_case",
        };
        var vbRule = new Dictionary<string, string>()
        {
            ["dotnet_naming_rule.modifiers_parse.severity"] = "error",
            ["dotnet_naming_rule.modifiers_parse.symbols"] = "modifiers",
            ["dotnet_naming_rule.modifiers_parse.style"] = "pascal_case",
            ["dotnet_naming_symbols.modifiers.required_modifiers"] = "must_inherit,shared",
            ["dotnet_naming_style.pascal_case.capitalization "] = "pascal_case",
        };
 
        var csharpResult = ParseDictionary(charpRule);
        var vbResult = ParseDictionary(vbRule);
 
        Assert.Equal(csharpResult.SymbolSpecifications.SelectMany(x => x.RequiredModifierList.Select(y => y.Modifier)),
                     vbResult.SymbolSpecifications.SelectMany(x => x.RequiredModifierList.Select(y => y.Modifier)));
        Assert.Equal(csharpResult.SymbolSpecifications.SelectMany(x => x.RequiredModifierList.Select(y => y.ModifierKindWrapper)),
                     vbResult.SymbolSpecifications.SelectMany(x => x.RequiredModifierList.Select(y => y.ModifierKindWrapper)));
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/38513")]
    public static void TestPrefixParse()
    {
        var rule = new Dictionary<string, string>()
        {
            ["dotnet_naming_style.pascal_case_and_prefix_style.required_prefix"] = "I",
            ["dotnet_naming_style.pascal_case_and_prefix_style.capitalization"] = "pascal_case",
            ["dotnet_naming_symbols.symbols.applicable_kinds"] = "interface",
            ["dotnet_naming_symbols.symbols.applicable_accessibilities"] = "*",
            ["dotnet_naming_rule.must_be_pascal_cased_and_prefixed.symbols"] = "symbols",
            ["dotnet_naming_rule.must_be_pascal_cased_and_prefixed.style"] = "pascal_case_and_prefix_style",
            ["dotnet_naming_rule.must_be_pascal_cased_and_prefixed.severity"] = "warning",
        };
 
        var result = ParseDictionary(rule);
        Assert.Single(result.NamingRules);
        var namingRule = result.NamingRules.Single();
        Assert.Single(result.NamingStyles);
        var namingStyle = result.NamingStyles.Single();
        Assert.Single(result.SymbolSpecifications);
        var symbolSpec = result.SymbolSpecifications.Single();
        Assert.Equal(namingStyle.ID, namingRule.NamingStyleID);
        Assert.Equal(symbolSpec.ID, namingRule.SymbolSpecificationID);
        Assert.Equal(ReportDiagnostic.Warn, namingRule.EnforcementLevel);
        Assert.Equal("symbols", symbolSpec.Name);
        var expectedApplicableTypeKindList = new[] { new SymbolKindOrTypeKind(TypeKind.Interface) };
        AssertEx.SetEqual(expectedApplicableTypeKindList, symbolSpec.ApplicableSymbolKindList);
        Assert.Equal("pascal_case_and_prefix_style", namingStyle.Name);
        Assert.Equal("I", namingStyle.Prefix);
        Assert.Equal("", namingStyle.Suffix);
        Assert.Equal("", namingStyle.WordSeparator);
        Assert.Equal(Capitalization.PascalCase, namingStyle.CapitalizationScheme);
    }
 
    [Fact]
    public static void TestEditorConfigParseForApplicableSymbolKinds()
    {
        var symbolSpecifications = CreateDefaultSymbolSpecification();
        foreach (var applicableSymbolKind in symbolSpecifications.ApplicableSymbolKindList)
        {
            var editorConfigString = EditorConfigNamingStyleParser.ToEditorConfigString(ImmutableArray.Create(applicableSymbolKind));
            Assert.True(!string.IsNullOrEmpty(editorConfigString));
        }
    }
 
    [Theory]
    [InlineData("a", "b", "a", "public", "public, private")]
    [InlineData("b", "a", "a", "public, private", "public")]
    [InlineData("b", "a", "b", "public", "public, private")]
    [InlineData("a", "b", "b", "public, private", "public")]
    [InlineData("a", "b", "a", "*", "*")]
    [InlineData("b", "a", "a", "*", "*")]
    [InlineData("A", "b", "A", "*", "*")]
    [InlineData("b", "A", "A", "*", "*")]
    [InlineData("a", "B", "a", "*", "*")]
    [InlineData("B", "a", "a", "*", "*")]
    [InlineData("A", "B", "A", "*", "*")]
    [InlineData("B", "A", "A", "*", "*")]
    public static void TestOrderedByAccessibilityBeforeName(string firstName, string secondName, string firstNameAfterOrdering, string firstAccessibility, string secondAccessibility)
    {
        var namingStylePreferences = ParseDictionary(new Dictionary<string, string>()
        {
            [$"dotnet_naming_rule.{firstName}.severity"] = "error",
            [$"dotnet_naming_rule.{firstName}.symbols"] = "first_symbols",
            [$"dotnet_naming_rule.{firstName}.style"] = $"{firstName}_style",
            ["dotnet_naming_symbols.first_symbols.applicable_kinds"] = "method,property",
            ["dotnet_naming_symbols.first_symbols.applicable_accessibilities"] = firstAccessibility,
            [$"dotnet_naming_style.{firstName}_style.capitalization"] = "pascal_case",
            [$"dotnet_naming_style.{secondName}_style.capitalization"] = "camel_case",
            [$"dotnet_naming_rule.{secondName}.severity"] = "error",
            [$"dotnet_naming_rule.{secondName}.symbols"] = "second_symbols",
            [$"dotnet_naming_rule.{secondName}.style"] = $"{secondName}_style",
            ["dotnet_naming_symbols.second_symbols.applicable_kinds"] = "method,property",
            ["dotnet_naming_symbols.second_symbols.applicable_accessibilities"] = secondAccessibility,
        });
 
        var secondNameAfterOrdering = firstNameAfterOrdering == firstName ? secondName : firstName;
        Assert.Equal($"{firstNameAfterOrdering}_style", namingStylePreferences.Rules.NamingRules[0].NamingStyle.Name);
        Assert.Equal($"{secondNameAfterOrdering}_style", namingStylePreferences.Rules.NamingRules[1].NamingStyle.Name);
    }
 
    [Theory]
    [InlineData("a", "b", "a", "static, readonly", "static")]
    [InlineData("b", "a", "a", "static", "static, readonly")]
    [InlineData("b", "a", "b", "static, readonly", "static")]
    [InlineData("a", "b", "b", "static", "static, readonly")]
    [InlineData("a", "b", "a", "", "")]
    [InlineData("b", "a", "a", "", "")]
    [InlineData("A", "b", "A", "", "")]
    [InlineData("b", "A", "A", "", "")]
    [InlineData("a", "B", "a", "", "")]
    [InlineData("B", "a", "a", "", "")]
    [InlineData("A", "B", "A", "", "")]
    [InlineData("B", "A", "A", "", "")]
    public static void TestOrderedByModifiersBeforeName(string firstName, string secondName, string firstNameAfterOrdering, string firstModifiers, string secondModifiers)
    {
        var namingStylePreferences = ParseDictionary(new Dictionary<string, string>()
        {
            [$"dotnet_naming_rule.{firstName}.severity"] = "error",
            [$"dotnet_naming_rule.{firstName}.symbols"] = "first_symbols",
            [$"dotnet_naming_rule.{firstName}.style"] = $"{firstName}_style",
            ["dotnet_naming_symbols.first_symbols.applicable_kinds"] = "method,property",
            ["dotnet_naming_symbols.first_symbols.required_modifiers"] = firstModifiers,
            [$"dotnet_naming_style.{firstName}_style.capitalization"] = "pascal_case",
            [$"dotnet_naming_style.{secondName}_style.capitalization"] = "camel_case",
            [$"dotnet_naming_rule.{secondName}.severity"] = "error",
            [$"dotnet_naming_rule.{secondName}.symbols"] = "second_symbols",
            [$"dotnet_naming_rule.{secondName}.style"] = $"{secondName}_style",
            ["dotnet_naming_symbols.second_symbols.applicable_kinds"] = "method,property",
            ["dotnet_naming_symbols.second_symbols.required_modifiers"] = secondModifiers,
        });
 
        var secondNameAfterOrdering = firstNameAfterOrdering == firstName ? secondName : firstName;
        Assert.Equal($"{firstNameAfterOrdering}_style", namingStylePreferences.Rules.NamingRules[0].NamingStyle.Name);
        Assert.Equal($"{secondNameAfterOrdering}_style", namingStylePreferences.Rules.NamingRules[1].NamingStyle.Name);
    }
 
    [Theory]
    [InlineData("a", "b", "a", "method", "method, property")]
    [InlineData("b", "a", "a", "method, property", "method")]
    [InlineData("b", "a", "b", "method", "method, property")]
    [InlineData("a", "b", "b", "method, property", "method")]
    [InlineData("a", "b", "a", "*", "*")]
    [InlineData("b", "a", "a", "*", "*")]
    [InlineData("A", "b", "A", "*", "*")]
    [InlineData("b", "A", "A", "*", "*")]
    [InlineData("a", "B", "a", "*", "*")]
    [InlineData("B", "a", "a", "*", "*")]
    [InlineData("A", "B", "A", "*", "*")]
    [InlineData("B", "A", "A", "*", "*")]
    public static void TestOrderedBySymbolsBeforeName(string firstName, string secondName, string firstNameAfterOrdering, string firstSymbols, string secondSymbols)
    {
        var namingStylePreferences = ParseDictionary(new Dictionary<string, string>()
        {
            [$"dotnet_naming_rule.{firstName}.severity"] = "error",
            [$"dotnet_naming_rule.{firstName}.symbols"] = "first_symbols",
            [$"dotnet_naming_rule.{firstName}.style"] = $"{firstName}_style",
            ["dotnet_naming_symbols.first_symbols.applicable_kinds"] = firstSymbols,
            [$"dotnet_naming_style.{firstName}_style.capitalization"] = "pascal_case",
            [$"dotnet_naming_style.{secondName}_style.capitalization"] = "camel_case",
            [$"dotnet_naming_rule.{secondName}.severity"] = "error",
            [$"dotnet_naming_rule.{secondName}.symbols"] = "second_symbols",
            [$"dotnet_naming_rule.{secondName}.style"] = $"{secondName}_style",
            ["dotnet_naming_symbols.second_symbols.applicable_kinds"] = secondSymbols,
        });
 
        var secondNameAfterOrdering = firstNameAfterOrdering == firstName ? secondName : firstName;
        Assert.Equal($"{firstNameAfterOrdering}_style", namingStylePreferences.Rules.NamingRules[0].NamingStyle.Name);
        Assert.Equal($"{secondNameAfterOrdering}_style", namingStylePreferences.Rules.NamingRules[1].NamingStyle.Name);
    }
}