File: Code\BestFriendTest.cs
Web Access
Project: src\test\Microsoft.ML.CodeAnalyzer.Tests\Microsoft.ML.CodeAnalyzer.Tests.csproj (Microsoft.ML.CodeAnalyzer.Tests)
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.ML.CodeAnalyzer.Tests.Helpers;
using Xunit;
using VerifyCS = Microsoft.ML.CodeAnalyzer.Tests.Helpers.CSharpCodeFixVerifier<
Microsoft.ML.InternalCodeAnalyzer.BestFriendAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
namespace Microsoft.ML.InternalCodeAnalyzer.Tests
{
    public sealed class BestFriendTest
    {
        // We do things in this somewhat odd way rather than just referencing the Core assembly directly,
        // because we certainly want the best friend attribute itself to be internal, but the assembly
        // we build dynamically as part of the test cannot be signed, and so cannot itself be a friend
        // of the core assembly (even if we were in a mood to pollute the core assembly with friend
        // declarations to enable this one test). We instead compile the same source, as part of this
        // dummy assembly. The type name will be the same so the same analyzer will work.
        private readonly Lazy<string> _sourceAttribute = TestUtils.LazySource("BestFriendAttribute.cs");
        private readonly Lazy<string> _sourceDeclaration = TestUtils.LazySource("BestFriendDeclaration.cs");
        private readonly Lazy<string> _sourceUser = TestUtils.LazySource("BestFriendUser.cs");
 
        [Fact]
        public async Task BestFriend()
        {
            // The setup to this one is a bit more involved than many of the analyzer tests,
            // because in this case we have to actually set up *two* assemblies, where the
            // first considers the second a friend. But, setting up this dependency structure
            // so that things actually compile to the point where the analyzer can actually do
            // its work is rather involved.
 
            var expected = new DiagnosticResult[] {
                VerifyCS.Diagnostic().WithLocation(10, 31).WithArguments("A"),
                VerifyCS.Diagnostic().WithLocation(11, 31).WithArguments("A"),
                VerifyCS.Diagnostic().WithLocation(11, 33).WithArguments("My"),
                VerifyCS.Diagnostic().WithLocation(14, 33).WithArguments("Awhile"),
                VerifyCS.Diagnostic().WithLocation(15, 33).WithArguments("And"),
                VerifyCS.Diagnostic().WithLocation(18, 13).WithArguments("A"),
                VerifyCS.Diagnostic().WithLocation(18, 25).WithArguments("A"),
                new DiagnosticResult("CS0122", DiagnosticSeverity.Error).WithLocation(23, 21).WithMessage("'D.D(float)' is inaccessible due to its protection level"),
                VerifyCS.Diagnostic().WithLocation(25, 13).WithArguments("IA"),
                VerifyCS.Diagnostic().WithLocation(25, 23).WithArguments("IA"),
                VerifyCS.Diagnostic().WithLocation(32, 38).WithArguments(".ctor"),
                VerifyCS.Diagnostic().WithLocation(38, 38).WithArguments(".ctor"),
            };
 
            VerifyCS.Test test = null;
            test = new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp7_2,
                TestState =
                {
                    Sources = { _sourceUser.Value },
                },
                SolutionTransforms =
                {
                    (solution, projectId) =>
                    {
                        var projectA = solution.AddProject("ProjectA", "ProjectA", LanguageNames.CSharp);
                        projectA = projectA.AddDocument("BestFriendAttribute.cs", _sourceAttribute.Value).Project;
                        projectA = projectA.AddDocument("BestFriendDeclaration.cs", _sourceDeclaration.Value).Project;
                        projectA = projectA.WithParseOptions(((CSharpParseOptions)projectA.ParseOptions).WithLanguageVersion(LanguageVersion.CSharp7_2));
                        projectA = projectA.WithCompilationOptions(projectA.CompilationOptions.WithOutputKind(OutputKind.DynamicallyLinkedLibrary));
                        projectA = projectA.WithMetadataReferences(solution.GetProject(projectId).MetadataReferences);
                        solution = projectA.Solution;
 
                        solution = solution.AddProjectReference(projectId, new ProjectReference(projectA.Id));
                        solution = solution.WithProjectAssemblyName(projectId, "ProjectB");
 
                        return solution;
                    },
                },
            };
 
            // Remove these assemblies, or an additional definition of BestFriendAttribute could exist and the
            // compilation will not be able to locate a single definition for use in the analyzer.
            Assert.True(test.TestState.AdditionalReferences.Remove(AdditionalMetadataReferences.MLNetCoreReference));
            Assert.True(test.TestState.AdditionalReferences.Remove(AdditionalMetadataReferences.MLNetDataReference));
 
            test.TestBehaviors |= TestBehaviors.SkipGeneratedCodeCheck;
            test.ExpectedDiagnostics.AddRange(expected);
            await test.RunAsync();
        }
    }
}