Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions Source/aweXpect.Core/Formatting/ValueFormatters.Type.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Text;
using aweXpect.Core.Helpers;

Expand Down Expand Up @@ -103,10 +104,16 @@ public static void Format(
FormatType(value, stringBuilder);
}

#pragma warning disable S3776 // https://rules.sonarsource.com/csharp/RSPEC-3776
private static void FormatType(
Type value,
StringBuilder stringBuilder)
=> FormatType(value, stringBuilder, null);

#pragma warning disable S3776 // https://rules.sonarsource.com/csharp/RSPEC-3776
private static void FormatType(
Type value,
StringBuilder stringBuilder,
Type[]? genericArguments)
{
if (value == typeof(void))
{
Expand All @@ -125,17 +132,31 @@ private static void FormatType(
{
if (value.IsNested && value.DeclaringType is not null)
{
FormatType(value.DeclaringType, stringBuilder);
Type[]? declaringTypeGenericArguments = null;
if (value.IsGenericType)
{
int arity = GetArityOfGenericParameters(value.DeclaringType);
declaringTypeGenericArguments = [..value.GenericTypeArguments.Take(arity)];
genericArguments = [..(genericArguments ?? value.GenericTypeArguments).Skip(arity)];
}

Comment thread
vbreuss marked this conversation as resolved.
Outdated
FormatType(value.DeclaringType, stringBuilder, declaringTypeGenericArguments);
stringBuilder.Append('.');
}

if (value.IsGenericType)
{
Type genericTypeDefinition = value.GetGenericTypeDefinition();
stringBuilder.Append(genericTypeDefinition.Name.SubstringUntilFirst('`'));
if (genericArguments?.Length == 0)
{
return;
}

stringBuilder.Append('<');
bool isFirstArgument = true;
foreach (Type argument in value.GetGenericArguments())
genericArguments ??= value.GetGenericArguments();
foreach (var argument in genericArguments)
Comment thread
vbreuss marked this conversation as resolved.
Outdated
{
if (!isFirstArgument)
{
Expand All @@ -158,6 +179,20 @@ private static void FormatType(
}
}
#pragma warning restore S3776

private static int GetArityOfGenericParameters(Type type)
{
int tickIndex = type.Name.LastIndexOf('`');
if (tickIndex != -1)
{
var arityStr = type.Name[(tickIndex + 1)..];
if (int.TryParse(arityStr, NumberStyles.None, CultureInfo.InvariantCulture, out int arity))
{
return arity;
}
}
return 0;
Comment thread
vbreuss marked this conversation as resolved.
}

private static bool AppendedPrimitiveAlias(Type value, StringBuilder stringBuilder)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,38 @@ public async Task NestedGenericTypes_ShouldIncludeTheDeclaringTypeAndName()
await That(sb.ToString()).IsEqualTo(expectedResult);
}

[Fact]
public async Task NestedGenericTypeInGenericTypes_ShouldIncludeTheDeclaringTypeAndName()
{
Type value = typeof(NestedGenericType<TypeTests>.InnerClass<int, string>);
string expectedResult = "ValueFormatters.TypeTests.NestedGenericType<ValueFormatters.TypeTests>.InnerClass<int, string>";
StringBuilder sb = new();

string result = Formatter.Format(value);
string objectResult = Formatter.Format((object?)value);
Formatter.Format(sb, value);

await That(result).IsEqualTo(expectedResult);
await That(objectResult).IsEqualTo(expectedResult);
await That(sb.ToString()).IsEqualTo(expectedResult);
}

[Fact]
public async Task NestedTypeInGenericTypes_ShouldIncludeTheDeclaringTypeAndName()
{
Type value = typeof(NestedGenericType<TypeTests>.InnerRegularClass);
string expectedResult = "ValueFormatters.TypeTests.NestedGenericType<ValueFormatters.TypeTests>.InnerRegularClass";
StringBuilder sb = new();

string result = Formatter.Format(value);
string objectResult = Formatter.Format((object?)value);
Formatter.Format(sb, value);

await That(result).IsEqualTo(expectedResult);
await That(objectResult).IsEqualTo(expectedResult);
await That(sb.ToString()).IsEqualTo(expectedResult);
}

[Fact]
public async Task NestedTypes_ShouldIncludeTheDeclaringTypeAndName()
{
Expand Down Expand Up @@ -259,7 +291,12 @@ public async Task WhenVoid_ShouldUseSimpleName()
}

// ReSharper disable once UnusedTypeParameter
private class NestedGenericType<T>;
private class NestedGenericType<T>
{
public sealed class InnerClass<T1, T2>;

public sealed class InnerRegularClass;
}

// ReSharper disable once UnusedParameter.Local
private static void DummyMethodToGetSpecialTypes<TParameter>(TParameter value)
Expand Down
Loading