File: CallAnalysis\UseThrowsTests.cs
Web Access
Project: src\test\Analyzers\Microsoft.Analyzers.Local.Tests\Microsoft.Analyzers.Local.Tests.csproj (Microsoft.Analyzers.Local.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.LocalAnalyzers.Resource.Test;
using Microsoft.Shared.Diagnostics;
using Xunit;
 
namespace Microsoft.Extensions.LocalAnalyzers.CallAnalysis.Test;
 
public static class UseThrowsTests
{
    private const string ThrowHelpersClass = "Microsoft.Shared.Diagnostics.Throws.";
    private const string ThrowIfNullHelper = "Microsoft.Shared.Diagnostics.Throws.IfNull";
 
    private static readonly Assembly[] _references = new[]
    {
        Assembly.GetAssembly(typeof(Throw))!,
    };
 
    [Theory]
    [MemberData(nameof(SingleWarningData))]
    public static async Task ShouldFindSingleWarning(string original, string exception)
    {
        var d = await RoslynTestUtils.RunAnalyzer(
            new CallAnalyzer(),
            _references,
            new[] { original });
 
        Assert.Single(d);
        original.AssertDiagnostic(0, DiagDescriptors.ThrowsStatement, d[0]);
        Assert.Contains(ThrowHelpersClass + exception, d[0].GetMessage(), StringComparison.Ordinal);
    }
 
    [Theory]
    [MemberData(nameof(NoWarningData))]
    public static async Task ShouldNotProduceWarnings(string original)
    {
        var d = await RoslynTestUtils.RunAnalyzer(
            new CallAnalyzer(),
            _references,
            new[] { original });
 
        Assert.Empty(d);
    }
 
    public static IEnumerable<object[]> SingleWarningData =>
        new List<object[]>
        {
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value)
        {
            /*0+*/throw new ArgumentNullException(nameof(value));/*-0*/
        }
    }
}
",
"ArgumentNullException"
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value)
        {
            /*0+*/throw new ArgumentException(nameof(value));/*-0*/
        }
    }
}
",
"ArgumentException"
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value)
        {
            /*0+*/throw new ArgumentOutOfRangeException(nameof(value));/*-0*/
        }
    }
}
",
"ArgumentOutOfRangeException"
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value, int i)
        {
            if (i > value.Length)
            {
                /*0+*/throw new ArgumentOutOfRangeException(nameof(i));/*-0*/
            }
        }
    }
}
",
"ArgumentOutOfRangeException"
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static string Transform(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                /*0+*/throw new ArgumentException(nameof(key));/*-0*/
            }
 
            return key;
        }
    }
}
",
"ArgumentException"
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static string Transform(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                /*0+*/throw new ArgumentException($""Argument {nameof(key)} was null or empty."", nameof(key));/*-0*/
            }
 
            return key;
        }
    }
}
",
"ArgumentException"
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static string Transform(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                /*0+*/throw new ArgumentNullException(nameof(key), ""message"");/*-0*/
            }
 
            return key;
        }
    }
}
",
"ArgumentNullException"
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value, int i)
        {
            if (i > value.Length)
            {
                /*0+*/throw new ArgumentOutOfRangeException(nameof(i), ""message"");/*-0*/
            }
        }
    }
}
",
"ArgumentOutOfRangeException"
                },
 
        // temporarily disabled in order to roll out analyzer updates without changing
        // the rest of the source base. I'll start enabling the new analyzers and fixing
        // all the warnings in subsequent prs.
#if TURNED_OFF_FOR_ANALYZER_ROLLOUT
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value, int i)
        {
            /*0+*/throw new InvalidOperationException(""message"");/*-0*/
        }
    }
}
",
"InvalidOperationException"
                },
#endif
        };
 
    public static IEnumerable<object[]> NoWarningData =>
       new List<object[]>
       {
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value)
        {
            _ = value ?? throw new ArgumentException(nameof(value));
        }
    }
}
",
                },
                new object[]
                {
@"using System;
 
namespace Example
{
    public static class TestClass
    {
        public static void Test(string value)
        {
            var valNew = value == null ? throw new ArgumentNullException(nameof(value)) : value;
        }
    }
}
",
                },
       };
 
    [Theory]
    [MemberData(nameof(ExpressionSingleWarningData))]
    public static async Task Expression_ShouldFindSingleWarning(string original)
    {
        var d = await RoslynTestUtils.RunAnalyzer(
            new CallAnalyzer(),
            _references,
            new[] { original });
 
        Assert.Single(d);
        original.AssertDiagnostic(0, DiagDescriptors.ThrowsExpression, d[0]);
        Assert.Contains(ThrowIfNullHelper, d[0].GetMessage(), StringComparison.Ordinal);
    }
 
    public static IEnumerable<object[]> ExpressionSingleWarningData =
        new List<object[]>
        {
                new object[]
                {
                    @"
                    using System;
 
                    namespace Example
                    {
                        public class TestClass
                        {
                            public static void Test(string value)
                            {
                                _ = /*0+*/value ?? throw new ArgumentNullException(nameof(value))/*-0*/;
                            }
                        }
                    }",
                },
                new object[]
                {
                    @"
                    using System;
 
                    namespace Example
                    {
                        public class TestClass
                        {
                            public static void Test(string value)
                            {
                                var newVal = /*0+*/value ?? throw new ArgumentNullException(nameof(value))/*-0*/;
                            }
                        }
                    }",
                }
        };
}