File: Options\NamingStylePreferencesTests.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;
using System.Linq;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.Diagnostics.Analyzers.NamingStyles;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.UnitTests.CodeStyle;
 
[Trait(Traits.Feature, Traits.Features.NamingStyle)]
public sealed class NamingStylePreferencesTests
{
    private static string ReserializePreferences(string serializedPreferences)
    {
        var preferences = NamingStylePreferences.FromXElement(XElement.Parse(serializedPreferences));
        return preferences.CreateXElement().ToString();
    }
 
    private static void AssertTrimmedEqual(string expected, string actual)
        => Assert.Equal(expected.Trim(), actual.Trim());
 
    [Fact]
    public void Equality()
    {
        Assert.True(
            NamingStylePreferences.FromXElement(XElement.Parse(NamingStylePreferences.DefaultNamingPreferencesString)).Equals(
            NamingStylePreferences.FromXElement(XElement.Parse(NamingStylePreferences.DefaultNamingPreferencesString))));
    }
 
    [Fact]
    public void TestPreserveDefaultPreferences()
    {
        AssertTrimmedEqual(
            NamingStylePreferences.DefaultNamingPreferencesString,
            ReserializePreferences(NamingStylePreferences.DefaultNamingPreferencesString));
    }
 
    [Fact]
    public void TestCannotUpgrade3To5()
    {
        var serializedPreferences = @"
<NamingPreferencesInfo SerializationVersion=""3"">
  <SymbolSpecifications>
    <SymbolSpecification ID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" Name=""Method"">
      <ApplicableSymbolKindList>
        <SymbolKind>Method</SymbolKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
    <SymbolSpecification ID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" Name=""Property Or Method"">
      <ApplicableSymbolKindList>
        <SymbolKind>Property</SymbolKind>
        <SymbolKind>Method</SymbolKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
  </SymbolSpecifications>
  <NamingStyles>
    <NamingStyle ID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" Name=""Test Pascal Case Rule"" Prefix="""" Suffix="""" WordSeparator="""" CapitalizationScheme=""PascalCase"" />
  </NamingStyles>
  <NamingRules>
    <SerializableNamingRule SymbolSpecificationID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Info"" />
    <SerializableNamingRule SymbolSpecificationID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Error"" />
  </NamingRules>
</NamingPreferencesInfo>";
 
        AssertTrimmedEqual(
            NamingStylePreferences.DefaultNamingPreferencesString,
            ReserializePreferences(serializedPreferences));
    }
 
    [Fact]
    public void TestUpgrade4To5()
    {
        var serializedPreferences = @"
<NamingPreferencesInfo SerializationVersion=""4"">
  <SymbolSpecifications>
    <SymbolSpecification ID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" Name=""Method"">
      <ApplicableSymbolKindList>
        <SymbolKind>Method</SymbolKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
    <SymbolSpecification ID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" Name=""Property Or Method"">
      <ApplicableSymbolKindList>
        <SymbolKind>Property</SymbolKind>
        <SymbolKind>Method</SymbolKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
  </SymbolSpecifications>
  <NamingStyles>
    <NamingStyle ID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" Name=""Test Pascal Case Rule"" Prefix="""" Suffix="""" WordSeparator="""" CapitalizationScheme=""PascalCase"" />
  </NamingStyles>
  <NamingRules>
    <SerializableNamingRule SymbolSpecificationID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Info"" />
    <SerializableNamingRule SymbolSpecificationID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Error"" />
  </NamingRules>
</NamingPreferencesInfo>";
 
        AssertTrimmedEqual(
            serializedPreferences
                .Replace("SerializationVersion=\"4\"", "SerializationVersion=\"5\"")
                .Replace("<SymbolKind>Method</SymbolKind>", "<MethodKind>Ordinary</MethodKind>"),
            ReserializePreferences(serializedPreferences));
    }
 
