File: LogParserUtilitiesTests.cs
Web Access
Project: src\test\Generators\Microsoft.Gen.Logging\Unit\Microsoft.Gen.Logging.Unit.Tests.csproj (Microsoft.Gen.Logging.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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.Gen.Logging.Model;
using Microsoft.Gen.Logging.Parsing;
using Microsoft.Gen.Shared;
using Moq;
using Moq.Protected;
using Xunit;
 
namespace Microsoft.Gen.Logging.Test;
 
public class LogParserUtilitiesTests
{
    [Fact]
    public void ShouldDetectNullableOfT()
    {
        var typeSymbolMock = new Mock<ITypeSymbol>();
        typeSymbolMock.SetupGet(x => x.SpecialType).Returns(SpecialType.System_Nullable_T);
        var result = typeSymbolMock.Object.IsNullableOfT();
        Assert.True(result);
 
        var anotherTypeSymbolMock = new Mock<ITypeSymbol>();
        anotherTypeSymbolMock.SetupGet(x => x.SpecialType).Returns(SpecialType.None);
        anotherTypeSymbolMock.SetupGet(x => x.OriginalDefinition).Returns(typeSymbolMock.Object);
        result = typeSymbolMock.Object.IsNullableOfT();
        Assert.True(result);
    }
 
    [Fact]
    public void ShouldNotDetectNullableOfT()
    {
        var typeSymbolMock = new Mock<ITypeSymbol>();
        typeSymbolMock.SetupGet(x => x.SpecialType).Returns(SpecialType.None);
        typeSymbolMock.SetupGet(x => x.OriginalDefinition).Returns(typeSymbolMock.Object);
        var result = typeSymbolMock.Object.IsNullableOfT();
        Assert.False(result);
    }
 
    [Fact]
    public void RecordHasSensitivePublicMembers_ShouldReturnFalse_WhenNoDataClasses()
    {
        var symbolMock = new Mock<ITypeSymbol>();
        symbolMock
            .Setup(x => x.GetMembers())
            .Returns(ImmutableArray<ISymbol>.Empty);
 
        var symbolHolder = new SymbolHolder(
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!);
 
        var diagMock = new Mock<Action<Diagnostic>>();
        var parser = new Parser(null!, diagMock.Object, CancellationToken.None);
        var result = parser.RecordHasSensitivePublicMembers(symbolMock.Object, symbolHolder);
        Assert.False(result);
        symbolMock.VerifyNoOtherCalls();
    }
 
    [Theory]
    [CombinatorialData]
    public void RecordHasSensitivePublicMembers_ShouldNotThrow_WhenNoMembersOnType(bool isNull)
    {
        var symbolMock = new Mock<INamedTypeSymbol>();
        symbolMock
            .Setup(x => x.GetMembers())
            .Returns(isNull
                ? default
                : ImmutableArray<ISymbol>.Empty);
 
        symbolMock
            .Setup(x => x.GetAttributes())
            .Returns(Array.Empty<AttributeData>().ToImmutableArray());
 
        symbolMock
            .SetupGet(x => x.BaseType)
            .Returns((INamedTypeSymbol?)null);
 
        symbolMock
            .SetupGet(x => x.SpecialType)
            .Returns(SpecialType.None);
 
        var symbolHolder = new SymbolHolder(
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            Mock.Of<INamedTypeSymbol>(),
            null!);
 
        var diagMock = new Mock<Action<Diagnostic>>();
        var parser = new Parser(null!, diagMock.Object, CancellationToken.None);
        var result = parser.RecordHasSensitivePublicMembers(symbolMock.Object, symbolHolder);
        Assert.False(result);
        symbolMock.VerifyAll();
        symbolMock.VerifyNoOtherCalls();
    }
 
    [Theory]
    [CombinatorialData]
    public void ProcessLogPropertiesForParameter_ShouldNotThrow_WhenNoMembersOnType(bool isNull)
    {
        var symbolHolder = new SymbolHolder(
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            null!,
            new HashSet<INamedTypeSymbol>(SymbolEqualityComparer.Default),
            null!,
            null!,
            null!,
            null!,
            null!);
 
        const string ParamType = "param type";
 
        var paramTypeMock = new Mock<INamedTypeSymbol>()
            .As<ITypeSymbol>();
 
        paramTypeMock.SetupGet(x => x.Kind).Returns(SymbolKind.NamedType);
        paramTypeMock.SetupGet(x => x.TypeKind).Returns(TypeKind.Class);
        paramTypeMock.SetupGet(x => x.SpecialType).Returns(SpecialType.None);
        paramTypeMock.SetupGet(x => x.OriginalDefinition).Returns(paramTypeMock.Object);
        paramTypeMock.Setup(x => x.ToDisplayString(It.IsAny<SymbolDisplayFormat>()))
            .Returns(ParamType);
 
        paramTypeMock
            .SetupGet(x => x.BaseType)
            .Returns((INamedTypeSymbol?)null);
 
        paramTypeMock
            .Setup(x => x.GetMembers())
            .Returns(isNull
                ? default
                : ImmutableArray<ISymbol>.Empty);
 
        var paramSymbolMock = new Mock<IParameterSymbol>();
        paramSymbolMock.SetupGet(x => x.Type)
            .Returns(paramTypeMock.Object);
 
        var logPropertiesAttribute = new Mock<AttributeData>();
        logPropertiesAttribute
            .Protected()
            .SetupGet<ImmutableArray<KeyValuePair<string, TypedConstant>>>("CommonNamedArguments")
            .Returns(ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty);
 
        logPropertiesAttribute
            .Protected()
            .SetupGet<ImmutableArray<TypedConstant>>("CommonConstructorArguments")
            .Returns(ImmutableArray<TypedConstant>.Empty);
 
        var diagMock = new Mock<Action<Diagnostic>>();
        var parser = new Parser(null!, diagMock.Object, CancellationToken.None);
        bool unused = false;
        var result = parser.ProcessLogPropertiesForParameter(
            logPropertiesAttribute.Object,
            null!,
            new LoggingMethodParameter(),
            paramSymbolMock.Object,
            symbolHolder,
            ref unused);
 
        diagMock.Verify(x => x.Invoke(It.Is<Diagnostic>(d => d.Id == DiagDescriptors.LogPropertiesParameterSkipped.Id)), Times.Once);
        Assert.True(result);
    }
}