File: Code\ContractsCheckTest.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.ContractsCheckAnalyzer,
Microsoft.ML.InternalCodeAnalyzer.ContractsCheckNameofFixProvider>;
 
namespace Microsoft.ML.InternalCodeAnalyzer.Tests
{
    public sealed class ContractsCheckTest
    {
        private readonly Lazy<string> _source = TestUtils.LazySource("ContractsCheckResource.cs");
        private readonly Lazy<string> _sourceContracts = TestUtils.LazySource("Contracts.cs");
        private readonly Lazy<string> _sourceFriend = TestUtils.LazySource("BestFriendAttribute.cs");
 
        [Fact]
        public async Task ContractsCheck()
        {
            const int basis = 11;
            var expected = new DiagnosticResult[] {
                new DiagnosticResult("CS0051", DiagnosticSeverity.Error).WithLocation(15, 16).WithMessage("Inconsistent accessibility: parameter type 'IHostEnvironment' is less accessible than method 'TypeName.TypeName(IHostEnvironment, float, int)'"),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(basis + 8, 46).WithArguments("CheckParam", "paramName", "\"p\""),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(basis + 9, 46).WithArguments("CheckParam", "paramName", "nameof(p) + nameof(p)"),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(basis + 11, 28).WithArguments("CheckValue", "paramName", "\"p\""),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(basis + 13, 39).WithArguments("CheckUserArg", "name", "\"foo\""),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.ExceptionDiagnostic.Rule).WithLocation(basis + 15, 13).WithArguments("Except"),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.ExceptionDiagnostic.Rule).WithLocation(basis + 16, 13).WithArguments("ExceptParam"),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(basis + 22, 39).WithArguments("ExceptParam", "paramName", "\"env\""),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.SimpleMessageDiagnostic.Rule).WithLocation(basis + 24, 29).WithArguments("Check", "$\"Hello {foo} is cool\""),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.SimpleMessageDiagnostic.Rule).WithLocation(basis + 28, 29).WithArguments("Check", "string.Format(\"Hello {0} is cool\", foo)"),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.SimpleMessageDiagnostic.Rule).WithLocation(basis + 32, 35).WithArguments("Check", "\"Less fine: \" + env.GetType().Name"),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(basis + 34, 17).WithArguments("CheckUserArg", "name", "\"p\""),
                VerifyCS.Diagnostic(ContractsCheckAnalyzer.DecodeMessageWithLoadContextDiagnostic.Rule).WithLocation(basis + 39, 41).WithArguments("CheckDecode", "\"This message is suspicious\""),
                new DiagnosticResult("CS0122", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 752, 24, 752, 35).WithMessage("'ICancelable' is inaccessible due to its protection level"),
                new DiagnosticResult("CS0122", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 752, 67, 752, 77).WithMessage("'ICancelable.IsCanceled' is inaccessible due to its protection level"),
            };
 
            var test = new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp7_2,
                TestState =
                {
                    Sources =
                    {
                        _source.Value,
                        _sourceContracts.Value,
                        _sourceFriend.Value,
                    },
                }
            };
 
            test.ExpectedDiagnostics.AddRange(expected);
            await test.RunAsync();
        }
 
        [Fact]
        public async Task ContractsCheckDecoy()
        {
            // Run a test with a "decoy" Contacts that has the same signature on the method,
            // except the namespace is distinct so it is a different type. We should not find
            // diagnostics on a class like this!
            const string decoySource = @"
using System;
namespace TestNamespace
{
    public static class Contracts
 
    {
        public static Exception ExceptParam(string paramName, string msg) => null;
    }
 
    public sealed class TypeName
    {
        public TypeName()
            => Contracts.ExceptParam(""myAwesomeParameter"", ""What a great thing"");
    }
}";
            await VerifyCS.VerifyAnalyzerAsync(decoySource);
        }
 
        private readonly Lazy<string> _sourcePreFix = TestUtils.LazySource("ContractsCheckBeforeFix.cs");
        private readonly Lazy<string> _sourcePostFix = TestUtils.LazySource("ContractsCheckAfterFix.cs");
 
        private readonly Lazy<string> _sourceArgAttr = TestUtils.LazySource("ArgumentAttribute.cs");
        private readonly Lazy<string> _sourceArgType = TestUtils.LazySource("ArgumentType.cs");
        private readonly Lazy<string> _sourceBestAttr = TestUtils.LazySource("BestFriendAttribute.cs");
        private readonly Lazy<string> _sourceDefArgAttr = TestUtils.LazySource("DefaultArgumentAttribute.cs");
 
        [Fact]
        public async Task ContractsCheckFix()
        {
            var test = new VerifyCS.Test
            {
                LanguageVersion = LanguageVersion.CSharp7_2,
                TestState =
                {
                    Sources =
                    {
                        _sourcePreFix.Value,
                        _sourceContracts.Value,
                        _sourceArgAttr.Value,
                        _sourceArgType.Value,
                        _sourceBestAttr.Value,
                        _sourceDefArgAttr.Value,
                    },
                    ExpectedDiagnostics =
                    {
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.ExceptionDiagnostic.Rule).WithLocation(9, 43).WithArguments("ExceptParam"),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(9, 65).WithArguments("ExceptParam", "paramName", "\"yuck\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(13, 39).WithArguments("CheckValue", "paramName", "\"str\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(14, 66).WithArguments("CheckUserArg", "name", "\"Foo\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(15, 57).WithArguments("CheckUserArg", "name", "\"Bar\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(16, 57).WithArguments("CheckUserArg", "name", "\"A\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(17, 52).WithArguments("ExceptParam", "paramName", "\"Bar\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(20, 17).WithArguments("CheckParam", "paramName", "\"isFive\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(21, 49).WithArguments("CheckValue", "paramName", "\"Y\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(22, 52).WithArguments("ExceptParam", "paramName", "\"tom\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(23, 39).WithArguments("CheckValue", "paramName", "\"noMatch\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(24, 53).WithArguments("CheckUserArg", "name", "\"chumble\""),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(25, 53).WithArguments("CheckUserArg", "name", "\"sp\""),
                        new DiagnosticResult("CS0122", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 752, 24, 752, 35).WithMessage("'ICancelable' is inaccessible due to its protection level"),
                        new DiagnosticResult("CS0122", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 752, 67, 752, 77).WithMessage("'ICancelable.IsCanceled' is inaccessible due to its protection level"),
                        new DiagnosticResult("CS1503", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 753, 90, 753, 93).WithMessage("Argument 2: cannot convert from 'Microsoft.ML.Runtime.IHostEnvironment' to 'Microsoft.ML.Runtime.IExceptionContext'"),
                    },
                },
                FixedState =
                {
                    Sources =
                    {
                        _sourcePostFix.Value,
                        _sourceContracts.Value,
                        _sourceArgAttr.Value,
                        _sourceArgType.Value,
                        _sourceBestAttr.Value,
                        _sourceDefArgAttr.Value,
                    },
                    ExpectedDiagnostics =
                    {
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.ExceptionDiagnostic.Rule).WithLocation(9, 43).WithArguments("ExceptParam"),
                        VerifyCS.Diagnostic(ContractsCheckAnalyzer.NameofDiagnostic.Rule).WithLocation(23, 39).WithArguments("CheckValue", "paramName", "\"noMatch\""),
                        new DiagnosticResult("CS0122", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 752, 24, 752, 35).WithMessage("'ICancelable' is inaccessible due to its protection level"),
                        new DiagnosticResult("CS0122", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 752, 67, 752, 77).WithMessage("'ICancelable.IsCanceled' is inaccessible due to its protection level"),
                        new DiagnosticResult("CS1503", DiagnosticSeverity.Error).WithSpan("/0/Test1.cs", 753, 90, 753, 93).WithMessage("Argument 2: cannot convert from 'Microsoft.ML.Runtime.IHostEnvironment' to 'Microsoft.ML.Runtime.IExceptionContext'"),
                    },
                },
            };
 
            await test.RunAsync();
        }
    }
}