    [Fact]
    public void TestPreserveLatestVersion5()
    {
        var serializedPreferences = @"
<NamingPreferencesInfo SerializationVersion=""5"">
  <SymbolSpecifications>
    <SymbolSpecification ID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" Name=""Method"">
      <ApplicableSymbolKindList>
        <MethodKind>Ordinary</MethodKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
    <SymbolSpecification ID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" Name=""Property Or Method"">
      <ApplicableSymbolKindList>
        <SymbolKind>Property</SymbolKind>
        <MethodKind>Ordinary</MethodKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
  </SymbolSpecifications>
  <NamingStyles>
    <NamingStyle ID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" Name=""Test Pascal Case Rule"" Prefix="""" Suffix="""" WordSeparator="""" CapitalizationScheme=""PascalCase"" />
  </NamingStyles>
  <NamingRules>
    <SerializableNamingRule SymbolSpecificationID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Info"" />
    <SerializableNamingRule SymbolSpecificationID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Error"" />
  </NamingRules>
</NamingPreferencesInfo>";
 
        AssertTrimmedEqual(
            serializedPreferences,
            ReserializePreferences(serializedPreferences));
    }
 
    [Fact]
    public void TestCannotDowngradeHigherThanLatestVersion5()
    {
        var serializedPreferences = @"
<NamingPreferencesInfo SerializationVersion=""6"">
  <SymbolSpecifications>
    <SymbolSpecification ID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" Name=""Method"">
      <ApplicableSymbolKindList>
        <MethodKind>Ordinary</MethodKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
    <SymbolSpecification ID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" Name=""Property Or Method"">
      <ApplicableSymbolKindList>
        <SymbolKind>Property</SymbolKind>
        <MethodKind>Ordinary</MethodKind>
      </ApplicableSymbolKindList>
      <ApplicableAccessibilityList />
      <RequiredModifierList />
    </SymbolSpecification>
  </SymbolSpecifications>
  <NamingStyles>
    <NamingStyle ID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" Name=""Test Pascal Case Rule"" Prefix="""" Suffix="""" WordSeparator="""" CapitalizationScheme=""PascalCase"" />
  </NamingStyles>
  <NamingRules>
    <SerializableNamingRule SymbolSpecificationID=""390caed4-f0a9-42bb-adbb-b44c4a302a22"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Info"" />
    <SerializableNamingRule SymbolSpecificationID=""da6a2919-5aa6-4ad1-a24d-576776ed3974"" NamingStyleID=""87e7c501-9948-4b53-b1eb-a6cbe918feee"" EnforcementLevel=""Error"" />
  </NamingRules>
</NamingPreferencesInfo>";
 
        AssertTrimmedEqual(
            NamingStylePreferences.DefaultNamingPreferencesString,
            ReserializePreferences(serializedPreferences));
    }
 
    /// <summary>
    /// Having duplicates in enums like this means that calling Enum.ToString() will potentially be unstable.
    /// See https://github.com/dotnet/roslyn/issues/44714 for an example where were previously bitten by this;
    /// we should avoid doing this in the future. If this test fails, update <see cref="SymbolSpecification.ModifierKind"/>
    /// to ensure the existing naming styles continue to serialize as they originally did.
    /// </summary>
    [Theory]
    [InlineData(typeof(SymbolKind))]
    [InlineData(typeof(TypeKind), nameof(TypeKind.Struct), nameof(TypeKind.Structure))]
    [InlineData(typeof(MethodKind), nameof(MethodKind.AnonymousFunction), nameof(MethodKind.LambdaMethod), nameof(MethodKind.SharedConstructor), nameof(MethodKind.StaticConstructor))]
    public void NoDuplicateEntriesInKindEnumerations(Type type, params string[] expectedDuplicates)
    {
        Assert.True(type.IsEnum);
 
        var enumNamesAndValues = type.GetEnumNames().Zip(type.GetEnumValues().Cast<object>(), (name, value) => (name, value));
        var duplicates = enumNamesAndValues.GroupBy(e => e.value)
                                           .Where(group => group.Count() > 1)
                                           .SelectMany(group => group)
                                           .Select(e => e.name)
                                           .OrderBy(name => name);
 
        Assert.Equal(expectedDuplicates, duplicates);
    }
}