Skip to content

Commit

Permalink
fix: fix TypeCache parsing behavior and related unit tests. (#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
iyaneruz0 authored Dec 11, 2024
1 parent f16eff7 commit e4f18e3
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 29 deletions.
26 changes: 6 additions & 20 deletions src/Silverback.Core/Util/TypesCache.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (c) 2020 Sergio Aquilini
// Copyright (c) 2020 Sergio Aquilini
// This code is licensed under MIT license (see LICENSE file for details)

using System;
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions;

namespace Silverback.Util
{
Expand All @@ -30,29 +31,14 @@ internal static class TypesCache
return type;
}

internal static string CleanAssemblyQualifiedName(string typeAssemblyQualifiedName)
private static string CleanAssemblyQualifiedName(string typeAssemblyQualifiedName)
{
if (string.IsNullOrEmpty(typeAssemblyQualifiedName))
if (string.IsNullOrWhiteSpace(typeAssemblyQualifiedName))
return typeAssemblyQualifiedName;

int endGenericType = typeAssemblyQualifiedName.LastIndexOf(']');
if (endGenericType == -1)
{
string[] split = typeAssemblyQualifiedName.Split(',', 3, StringSplitOptions.RemoveEmptyEntries);
return split.Length >= 2 ? $"{split[0].Trim()}, {split[1].Trim()}" : typeAssemblyQualifiedName;
}

int startGenericType = typeAssemblyQualifiedName.IndexOf('[', StringComparison.InvariantCulture);
if (startGenericType == -1)
return typeAssemblyQualifiedName;

string type = typeAssemblyQualifiedName[..startGenericType].Trim();
if (endGenericType + 1 >= typeAssemblyQualifiedName.Length)
return type;
var cleanAssemblyQualifiedName = Regex.Replace(typeAssemblyQualifiedName, @", (Version=\d+\.\d+\.\d+\.\d+|Culture=\w+|PublicKeyToken=\w+)", string.Empty);

string next = typeAssemblyQualifiedName[(endGenericType + 1)..];
string assemblyName = next.Split(",", 2, StringSplitOptions.RemoveEmptyEntries)[0].Trim();
return $"{type}, {assemblyName}";
return cleanAssemblyQualifiedName;
}

[SuppressMessage("", "CA1031", Justification = "Can catch all, the operation is retried")]
Expand Down
87 changes: 87 additions & 0 deletions tests/Silverback.Core.Tests/Util/TypesCacheTests.TestData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) 2020 Sergio Aquilini
// This code is licensed under MIT license (see LICENSE file for details)

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace Silverback.Tests.Core.Util
{
public partial class TypesCacheTests
{
public static IEnumerable<object[]> AssemblyQualifiedNameType_ReturnType()
{
// Shortened qualified name with no types
yield return new object[]
{
"Silverback.Tests.Core.Util.TypesCacheTests+GenericTypeTest`2, Silverback.Core.Tests",
new AssemblyQualifiedGenericTypeResult(
typeof(GenericTypeTest<,>)),
};

// Shortened qualified name with types [shortened qualified name],[shortened qualified name, assembly]
yield return new object[]
{
"Silverback.Tests.Core.Util.TypesCacheTests+GenericTypeTest`2[[System.Int64],[Silverback.Tests.Core.Util.TypesCacheTests, Silverback.Core.Tests]], Silverback.Core.Tests",
new AssemblyQualifiedGenericTypeResult(
typeof(GenericTypeTest<long, TypesCacheTests>)),
};

// Shortened qualified name with types [full qualified name],[shortened qualified name]
yield return new object[]
{
"Silverback.Tests.Core.Util.TypesCacheTests+GenericTypeTest`2[[System.Int64, System.Private.CoreLib, Version=1.2.3.4, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Silverback.Tests.Core.Util.TypesCacheTests, Silverback.Core.Tests]], Silverback.Core.Tests",
new AssemblyQualifiedGenericTypeResult(
typeof(GenericTypeTest<long, TypesCacheTests>)),
};

// Shortened qualified name with types [full qualified name],[full qualified name]
yield return new object[]
{
"Silverback.Tests.Core.Util.TypesCacheTests+GenericTypeTest`2[[System.Int64, System.Private.CoreLib, Version=1.2.3.4, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Silverback.Tests.Core.Util.TypesCacheTests, Silverback.Core.Tests, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null]], Silverback.Core.Tests",
new AssemblyQualifiedGenericTypeResult(
typeof(GenericTypeTest<long, TypesCacheTests>)),
};

// Shortened qualified name with types [shortened qualified name],[full qualified name]
yield return new object[]
{
"Silverback.Tests.Core.Util.TypesCacheTests+GenericTypeTest`2[[System.Int64, System.Private.CoreLib],[Silverback.Tests.Core.Util.TypesCacheTests, Silverback.Core.Tests, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null]], Silverback.Core.Tests",
new AssemblyQualifiedGenericTypeResult(
typeof(GenericTypeTest<long, TypesCacheTests>)),
};

// Full qualified name with full qualified types.
yield return new object[]
{
"Silverback.Tests.Core.Util.TypesCacheTests+GenericTypeTest`2[[System.Int64, System.Private.CoreLib, Version=1.2.3.4, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[Silverback.Tests.Core.Util.TypesCacheTests, Silverback.Core.Tests, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null]], Silverback.Core.Tests, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null",
new AssemblyQualifiedGenericTypeResult(
typeof(GenericTypeTest<long, TypesCacheTests>)),
};

// Full qualified name - no culture, with type [full qualified name - no version]
yield return new object[]
{
"System.Collections.Generic.List`1[[System.Char, System.Private.CoreLib, Culture=neutral]], System.Private.CoreLib, Version=5.0.0.0, PublicKeyToken=7cec85d7bea7798e",
new AssemblyQualifiedGenericTypeResult(
typeof(List<char>)),
};
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1034:Nested types should not be visible", Justification = "Record belongs to unit test data.")]
public record AssemblyQualifiedGenericTypeResult(Type MatchingType)
{
}

[SuppressMessage("StyleCop.CSharp.DocumentationRules", "CA1812: Avoid uninstantiated internal classes", Justification = "Class loaded via tests.")]
private class GenericTypeTest<T1, T2>
where T2 : class
{
[SuppressMessage("Major Code Smell", "S1144:Unused private types or members should be removed", Justification = "Generic type assignment.")]
public T1? P1 { get; }

[SuppressMessage("Major Code Smell", "S1144:Unused private types or members should be removed", Justification = "Generic type assignment.")]
public T2? P2 { get; set; }
}
}
}
16 changes: 7 additions & 9 deletions tests/Silverback.Core.Tests/Util/TypesCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Silverback.Tests.Core.Util
{
public class TypesCacheTests
public partial class TypesCacheTests
{
[Fact]
public void GetType_ExistingType_TypeReturned()
Expand Down Expand Up @@ -64,16 +64,14 @@ public void GetType_IncompleteTypeName_TypeReturned()
}

[Theory]
[InlineData("Silverback.Tests.Core.TestTypes.Messages.TestEventOne2", "Silverback.Tests.Core.TestTypes.Messages.TestEventOne2")]
[InlineData("Silverback.Tests.Core.TestTypes.Messages.TestEventOne2, Silverback.Core.Tests", "Silverback.Tests.Core.TestTypes.Messages.TestEventOne2, Silverback.Core.Tests")]
[InlineData("Silverback.Tests.Core.TestTypes.Messages.TestEventOne2, Silverback.Core.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Silverback.Tests.Core.TestTypes.Messages.TestEventOne2, Silverback.Core.Tests")]
[InlineData("Silverback.Tests.Core.Util.TypesCacheTests+MyMessage`2[[System.Int32, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int64, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], Silverback.Core.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "Silverback.Tests.Core.Util.TypesCacheTests+MyMessage`2, Silverback.Core.Tests")]
[InlineData("Silverback.Tests.Core.Util.TypesCacheTests+MyMessage`2[[System.Int32, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int64, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]", "Silverback.Tests.Core.Util.TypesCacheTests+MyMessage`2")]
public void GetType_GenericType_TypeReturned(string typeAssemblyQualifiedName, string expected)
[MemberData(nameof(AssemblyQualifiedNameType_ReturnType))]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1825:Avoid zero-length array allocations", Justification = "Unit test member data.")]
public void GetType_GenericType_TypeReturned(string typeAssemblyQualifiedName, AssemblyQualifiedGenericTypeResult expectedResult)
{
string cleanedName = TypesCache.CleanAssemblyQualifiedName(typeAssemblyQualifiedName);
var type = TypesCache.GetType(typeAssemblyQualifiedName);

cleanedName.Should().Be(expected);
type.Should().NotBeNull();
expectedResult.MatchingType.IsAssignableFrom(type).Should().BeTrue();
}
}
}

0 comments on commit e4f18e3

Please sign in to comment.