I'm trying to write a custom Equivalency Step for Fluent Assertions to compare Enum
values on the subject side back to a string on the exception side.
The problem I seem to be facing is that the subject type passed in to the IEquivalencyStep
has been converted to a string before my EquivalencyStep
is even invoked.
Is there some magic happening within fluent assertions that's trying to convert the enum straight in to a string?
An example of the code is below:
public class SubjectClass
{
public EnumType Prop1 { get; set; }
}
public enum EnumType
{
A,
B,
C
}
public class ExpectionClass
{
public string Prop1 { get; set; }
}
[TestFixture]
public class ComparingEnumWithTests
{
[Test]
public void Test()
{
var expection = new ExpectionClass() {Prop1 = "bbb"};
var subject = new SubjectClass() {Prop1 = EnumType.B};
subject.ShouldBeEquivalentTo(expection, opt => opt.Using(new ComparingEnumWith<EnumType>(new Dictionary<string, EnumType>()
{
{"aaa", EnumType.A },
{"bbb", EnumType.B },
{"ccc", EnumType.C }
})));
}
}
public class ComparingEnumWith<TEnum> : IEquivalencyStep
where TEnum : struct
{
private readonly IReadOnlyDictionary<string, TEnum> _dictionary;
private readonly Type _enumType;
public ComparingEnumWith(IReadOnlyDictionary<string, TEnum> dictionary)
{
_enumType = typeof(TEnum);
if (!_enumType.IsEnum)
{
throw new ArgumentException("TEnum must be an enum");
}
_dictionary = dictionary;
}
public bool CanHandle(IEquivalencyValidationContext context, IEquivalencyAssertionOptions config)
{
var subjectType = config.GetSubjectType(context);
return subjectType != null && subjectType == _enumType && context.Expectation is string;
}
public bool Handle(IEquivalencyValidationContext context, IEquivalencyValidator parent, IEquivalencyAssertionOptions config)
{
var expected = _dictionary[(string)context.Expectation];
return ((TEnum)context.Subject).Equals(expected);
}
}
UPDATE:
From the problem above I've adapted the code to the below incase anyone else is having the same problem.
public class SubjectClass
{
public EnumType Prop1 { get; set; }
}
public enum EnumType
{
A,
B,
C
}
public class ExpectionClass
{
public string Prop1 { get; set; }
}
[TestFixture]
public class ComparingEnumWithTests
{
[Test]
public void Test()
{
var expection = new ExpectionClass() {Prop1 = "bbb"};
var subject = new SubjectClass() {Prop1 = EnumType.B};
AssertionOptions.EquivalencySteps.Insert<ComparingEnumWith<EnumTypeDataMapProvider, EnumType>>();
subject.ShouldBeEquivalentTo(expection);
}
}
public interface IEnumDataMapProvider<TEnum>
{
IReadOnlyDictionary<string, TEnum> Map { get; }
}
public class EnumTypeDataMapProvider : IEnumDataMapProvider<EnumType>
{
public IReadOnlyDictionary<string, EnumType> Map => new Dictionary<string, EnumType>()
{
{"aaa", EnumType.A},
{"bbb", EnumType.B},
{"ccc", EnumType.C}
};
}
public class ComparingEnumWith<TMapProvider, TEnum> : IEquivalencyStep
where TMapProvider : IEnumDataMapProvider<TEnum>
where TEnum : struct
{
private readonly IReadOnlyDictionary<string, TEnum> _dictionary;
private readonly Type _enumType;
public ComparingEnumWith()
{
_enumType = typeof(TEnum);
if (!_enumType.IsEnum)
{
throw new ArgumentException("TEnum must be an enum");
}
var provider = Activator.CreateInstance<TMapProvider>();
_dictionary = provider.Map;
}
public bool CanHandle(IEquivalencyValidationContext context, IEquivalencyAssertionOptions config)
{
var subjectType = config.GetSubjectType(context);
return subjectType != null && subjectType == _enumType && context.Expectation is string;
}
public bool Handle(IEquivalencyValidationContext context, IEquivalencyValidator parent, IEquivalencyAssertionOptions config)
{
var expected = _dictionary[(string)context.Expectation];
return ((TEnum)context.Subject).Equals(expected);
}
}
That's a bug. You're registering something we call a user equivalency step. But these run after the built-in TryConversionEquivalencyStep
and ReferenceEqualityEquivalencyStep
. If you can please file this as a bug, we can look at it. As a workaround, consider inserting your custom step before all the built-in steps using AssertionOptions.EquivalencySteps.Insert<ComparingEnumWith<T>>();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With