Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jnyrup committed Jan 23, 2021
1 parent ad75fe4 commit 9cfc7d6
Show file tree
Hide file tree
Showing 14 changed files with 718 additions and 211 deletions.
7 changes: 0 additions & 7 deletions Src/FluentAssertions/AssertionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,6 @@ public static ExecutionTime ExecutionTime(this Func<Task> action)
return new ExecutionTime(action);
}

/// <summary>
/// Returns an <see cref="EnumAssertions"/> object that can be used to assert the
/// current <see cref="Enum"/>.
/// </summary>
public static EnumAssertions Should(this Enum @enum)
=> new EnumAssertions(@enum);

/// <summary>
/// Returns an <see cref="ExecutionTimeAssertions"/> object that can be used to assert the
/// current <see cref="FluentAssertions.Specialized.ExecutionTime"/>.
Expand Down
8 changes: 3 additions & 5 deletions Src/FluentAssertions/Common/ObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public static bool IsSameOrEqualTo(this object actual, object expected)
Type actualType = actual.GetType();

return actualType != expectedType
&& (actual.IsNumericType() || actualType.IsEnum)
&& (expected.IsNumericType() || expectedType.IsEnum)
&& actual.IsNumericType()
&& expected.IsNumericType()
&& CanConvert(actual, expected, actualType, expectedType)
&& CanConvert(expected, actual, expectedType, actualType);
}
Expand All @@ -55,9 +55,7 @@ private static bool CanConvert(object source, object target, Type sourceType, Ty

private static object ConvertTo(this object source, Type targetType)
{
return targetType.IsEnum
? Enum.ToObject(targetType, source)
: Convert.ChangeType(source, targetType, CultureInfo.InvariantCulture);
return Convert.ChangeType(source, targetType, CultureInfo.InvariantCulture);
}

private static bool IsNumericType(this object obj)
Expand Down
36 changes: 36 additions & 0 deletions Src/FluentAssertions/EnumAssertionsExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using FluentAssertions.Primitives;

namespace FluentAssertions
{
/// <summary>
/// Contains an extension method for custom assertions in unit tests related to Enum objects.
/// </summary>
[DebuggerNonUserCode]
public static class EnumAssertionsExtensions
{
/// <summary>
/// Returns an <see cref="EnumAssertions{TEnum, TAssertions}"/> object that can be used to assert the
/// current <typeparamref name="TEnum"/>.
/// </summary>
[Pure]
public static EnumAssertions<TEnum> Should<TEnum>(this TEnum @enum)
where TEnum : struct, Enum
{
return new EnumAssertions<TEnum>(@enum);
}

/// <summary>
/// Returns an <see cref="EnumAssertions{TEnum, TAssertions}"/> object that can be used to assert the
/// current <typeparamref name="TEnum"/>.
/// </summary>
[Pure]
public static NullableEnumAssertions<TEnum> Should<TEnum>(this TEnum? @enum)
where TEnum : struct, Enum
{
return new NullableEnumAssertions<TEnum>(@enum);
}
}
}
5 changes: 2 additions & 3 deletions Src/FluentAssertions/Equivalency/EnumEqualityStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ public class EnumEqualityStep : IEquivalencyStep
/// </summary>
public bool CanHandle(IEquivalencyValidationContext context, IEquivalencyAssertionOptions config)
{
Type subjectType = config.GetExpectationType(context.RuntimeType, context.CompileTimeType);
Type expectationType = config.GetExpectationType(context.RuntimeType, context.CompileTimeType);

return (subjectType?.IsEnum == true) ||
(context.Expectation?.GetType().IsEnum == true);
return expectationType.IsEnum;
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions Src/FluentAssertions/Equivalency/EnumerableEquivalencyStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ public class EnumerableEquivalencyStep : IEquivalencyStep
/// </summary>
public bool CanHandle(IEquivalencyValidationContext context, IEquivalencyAssertionOptions config)
{
Type subjectType = config.GetExpectationType(context.RuntimeType, context.CompileTimeType);
Type expectationType = config.GetExpectationType(context.RuntimeType, context.CompileTimeType);

return IsCollection(subjectType);
return IsCollection(expectationType);
}

/// <summary>
Expand Down
283 changes: 255 additions & 28 deletions Src/FluentAssertions/Primitives/EnumAssertions.cs

Large diffs are not rendered by default.

102 changes: 102 additions & 0 deletions Src/FluentAssertions/Primitives/NullableEnumAssertions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using FluentAssertions.Execution;

namespace FluentAssertions.Primitives
{
/// <summary>
/// Contains a number of methods to assert that a nullable <typeparamref name="TEnum"/> is in the expected state.
/// </summary>
public class NullableEnumAssertions<TEnum> : NullableEnumAssertions<TEnum, NullableEnumAssertions<TEnum>>
where TEnum : struct, Enum
{
public NullableEnumAssertions(TEnum? subject)
: base(subject)
{
}
}

/// <summary>
/// Contains a number of methods to assert that a nullable <typeparamref name="TEnum"/> is in the expected state.
/// </summary>
public class NullableEnumAssertions<TEnum, TAssertions> : EnumAssertions<TEnum, TAssertions>
where TEnum : struct, Enum
where TAssertions : NullableEnumAssertions<TEnum, TAssertions>
{
public NullableEnumAssertions(TEnum? subject)
: base(subject)
{
}

public new TEnum? Subject => SubjectInternal;

/// <summary>
/// Asserts that a nullable <typeparamref name="TEnum"/> value is not <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndWhichConstraint<TAssertions, TEnum> HaveValue(string because = "", params object[] becauseArgs)
{
Execute.Assertion
.ForCondition(SubjectInternal.HasValue)
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:nullable date and time} to have a value{reason}, but found {0}.", SubjectInternal);

return new AndWhichConstraint<TAssertions, TEnum>((TAssertions)this, SubjectInternal.GetValueOrDefault());
}

/// <summary>
/// Asserts that a nullable <typeparamref name="TEnum"/> is not <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndWhichConstraint<TAssertions, TEnum> NotBeNull(string because = "", params object[] becauseArgs)
{
return HaveValue(because, becauseArgs);
}

/// <summary>
/// Asserts that a nullable <typeparamref name="TEnum"/> value is <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> NotHaveValue(string because = "", params object[] becauseArgs)
{
Execute.Assertion
.ForCondition(!SubjectInternal.HasValue)
.BecauseOf(because, becauseArgs)
.FailWith("Did not expect {context:nullable date and time} to have a value{reason}, but found {0}.", SubjectInternal);

return new AndConstraint<TAssertions>((TAssertions)this);
}

/// <summary>
/// Asserts that a nullable <typeparamref name="TEnum"/> value is <c>null</c>.
/// </summary>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])"/> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> BeNull(string because = "", params object[] becauseArgs)
{
return NotHaveValue(because, becauseArgs);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ namespace FluentAssertions
public static FluentAssertions.Primitives.NullableDateTimeAssertions Should(this System.DateTime? actualValue) { }
public static FluentAssertions.Primitives.DateTimeOffsetAssertions Should(this System.DateTimeOffset actualValue) { }
public static FluentAssertions.Primitives.NullableDateTimeOffsetAssertions Should(this System.DateTimeOffset? actualValue) { }
public static FluentAssertions.Primitives.EnumAssertions Should(this System.Enum @enum) { }
public static FluentAssertions.Specialized.NonGenericAsyncFunctionAssertions Should(this System.Func<System.Threading.Tasks.Task> action) { }
public static FluentAssertions.Primitives.GuidAssertions Should(this System.Guid actualValue) { }
public static FluentAssertions.Primitives.NullableGuidAssertions Should(this System.Guid? actualValue) { }
Expand Down Expand Up @@ -144,6 +143,13 @@ namespace FluentAssertions
public static FluentAssertions.Data.DataTableAssertions<TDataTable> Should<TDataTable>(this TDataTable actualValue)
where TDataTable : System.Data.DataTable { }
}
public static class EnumAssertionsExtensions
{
public static FluentAssertions.Primitives.EnumAssertions<TEnum> Should<TEnum>(this TEnum @enum)
where TEnum : struct, System.Enum { }
public static FluentAssertions.Primitives.NullableEnumAssertions<TEnum> Should<TEnum>(this TEnum? @enum)
where TEnum : struct, System.Enum { }
}
public class EquivalencyStepCollection : System.Collections.Generic.IEnumerable<FluentAssertions.Equivalency.IEquivalencyStep>, System.Collections.IEnumerable
{
public EquivalencyStepCollection() { }
Expand Down Expand Up @@ -1738,20 +1744,33 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> After(System.DateTime target, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> Before(System.DateTime target, string because = "", params object[] becauseArgs) { }
}
public class EnumAssertions : FluentAssertions.Primitives.EnumAssertions<System.Enum, FluentAssertions.Primitives.EnumAssertions>
public class EnumAssertions<TEnum> : FluentAssertions.Primitives.EnumAssertions<TEnum, FluentAssertions.Primitives.EnumAssertions<TEnum>>
where TEnum : struct, System.Enum
{
public EnumAssertions(System.Enum subject) { }
public EnumAssertions(TEnum subject) { }
}
public class EnumAssertions<TEnum, TAssertions> : FluentAssertions.Primitives.ObjectAssertions<TEnum, TAssertions>
where TEnum : System.Enum
public class EnumAssertions<TEnum, TAssertions>
where TEnum : struct, System.Enum
where TAssertions : FluentAssertions.Primitives.EnumAssertions<TEnum, TAssertions>
{
public EnumAssertions(TEnum subject) { }
protected override string Identifier { get; }
public FluentAssertions.AndConstraint<TAssertions> HaveFlag<T>(T expectedFlag, string because = "", params object[] becauseArgs)
where T : struct, TEnum { }
public FluentAssertions.AndConstraint<TAssertions> NotHaveFlag<T>(T unexpectedFlag, string because = "", params object[] becauseArgs)
where T : struct, TEnum { }
public TEnum Subject { get; }
public FluentAssertions.AndConstraint<TAssertions> Be(TEnum expected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> Be(TEnum? expected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> HaveFlag(TEnum expectedFlag, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> HaveSameNameAs<T>(T expected, string because = "", params object[] becauseArgs)
where T : struct, System.Enum { }
public FluentAssertions.AndConstraint<TAssertions> HaveSameValueAs<T>(T expected, string because = "", params object[] becauseArgs)
where T : struct, System.Enum { }
public FluentAssertions.AndConstraint<TAssertions> HaveValue(decimal expected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(TEnum unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(TEnum? unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotHaveFlag(TEnum unexpectedFlag, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotHaveSameNameAs<T>(T unexpected, string because = "", params object[] becauseArgs)
where T : struct, System.Enum { }
public FluentAssertions.AndConstraint<TAssertions> NotHaveSameValueAs<T>(T unexpected, string because = "", params object[] becauseArgs)
where T : struct, System.Enum { }
public FluentAssertions.AndConstraint<TAssertions> NotHaveValue(decimal unexpected, string because = "", params object[] becauseArgs) { }
}
public class GuidAssertions : FluentAssertions.Primitives.GuidAssertions<FluentAssertions.Primitives.GuidAssertions>
{
Expand Down Expand Up @@ -1810,6 +1829,22 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> NotBeNull(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotHaveValue(string because = "", params object[] becauseArgs) { }
}
public class NullableEnumAssertions<TEnum> : FluentAssertions.Primitives.NullableEnumAssertions<TEnum, FluentAssertions.Primitives.NullableEnumAssertions<TEnum>>
where TEnum : struct, System.Enum
{
public NullableEnumAssertions(TEnum? subject) { }
}
public class NullableEnumAssertions<TEnum, TAssertions> : FluentAssertions.Primitives.EnumAssertions<TEnum, TAssertions>
where TEnum : struct, System.Enum
where TAssertions : FluentAssertions.Primitives.NullableEnumAssertions<TEnum, TAssertions>
{
public NullableEnumAssertions(TEnum? subject) { }
public TEnum? Subject { get; }
public FluentAssertions.AndConstraint<TAssertions> BeNull(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndWhichConstraint<TAssertions, TEnum> HaveValue(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndWhichConstraint<TAssertions, TEnum> NotBeNull(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotHaveValue(string because = "", params object[] becauseArgs) { }
}
public class NullableGuidAssertions : FluentAssertions.Primitives.NullableGuidAssertions<FluentAssertions.Primitives.NullableGuidAssertions>
{
public NullableGuidAssertions(System.Guid? value) { }
Expand Down

0 comments on commit 9cfc7d6

Please sign in to comment.