File: ParserTests.Diagnostics.cs
Web Access
Project: src\test\Generators\Microsoft.Gen.Metrics\Unit\Microsoft.Gen.Metrics.Unit.Tests.csproj (Microsoft.Gen.Metrics.Unit.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.Text;
using System.Threading.Tasks;
using Xunit;
 
namespace Microsoft.Gen.Metrics.Test;
 
public partial class ParserTests
{
    [Fact]
    public async Task StrongTypeCounter_CyclicReference()
    {
        var d = await RunGenerator(@"
            public class TypeA
            {
                public TypeB testB { get; set; }
            }
 
            public class TypeB
            {
                public TypeA testA { get; set; }
            }
 
            public static partial class MetricClass
            {
                [Counter(typeof(TypeA), Name=""CyclicTest"")]
                public static partial CyclicTest CreateCyclicTestCounter(Meter meter);
            }");
 
        Assert.NotNull(d);
        var diag = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorTagTypeCycleDetected.Id, diag.Id);
        Assert.Contains("Test.TypeB ⇆ Test.TypeA", diag.GetMessage());
    }
 
    [Fact]
    public async Task StrongTypeCounter_CyclicReference_BaseCycle()
    {
        var d = await RunGenerator(@"
            public class TypeA : TypeB
            {
            }
 
            public class TypeB
            {
                public TypeC testC { get; set; }
            }
 
            public class TypeC
            {
                public TypeB testB { get; set; }
            }
 
            public static partial class MetricClass
            {
                [Counter(typeof(TypeA), Name=""CyclicTest"")]
                public static partial CyclicTest CreateCyclicTestCounter(Meter meter);
            }");
 
        Assert.NotNull(d);
        var diag = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorTagTypeCycleDetected.Id, diag.Id);
        Assert.Contains("Test.TypeC ⇆ Test.TypeB", diag.GetMessage());
    }
 
    [Fact]
    public async Task StrongTypeCounter_CyclicReference_InterimCycle()
    {
        var d = await RunGenerator(@"
            internal static partial class Metric
            {
                [Counter(typeof(Interim), Name=""CyclicTest"")]
                public static partial CyclicTest CreateCyclicTestCounter(Meter meter);
            }
 
            class BaseClass
            {
                public Transitive ToTransitive { get; set; }
            }
 
            class Interim : BaseClass
            {
                public Transitive ToTransitive { get; set; }
            }
 
            class Transitive
            {
                public Interim ToInterim { get; set; }
            }");
 
        Assert.NotNull(d);
        var diag = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorTagTypeCycleDetected.Id, diag.Id);
        Assert.Contains("Test.Transitive ⇆ Test.Interim", diag.GetMessage());
    }
 
    [Fact]
    public async Task StructTypeGauge()
    {
        var d = await RunGenerator(@"
            public enum Operations
            {
                Unknown = 0,
                Operation1 = 1,
            }
 
            public struct GaugeStruct
            {
                [Dimension(""Dim1_FromAttribute"")]
                public string? Dim1 { get; set; }
 
                [Dimension(""Operations_FromAttribute"")]
                public Operations Operations { get; set; }
            }
 
            public static partial class MetricClass
            {
                [Gauge(typeof(GaugeStruct), Name=""TotalCountTest"")]
                public static partial TotalCount CreateTotalCountCounter(Meter meter);
            }");
 
        Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorGaugeNotSupported.Id, d[0].Id);
    }
 
    [Fact]
    public async Task StrongTypeGauge()
    {
        // This test should return no errors.
        var d = await RunGenerator(@"
            public class DimensionsTest : ParentDimensions
            {
                [Dimension(""test1_FromAttribute"")]
                public string? test1 { get; set; }
 
                [Dimension(""Operations_FromAttribute"")]
                public Operations operations {get;set;}
 
                public ChildDimensions? ChildDimensions1 { get; set; }
 
                public void Method()
                {
                    System.Console.WriteLine(""I am a method."");
                }
            }
 
            public enum Operations
            {
                Unknown = 0,
                Operation1 = 1,
            }
 
            public class ParentDimensions
            {
                [Dimension(""parentDimension_FromAttribute"")]
                public string? ParentOperationNameWithAttribute { get;set; }
 
                public string? ParentOperationName { get;set; }
 
                public DimensionsStruct ChildDimensionsStruct { get; set; }
            }
 
            public class ChildDimensions
            {
                [Dimension(""test2_FromAttribute"")]
                public string test2_WithAttribute { get; set; }
 
                public string test2 { get; set; }
 
                [Dimension(""test1_FromAttribute_In_Child1"")]
                public string? test1 { get; set; }
            }
 
            public struct DimensionsStruct
            {
                [Dimension(""testStruct_FromAttribute"")]
                public string testStruct_WithAttribute { get; set; }
 
                public string testStruct { get; set; }
            }
 
            public static partial class MetricClass
            {
                [Gauge(typeof(DimensionsTest), Name=""TotalCountTest"")]
                public static partial TotalCount CreateTotalCountCounter(Meter meter);
            }");
 
        Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorGaugeNotSupported.Id, d[0].Id);
    }
 
    [Fact]
    public async Task DuplicateDimensionStringName()
    {
        var d = await RunGenerator(@"
            public class DimensionsTest
            {
                public string dim1 { get; set; }
                public ChildDimensions childDimensions { get; set; }
            }
 
            public class ChildDimensions
            {
                public string dim1 {get;set;}
            }
 
            public static partial class MetricClass
            {
                [Histogram(typeof(DimensionsTest), Name=""TotalCountTest"")]
                public static partial TotalCount CreateTotalCountCounter(Meter meter);
            }");
 
        _ = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorDuplicateTagName.Id, d[0].Id);
    }
 
    [Fact]
    public async Task DuplicateDimensionStringNameInAttribute()
    {
        var d = await RunGenerator(@"
            public class DimensionsTest
            {
                [Dimension(""dim1FromAttribute"")]
                public string dim1 { get; set; }
                public ChildDimensions childDimensions { get; set; }
            }
 
            public class ChildDimensions
            {
                [Dimension(""dim1FromAttribute"")]
                public string dim1 {get;set;}
            }
 
            public static partial class MetricClass
            {
                [Histogram(typeof(DimensionsTest), Name=""TotalCountTest"")]
                public static partial TotalCount CreateTotalCountCounter(Meter meter);
            }");
 
        _ = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorDuplicateTagName.Id, d[0].Id);
    }
 
    [Fact]
    public async Task DuplicateDimensionEnumName()
    {
        var d = await RunGenerator(@"
            public class DimensionsTest
            {
                public Operations operations { get; set; }
                public ChildDimensions childDimensions { get; set; }
            }
 
            public class ChildDimensions
            {
                public Operations operations { get; set; }
            }
 
            public enum Operations
            {
                Unknown = 0,
                Operation1 = 1,
            }
 
            public static partial class MetricClass
            {
                [Histogram(typeof(DimensionsTest), Name=""TotalCountTest"")]
                public static partial TotalCount CreateTotalCountCounter(Meter meter);
            }");
 
        _ = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorDuplicateTagName.Id, d[0].Id);
    }
 
    [Fact]
    public async Task DuplicateDimensionEnumNameInAttribute()
    {
        var d = await RunGenerator(@"
            public class DimensionsTest
            {
                [Dimension(""operations"")]
                public Operations operations { get; set; }
                public ChildDimensions childDimensions { get; set; }
            }
 
            public class ChildDimensions
            {
                public Operations operations { get; set; }
            }
 
            public enum Operations
            {
                Unknown = 0
            }
 
            public static partial class MetricClass
            {
                [Histogram(typeof(DimensionsTest), Name=""TotalCountTest"")]
                public static partial TotalCount CreateTotalCountCounter(Meter meter);
            }");
 
        _ = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorDuplicateTagName.Id, d[0].Id);
    }
 
    [Theory]
    [InlineData("int")]
    [InlineData("int?")]
    [InlineData("System.Int32")]
    [InlineData("System.Int32?")]
    [InlineData("bool")]
    [InlineData("bool?")]
    [InlineData("System.Boolean")]
    [InlineData("System.Boolean?")]
    [InlineData("byte")]
    [InlineData("byte?")]
    [InlineData("char?")]
    [InlineData("double?")]
    [InlineData("decimal?")]
    [InlineData("object")]
    [InlineData("object?")]
    [InlineData("System.Object")]
    [InlineData("System.Object?")]
    [InlineData("int[]")]
    [InlineData("int?[]")]
    [InlineData("int[]?")]
    [InlineData("int?[]?")]
    [InlineData("object[]")]
    [InlineData("object[]?")]
    [InlineData("System.Array")]
    [InlineData("System.DateTime")]
    [InlineData("System.DateTime?")]
    [InlineData("System.IDisposable")]
    [InlineData("System.Action")]
    [InlineData("System.Action<int>")]
    [InlineData("System.Func<double>")]
    [InlineData("System.Nullable<int>")]
    [InlineData("System.Nullable<char>")]
    [InlineData("System.Nullable<System.Int32>")]
    [InlineData("System.Nullable<System.Decimal>")]
    [InlineData("System.Nullable<System.DateTime>")]
    public async Task InvalidDimensionType(string type)
    {
        var d = await RunGenerator(@$"
            public class DimensionsTest
            {{
                public {type} dim1 {{ get; set; }}
            }}
 
            public static partial class MetricClass
            {{
                [Histogram(typeof(DimensionsTest), Name=""TotalCountTest"")]
                public static partial TotalCount CreateTotalCountCounter(Meter meter);
            }}");
 
        _ = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorInvalidTagNameType.Id, d[0].Id);
    }
 
    [Fact]
    public async Task TooManyDimensions()
    {
        StringBuilder sb = new StringBuilder();
 
        int i = 0;
 
        for (; i < 30; i++)
        {
            sb.AppendLine($"public class C{i} : C{i + 1} {{ public string dim{i} {{get;set;}}}}");
        }
 
        sb.AppendLine($"public class C{i} {{ public string dim{i} {{get;set;}}}}");
 
        sb.AppendLine(@"        public static partial class MetricClass
        {
            [Histogram(typeof(C0), Name=""TotalCountTest"")]
            public static partial TotalCount CreateTotalCountCounter(Meter meter);
        }");
 
        var d = await RunGenerator(sb.ToString());
 
        _ = Assert.Single(d);
        Assert.Equal(DiagDescriptors.ErrorTooManyTagNames.Id, d[0].Id);
    }
}