Skip to content

Commit

Permalink
Fixes #86 - Implement Is(Not)AssignableToType (#143)
Browse files Browse the repository at this point in the history
Co-authored-by: Bert Loedeman <[email protected]>
  • Loading branch information
loedeman and Bert Loedeman authored Jun 4, 2020
1 parent 6667ce1 commit 8c2f520
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/projects/EnsureThat/Enforcers/TypeArg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,70 @@ public Type IsNotOfType([ValidatedNotNull]Type param, Type nonExpectedType, [Inv
return param;
}

[NotNull]
[ContractAnnotation("param:null => halt")]
public T IsAssignableToType<T>([ValidatedNotNull]T param, Type expectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null) where T : class
{
Ensure.Any.IsNotNull(param, paramName, optsFn);

IsAssignableToType(param.GetType(), expectedType, paramName, optsFn);

return param;
}

[NotNull]
[ContractAnnotation("param:null => halt")]
public Type IsAssignableToType([ValidatedNotNull]Type param, Type expectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
{
Ensure.Any.IsNotNull(param, paramName, optsFn);
Ensure.Any.IsNotNull(expectedType, nameof(expectedType));

#if NETSTANDARD1_1
// According to: https://devblogs.microsoft.com/dotnet/porting-to-net-core/.
if (!expectedType.GetTypeInfo().IsAssignableFrom(param.GetTypeInfo()))
#else
if (!expectedType.IsAssignableFrom(param))
#endif
throw Ensure.ExceptionFactory.ArgumentException(
string.Format(ExceptionMessages.Types_IsAssignableToType_Failed, expectedType.FullName, param.FullName),
paramName,
optsFn);

return param;
}

[NotNull]
[ContractAnnotation("param:null => halt")]
public T IsNotAssignableToType<T>([ValidatedNotNull]T param, Type nonExpectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null) where T : class
{
Ensure.Any.IsNotNull(param, paramName, optsFn);

IsNotAssignableToType(param.GetType(), nonExpectedType, paramName, optsFn);

return param;
}

[NotNull]
[ContractAnnotation("param:null => halt")]
public Type IsNotAssignableToType([ValidatedNotNull]Type param, Type nonExpectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
{
Ensure.Any.IsNotNull(param, paramName, optsFn);
Ensure.Any.IsNotNull(nonExpectedType, nameof(nonExpectedType));

#if NETSTANDARD1_1
// According to: https://devblogs.microsoft.com/dotnet/porting-to-net-core/.
if (nonExpectedType.GetTypeInfo().IsAssignableFrom(param.GetTypeInfo()))
#else
if (nonExpectedType.IsAssignableFrom(param))
#endif
throw Ensure.ExceptionFactory.ArgumentException(
string.Format(ExceptionMessages.Types_IsNotAssignableToType_Failed, nonExpectedType.FullName),
paramName,
optsFn);

return param;
}

[NotNull]
[ContractAnnotation("param:null => halt")]
public T IsClass<T>([ValidatedNotNull]T param, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
Expand Down
20 changes: 20 additions & 0 deletions src/projects/EnsureThat/EnsureArg.Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,26 @@ public static object IsNotOfType([ValidatedNotNull]object param, Type nonExpecte
public static Type IsNotOfType([ValidatedNotNull]Type param, Type nonExpectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
=> Ensure.Type.IsNotOfType(param, nonExpectedType, paramName, optsFn);

[NotNull]
[ContractAnnotation("param:null => halt")]
public static object IsAssignableToType([ValidatedNotNull] object param, Type expectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
=> Ensure.Type.IsAssignableToType(param, expectedType, paramName, optsFn);

[NotNull]
[ContractAnnotation("param:null => halt")]
public static Type IsAssignableToType([ValidatedNotNull]Type param, Type expectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
=> Ensure.Type.IsAssignableToType(param, expectedType, paramName, optsFn);

[NotNull]
[ContractAnnotation("param:null => halt")]
public static object IsNotAssignableToType([ValidatedNotNull]object param, Type nonExpectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
=> Ensure.Type.IsNotAssignableToType(param, nonExpectedType, paramName, optsFn);

[NotNull]
[ContractAnnotation("param:null => halt")]
public static Type IsNotAssignableToType([ValidatedNotNull]Type param, Type nonExpectedType, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
=> Ensure.Type.IsNotAssignableToType(param, nonExpectedType, paramName, optsFn);

[NotNull]
[ContractAnnotation("param:null => halt")]
public static object IsClass([ValidatedNotNull]object param, [InvokerParameterName] string paramName = null, OptsFn optsFn = null)
Expand Down
6 changes: 6 additions & 0 deletions src/projects/EnsureThat/EnsureThatTypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public static void IsOfType(this in TypeParam param, [NotNull] Type expectedType
public static void IsNotOfType(this in TypeParam param, Type expectedType)
=> Ensure.Type.IsNotOfType(param.Type, expectedType, param.Name, param.OptsFn);

public static void IsAssignableToType(this in TypeParam param, [NotNull] Type expectedType)
=> Ensure.Type.IsAssignableToType(param.Type, expectedType, param.Name, param.OptsFn);

public static void IsNotAssignableToType(this in TypeParam param, Type expectedType)
=> Ensure.Type.IsNotAssignableToType(param.Type, expectedType, param.Name, param.OptsFn);

public static void IsClass<T>(this in Param<T> param)
=> Ensure.Type.IsClass(param.Value, param.Name, param.OptsFn);

Expand Down
2 changes: 2 additions & 0 deletions src/projects/EnsureThat/ExceptionMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public static class ExceptionMessages

public static string Types_IsOfType_Failed { get; } = "The param is not of expected type. Expected: '{0}'. Got: '{1}'.";
public static string Types_IsNotOfType_Failed { get; } = "The param was expected to not be of the type: '{0}'. But it was.";
public static string Types_IsAssignableToType_Failed { get; } = "The param is not assignable to the expected type. Expected: '{0}'. Got: '{1}'.";
public static string Types_IsNotAssignableToType_Failed { get; } = "The param was expected to not be assignable to the type: '{0}'. But it was.";
public static string Types_IsClass_Failed_Null { get; } = "The param was expected to be a class, but was NULL.";
public static string Types_IsClass_Failed { get; } = "The param was expected to be a class, but was type of: '{0}'.";

Expand Down
57 changes: 57 additions & 0 deletions src/tests/UnitTests/EnsureTypeParamTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ private class Bogus { }

private class NonBogus { }

private class AssignableToNonBogus : NonBogus { }

private static readonly Type BogusType = typeof(Bogus);

private static readonly Type NonBogusType = typeof(NonBogus);

private static readonly Type AssignableToNonBogusType = typeof(AssignableToNonBogus);

[Fact]
public void IsOfType_WhenNotTypeOf_ThrowsArgumentException() => AssertIsOfTypeScenario(
NonBogusType, BogusType,
Expand Down Expand Up @@ -52,6 +56,56 @@ public void IsNotOfType_WhenIsNotTheType_It_should_not_throw() => ShouldNotThrow
() => Ensure.ThatType(typeof(Bogus), ParamName).IsNotOfType(NonBogusType),
() => Ensure.ThatTypeFor(new Bogus(), ParamName).IsNotOfType(NonBogusType));

[Fact]
public void IsAssignableToType_WhenNotAssignableToType_ThrowsArgumentException() => AssertIsAssignableToTypeScenario(
NonBogusType, BogusType,
() => Ensure.Type.IsAssignableToType(typeof(Bogus), NonBogusType, ParamName),
() => Ensure.Type.IsAssignableToType(new Bogus(), NonBogusType, ParamName),
() => EnsureArg.IsAssignableToType(typeof(Bogus), NonBogusType, ParamName),
() => EnsureArg.IsAssignableToType(new Bogus(), NonBogusType, ParamName),
() => Ensure.ThatType(typeof(Bogus), ParamName).IsAssignableToType(NonBogusType),
() => Ensure.ThatTypeFor(new Bogus(), ParamName).IsAssignableToType(NonBogusType));

[Fact]
public void IsAssignableToType_WhenAssignableToType_It_should_not_throw() => ShouldNotThrow(
() => Ensure.Type.IsAssignableToType(NonBogusType, NonBogusType, ParamName),
() => Ensure.Type.IsAssignableToType(new NonBogus(), NonBogusType, ParamName),
() => EnsureArg.IsAssignableToType(NonBogusType, NonBogusType, ParamName),
() => EnsureArg.IsAssignableToType(new NonBogus(), NonBogusType, ParamName),
() => Ensure.ThatType(typeof(NonBogus), ParamName).IsAssignableToType(NonBogusType),
() => Ensure.ThatTypeFor(new NonBogus(), ParamName).IsAssignableToType(NonBogusType),
() => Ensure.Type.IsAssignableToType(AssignableToNonBogusType, NonBogusType, ParamName),
() => Ensure.Type.IsAssignableToType(new AssignableToNonBogus(), NonBogusType, ParamName),
() => EnsureArg.IsAssignableToType(AssignableToNonBogusType, NonBogusType, ParamName),
() => EnsureArg.IsAssignableToType(new AssignableToNonBogus(), NonBogusType, ParamName),
() => Ensure.ThatType(typeof(AssignableToNonBogus), ParamName).IsAssignableToType(NonBogusType),
() => Ensure.ThatTypeFor(new AssignableToNonBogus(), ParamName).IsAssignableToType(NonBogusType));

[Fact]
public void IsNotAssignableToType_WhenAssignableToType_ThrowsArgumentException() => ShouldThrow<ArgumentException>(
string.Format(ExceptionMessages.Types_IsNotAssignableToType_Failed, NonBogusType),
() => Ensure.Type.IsNotAssignableToType(typeof(NonBogus), NonBogusType, ParamName),
() => Ensure.Type.IsNotAssignableToType(new NonBogus(), NonBogusType, ParamName),
() => EnsureArg.IsNotAssignableToType(typeof(NonBogus), NonBogusType, ParamName),
() => EnsureArg.IsNotAssignableToType(new NonBogus(), NonBogusType, ParamName),
() => Ensure.ThatType(typeof(NonBogus), ParamName).IsNotAssignableToType(NonBogusType),
() => Ensure.ThatTypeFor(new NonBogus(), ParamName).IsNotAssignableToType(NonBogusType),
() => Ensure.Type.IsNotAssignableToType(typeof(AssignableToNonBogus), NonBogusType, ParamName),
() => Ensure.Type.IsNotAssignableToType(new AssignableToNonBogus(), NonBogusType, ParamName),
() => EnsureArg.IsNotAssignableToType(typeof(AssignableToNonBogus), NonBogusType, ParamName),
() => EnsureArg.IsNotAssignableToType(new AssignableToNonBogus(), NonBogusType, ParamName),
() => Ensure.ThatType(typeof(AssignableToNonBogus), ParamName).IsNotAssignableToType(NonBogusType),
() => Ensure.ThatTypeFor(new AssignableToNonBogus(), ParamName).IsNotAssignableToType(NonBogusType));

[Fact]
public void IsNotAssignableToType_WhenNotAssignableToType_It_should_not_throw() => ShouldNotThrow(
() => Ensure.Type.IsNotAssignableToType(BogusType, NonBogusType, ParamName),
() => Ensure.Type.IsNotAssignableToType(new Bogus(), NonBogusType, ParamName),
() => EnsureArg.IsNotAssignableToType(BogusType, NonBogusType, ParamName),
() => EnsureArg.IsNotAssignableToType(new Bogus(), NonBogusType, ParamName),
() => Ensure.ThatType(typeof(Bogus), ParamName).IsNotAssignableToType(NonBogusType),
() => Ensure.ThatTypeFor(new Bogus(), ParamName).IsNotAssignableToType(NonBogusType));

[Fact]
public void IsInt_WhenNotTypeOf_ThrowsArgumentException() => AssertIsOfTypeScenario(
typeof(int), typeof(decimal),
Expand Down Expand Up @@ -258,6 +312,9 @@ public void IsClass_WhenIsClass_It_should_not_throw()
private static void AssertIsOfTypeScenario(Type expected, Type actual, params Action[] actions)
=> ShouldThrow<ArgumentException>(string.Format(ExceptionMessages.Types_IsOfType_Failed, expected.FullName, actual.FullName), actions);

private static void AssertIsAssignableToTypeScenario(Type expected, Type actual, params Action[] actions)
=> ShouldThrow<ArgumentException>(string.Format(ExceptionMessages.Types_IsAssignableToType_Failed, expected.FullName, actual.FullName), actions);

private static void AssertIsNotClass(Type type, params Action[] actions)
=> ShouldThrow<ArgumentException>(string.Format(ExceptionMessages.Types_IsClass_Failed, type.FullName), actions);

Expand Down

0 comments on commit 8c2f520

Please sign in to comment.