|
// 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 Xunit;
namespace Microsoft.Extensions.Internal;
public class TypeNameHelperTest
{
[Theory]
// Predefined Types
[InlineData(typeof(int), "int")]
[InlineData(typeof(List<int>), "System.Collections.Generic.List<int>")]
[InlineData(typeof(Dictionary<int, string>), "System.Collections.Generic.Dictionary<int, string>")]
[InlineData(typeof(Dictionary<int, List<string>>), "System.Collections.Generic.Dictionary<int, System.Collections.Generic.List<string>>")]
[InlineData(typeof(List<List<string>>), "System.Collections.Generic.List<System.Collections.Generic.List<string>>")]
// Classes inside NonGeneric class
[InlineData(typeof(A),
"Microsoft.Extensions.Internal.TypeNameHelperTest+A")]
[InlineData(typeof(B<int>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+B<int>")]
[InlineData(typeof(C<int, string>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+C<int, string>")]
[InlineData(typeof(B<B<string>>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+B<Microsoft.Extensions.Internal.TypeNameHelperTest+B<string>>")]
[InlineData(typeof(C<int, B<string>>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+C<int, Microsoft.Extensions.Internal.TypeNameHelperTest+B<string>>")]
// Classes inside Generic class
[InlineData(typeof(Outer<int>.D),
"Microsoft.Extensions.Internal.TypeNameHelperTest+Outer<int>+D")]
[InlineData(typeof(Outer<int>.E<int>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+Outer<int>+E<int>")]
[InlineData(typeof(Outer<int>.F<int, string>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+Outer<int>+F<int, string>")]
[InlineData(typeof(Level1<int>.Level2<bool>.Level3<int>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+Level1<int>+Level2<bool>+Level3<int>")]
[InlineData(typeof(Outer<int>.E<Outer<int>.E<string>>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+Outer<int>+E<Microsoft.Extensions.Internal.TypeNameHelperTest+Outer<int>+E<string>>")]
[InlineData(typeof(Outer<int>.F<int, Outer<int>.E<string>>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+Outer<int>+F<int, Microsoft.Extensions.Internal.TypeNameHelperTest+Outer<int>+E<string>>")]
[InlineData(typeof(OuterGeneric<int>.InnerNonGeneric.InnerGeneric<int, string>.InnerGenericLeafNode<bool>),
"Microsoft.Extensions.Internal.TypeNameHelperTest+OuterGeneric<int>+InnerNonGeneric+InnerGeneric<int, string>+InnerGenericLeafNode<bool>")]
public void Can_pretty_print_CLR_full_name(Type type, string expected)
{
Assert.Equal(expected, TypeNameHelper.GetTypeDisplayName(type));
}
[Fact]
public void DoesNotPrintNamespace_ForGenericTypes_IfNullOrEmpty()
{
// Arrange
var type = typeof(ClassInGlobalNamespace<int>);
// Act & Assert
Assert.Equal("ClassInGlobalNamespace<int>", TypeNameHelper.GetTypeDisplayName(type));
}
[Theory]
// Predefined Types
[InlineData(typeof(int), "int")]
[InlineData(typeof(List<int>), "List<int>")]
[InlineData(typeof(Dictionary<int, string>), "Dictionary<int, string>")]
[InlineData(typeof(Dictionary<int, List<string>>), "Dictionary<int, List<string>>")]
[InlineData(typeof(List<List<string>>), "List<List<string>>")]
// Classes inside NonGeneric class
[InlineData(typeof(A), "A")]
[InlineData(typeof(B<int>), "B<int>")]
[InlineData(typeof(C<int, string>), "C<int, string>")]
[InlineData(typeof(C<int, B<string>>), "C<int, B<string>>")]
[InlineData(typeof(B<B<string>>), "B<B<string>>")]
// Classes inside Generic class
[InlineData(typeof(Outer<int>.D), "D")]
[InlineData(typeof(Outer<int>.E<int>), "E<int>")]
[InlineData(typeof(Outer<int>.F<int, string>), "F<int, string>")]
[InlineData(typeof(Outer<int>.F<int, Outer<int>.E<string>>), "F<int, E<string>>")]
[InlineData(typeof(Outer<int>.E<Outer<int>.E<string>>), "E<E<string>>")]
[InlineData(typeof(OuterGeneric<int>.InnerNonGeneric.InnerGeneric<int, string>.InnerGenericLeafNode<bool>), "InnerGenericLeafNode<bool>")]
public void Can_pretty_print_CLR_name(Type type, string expected)
{
Assert.Equal(expected, TypeNameHelper.GetTypeDisplayName(type, false));
}
[Theory]
[InlineData(typeof(void), "void")]
[InlineData(typeof(bool), "bool")]
[InlineData(typeof(byte), "byte")]
[InlineData(typeof(char), "char")]
[InlineData(typeof(decimal), "decimal")]
[InlineData(typeof(double), "double")]
[InlineData(typeof(float), "float")]
[InlineData(typeof(int), "int")]
[InlineData(typeof(long), "long")]
[InlineData(typeof(object), "object")]
[InlineData(typeof(sbyte), "sbyte")]
[InlineData(typeof(short), "short")]
[InlineData(typeof(string), "string")]
[InlineData(typeof(uint), "uint")]
[InlineData(typeof(ulong), "ulong")]
[InlineData(typeof(ushort), "ushort")]
public void Returns_common_name_for_built_in_types(Type type, string expected)
{
Assert.Equal(expected, TypeNameHelper.GetTypeDisplayName(type));
}
[Theory]
[InlineData(typeof(int[]), true, "int[]")]
[InlineData(typeof(string[][]), true, "string[][]")]
[InlineData(typeof(int[,]), true, "int[,]")]
[InlineData(typeof(bool[,,,]), true, "bool[,,,]")]
[InlineData(typeof(A[,][,,]), true, "Microsoft.Extensions.Internal.TypeNameHelperTest+A[,][,,]")]
[InlineData(typeof(List<int[,][,,]>), true, "System.Collections.Generic.List<int[,][,,]>")]
[InlineData(typeof(List<int[,,][,]>[,][,,]), false, "List<int[,,][,]>[,][,,]")]
public void Can_pretty_print_array_name(Type type, bool fullName, string expected)
{
Assert.Equal(expected, TypeNameHelper.GetTypeDisplayName(type, fullName));
}
public static TheoryData<Type, bool, string> GetOpenGenericsTestData()
{
var openDictionaryType = typeof(Dictionary<,>);
var genArgsDictionary = openDictionaryType.GetGenericArguments();
genArgsDictionary[0] = typeof(B<>);
var closedDictionaryType = openDictionaryType.MakeGenericType(genArgsDictionary);
var openLevelType = typeof(Level1<>.Level2<>.Level3<>);
var genArgsLevel = openLevelType.GetGenericArguments();
genArgsLevel[1] = typeof(string);
var closedLevelType = openLevelType.MakeGenericType(genArgsLevel);
var openInnerType = typeof(OuterGeneric<>.InnerNonGeneric.InnerGeneric<,>.InnerGenericLeafNode<>);
var genArgsInnerType = openInnerType.GetGenericArguments();
genArgsInnerType[3] = typeof(bool);
var closedInnerType = openInnerType.MakeGenericType(genArgsInnerType);
return new TheoryData<Type, bool, string>
{
{ typeof(List<>), false, "List<>" },
{ typeof(Dictionary<,>), false , "Dictionary<,>" },
{ typeof(List<>), true , "System.Collections.Generic.List<>" },
{ typeof(Dictionary<,>), true , "System.Collections.Generic.Dictionary<,>" },
{ typeof(Level1<>.Level2<>.Level3<>), true, "Microsoft.Extensions.Internal.TypeNameHelperTest+Level1<>+Level2<>+Level3<>" },
{
typeof(PartiallyClosedGeneric<>).BaseType,
true,
"Microsoft.Extensions.Internal.TypeNameHelperTest+C<, int>"
},
{
typeof(OuterGeneric<>.InnerNonGeneric.InnerGeneric<,>.InnerGenericLeafNode<>),
true,
"Microsoft.Extensions.Internal.TypeNameHelperTest+OuterGeneric<>+InnerNonGeneric+InnerGeneric<,>+InnerGenericLeafNode<>"
},
{
closedDictionaryType,
true,
"System.Collections.Generic.Dictionary<Microsoft.Extensions.Internal.TypeNameHelperTest+B<>,>"
},
{
closedLevelType,
true,
"Microsoft.Extensions.Internal.TypeNameHelperTest+Level1<>+Level2<string>+Level3<>"
},
{
closedInnerType,
true,
"Microsoft.Extensions.Internal.TypeNameHelperTest+OuterGeneric<>+InnerNonGeneric+InnerGeneric<,>+InnerGenericLeafNode<bool>"
}
};
}
[Theory]
[MemberData(nameof(GetOpenGenericsTestData))]
public void Can_pretty_print_open_generics(Type type, bool fullName, string expected)
{
Assert.Equal(expected, TypeNameHelper.GetTypeDisplayName(type, fullName));
}
public static TheoryData<Type, string> GetTypeDisplayName_IncludesGenericParameterNamesWhenOptionIsSetData =>
new TheoryData<Type, string>
{
{ typeof(B<>),"Microsoft.Extensions.Internal.TypeNameHelperTest+B<T>" },
{ typeof(C<,>),"Microsoft.Extensions.Internal.TypeNameHelperTest+C<T1, T2>" },
{ typeof(PartiallyClosedGeneric<>).BaseType,"Microsoft.Extensions.Internal.TypeNameHelperTest+C<T, int>" },
{ typeof(Level1<>.Level2<>),"Microsoft.Extensions.Internal.TypeNameHelperTest+Level1<T1>+Level2<T2>" },
};
[Theory]
[MemberData(nameof(GetTypeDisplayName_IncludesGenericParameterNamesWhenOptionIsSetData))]
public void GetTypeDisplayName_IncludesGenericParameterNamesWhenOptionIsSet(Type type, string expected)
{
// Arrange & Act
var actual = TypeNameHelper.GetTypeDisplayName(type, fullName: true, includeGenericParameterNames: true);
// Assert
Assert.Equal(expected, actual);
}
public static TheoryData<Type, string> GetTypeDisplayName_WithoutFullName_IncludesGenericParameterNamesWhenOptionIsSetData =>
new TheoryData<Type, string>
{
{ typeof(B<>),"B<T>" },
{ typeof(C<,>),"C<T1, T2>" },
{ typeof(PartiallyClosedGeneric<>).BaseType,"C<T, int>" },
{ typeof(Level1<>.Level2<>),"Level2<T2>" },
};
[Theory]
[MemberData(nameof(GetTypeDisplayName_WithoutFullName_IncludesGenericParameterNamesWhenOptionIsSetData))]
public void GetTypeDisplayName_WithoutFullName_IncludesGenericParameterNamesWhenOptionIsSet(Type type, string expected)
{
// Arrange & Act
var actual = TypeNameHelper.GetTypeDisplayName(type, fullName: false, includeGenericParameterNames: true);
// Assert
Assert.Equal(expected, actual);
}
public static TheoryData<Type, string> FullTypeNameData
{
get
{
return new TheoryData<Type, string>
{
// Predefined Types
{ typeof(int), "int" },
{ typeof(List<int>), "System.Collections.Generic.List" },
{ typeof(Dictionary<int, string>), "System.Collections.Generic.Dictionary" },
{ typeof(Dictionary<int, List<string>>), "System.Collections.Generic.Dictionary" },
{ typeof(List<List<string>>), "System.Collections.Generic.List" },
// Classes inside NonGeneric class
{ typeof(A), "Microsoft.Extensions.Internal.TypeNameHelperTest.A" },
{ typeof(B<int>), "Microsoft.Extensions.Internal.TypeNameHelperTest.B" },
{ typeof(C<int, string>), "Microsoft.Extensions.Internal.TypeNameHelperTest.C" },
{ typeof(C<int, B<string>>), "Microsoft.Extensions.Internal.TypeNameHelperTest.C" },
{ typeof(B<B<string>>), "Microsoft.Extensions.Internal.TypeNameHelperTest.B" },
// Classes inside Generic class
{ typeof(Outer<int>.D), "Microsoft.Extensions.Internal.TypeNameHelperTest.Outer.D" },
{ typeof(Outer<int>.E<int>), "Microsoft.Extensions.Internal.TypeNameHelperTest.Outer.E" },
{ typeof(Outer<int>.F<int, string>), "Microsoft.Extensions.Internal.TypeNameHelperTest.Outer.F" },
{ typeof(Outer<int>.F<int, Outer<int>.E<string>>),"Microsoft.Extensions.Internal.TypeNameHelperTest.Outer.F" },
{ typeof(Outer<int>.E<Outer<int>.E<string>>), "Microsoft.Extensions.Internal.TypeNameHelperTest.Outer.E" }
};
}
}
[Theory]
[MemberData(nameof(FullTypeNameData))]
public void Can_PrettyPrint_FullTypeName_WithoutGenericParametersAndNestedTypeDelimiter(Type type, string expectedTypeName)
{
// Arrange & Act
var displayName = TypeNameHelper.GetTypeDisplayName(type, fullName: true, includeGenericParameters: false, nestedTypeDelimiter: '.');
// Assert
Assert.Equal(expectedTypeName, displayName);
}
private class A { }
private class B<T> { }
private class C<T1, T2> { }
private class PartiallyClosedGeneric<T> : C<T, int> { }
private class Outer<T>
{
public class D { }
public class E<T1> { }
public class F<T1, T2> { }
}
private class OuterGeneric<T1>
{
public class InnerNonGeneric
{
public class InnerGeneric<T2, T3>
{
public class InnerGenericLeafNode<T4> { }
public class InnerLeafNode { }
}
}
}
private class Level1<T1>
{
public class Level2<T2>
{
public class Level3<T3>
{
}
}
}
}
|