Skip to content

Commit

Permalink
Better error messages for ambiguous exception. Extend GetTypeFromInte…
Browse files Browse the repository at this point in the history
…rface to take a type list instead of assuming all types from the assembly of the given type.
  • Loading branch information
cwinland committed May 28, 2024
1 parent b5d9d8a commit 8a8adaa
Showing 1 changed file with 50 additions and 3 deletions.
53 changes: 50 additions & 3 deletions FastMoq.Core/Extensions/TestClassExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Reflection;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Text;
using Xunit.Abstractions;

namespace FastMoq.Extensions
Expand Down Expand Up @@ -267,9 +268,10 @@ public static string GetMemberName<T, TValue>(this T _, Expression<Func<T, TValu
/// </summary>
/// <param name="mocker">The mocker.</param>
/// <param name="tType">Type of the t.</param>
/// <param name="typeList">The type list.</param>
/// <returns>Type.</returns>
/// <exception cref="System.Runtime.AmbiguousImplementationException"></exception>
public static Type GetTypeFromInterface(this Mocker mocker, Type tType)
public static Type GetTypeFromInterface(this Mocker mocker, Type tType, List<Type>? typeList = null)
{
if (!tType.IsInterface)
{
Expand All @@ -283,8 +285,12 @@ public static Type GetTypeFromInterface(this Mocker mocker, Type tType)
return mappedType.InstanceType;
}

var types = tType.Assembly.GetTypes().ToList();
var types = typeList ?? tType.Assembly.GetTypes().ToList();
return GetTypeFromInterfaceList(mocker, tType, types);
}

private static Type GetTypeFromInterfaceList(Mocker mocker, Type tType, List<Type> types)
{
// Get interfaces that contain T.
var interfaces = types.Where(type => type.IsInterface && type.GetInterfaces().Contains(tType)).ToList();

Expand All @@ -298,13 +304,54 @@ public static Type GetTypeFromInterface(this Mocker mocker, Type tType)
return possibleTypes.Count switch
{
> 1 => possibleTypes.Count(x => x.IsPublic) > 1
? throw new AmbiguousImplementationException()
? throw mocker.GetAmbiguousImplementationException(tType, possibleTypes)
: possibleTypes.Find(x => x.IsPublic) ?? possibleTypes.FirstOrDefault() ?? tType,
1 => possibleTypes[0],
_ => tType,
};
}

/// <summary>
/// Throws the ambiguous implementation exception.
/// </summary>
/// <param name="mocker">The mocker.</param>
/// <param name="message">The message.</param>
/// <returns>System.Runtime.AmbiguousImplementationException.</returns>
public static AmbiguousImplementationException GetAmbiguousImplementationException(this Mocker mocker, string message)
{
mocker.exceptionLog.Add(message);
return new AmbiguousImplementationException(message);
}

/// <summary>
/// Gets the ambiguous implementation exception.
/// </summary>
/// <param name="mocker">The mocker.</param>
/// <param name="tType">Type of the t.</param>
/// <param name="types">The types.</param>
/// <returns>System.Runtime.AmbiguousImplementationException.</returns>
public static AmbiguousImplementationException GetAmbiguousImplementationException(this Mocker mocker, Type tType, ICollection<Type>? types = null)
{
var builder = new StringBuilder($"Multiple components of type '{tType}' was found.");

if (types?.Count > 1)
{
builder.AppendLine("\r\nTypes found:");

builder.AppendJoin(", ", types.Select(x => x.FullName));
}
return mocker.GetAmbiguousImplementationException(builder.ToString());
}

/// <summary>
/// Throws the ambiguous constructor implementation exception.
/// </summary>
/// <param name="mocker">The mocker.</param>
/// <param name="tType">Type of the t.</param>
/// <returns>System.Runtime.AmbiguousImplementationException.</returns>
public static AmbiguousImplementationException GetAmbiguousConstructorImplementationException(this Mocker mocker, Type tType) =>
mocker.GetAmbiguousImplementationException($"Multiple parameterized constructors exist of type '{tType}'. Cannot decide which to use.");

/// <summary>
/// Sets the field value.
/// </summary>
Expand Down

0 comments on commit 8a8adaa

Please sign in to comment.