I came across a strange behavior and would like some clarification what’s happening here.
I did create a simple immutable struct
public readonly struct MatchingPair : IEquatable<MatchingPair>
{
private MatchingPair(Assets asset1, Assets asset2, bool validate = true)
{
if (validate)
{
InvalidMatchingPairException.ThrowIfEqualOrUnknown(asset1, asset2);
}
if (asset1 < asset2)
{
Asset1 = asset1;
Asset2 = asset2;
}
else
{
Asset1 = asset2;
Asset2 = asset1;
}
}
public static MatchingPair Create(Assets asset1, Assets asset2)
{
return new MatchingPair(asset1, asset2);
}
internal static MatchingPair InternalCreate(Assets asset1, Assets asset2)
{
return new MatchingPair(asset1, asset2, false);
}
public Assets Asset1 { get; }
public Assets Asset2 { get; }
public override string ToString()
{
return $"{Asset1}<->{Asset2}";
}
public bool Equals(MatchingPair other)
{
return Asset1 == other.Asset1 && Asset2 == other.Asset2;
}
public override bool Equals(object? obj)
{
return obj is MatchingPair other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine((int)Asset1, (int)Asset2);
}
public static bool operator ==(MatchingPair left, MatchingPair right)
{
return left.Equals(right);
}
public static bool operator !=(MatchingPair left, MatchingPair right)
{
return !left.Equals(right);
}
}
Assets
is a simple enum nothing fancy.
After that I created an Exception class that will be raised when the Assets are invalid.
Lazy as I am I did not write every testcase instead I used the DynamicDataAttribute
from the MSTestv2 Unit Test Framework.
However this does not work as expected because MatchingPair is losing it’s values.
The minimal Test looks like
[TestMethod]
[DynamicData(nameof(MatchingEngineExceptionConstructor4Data))]
public void MatchingEngineException_Constructor4_Test(string? message, MatchingPair? matchingPair, string expectedMessage)
{
if (matchingPair.HasValue)
{
Assert.AreEqual(Assets.Btc, matchingPair.Value.Asset1);
Assert.AreEqual(Assets.Etc, matchingPair.Value.Asset2); // Fails unexpectedly
}
// ...actual test...
}
To create the test data I did the following
private static IEnumerable<object?[]> MatchingEngineExceptionConstructor4Data
{
get
{
foreach (var message in new[] { null, "Céẞßö." })
{
var expectedMessage = message ?? "Error in the matching engine.";
foreach (MatchingPair? matchingPair in new MatchingPair?[] { null, MatchingPair.Create(Assets.Btc, Assets.Etc) })
{
if (matchingPair != null) { expectedMessage += $" (MatchingPair '{matchingPair}')"; }
yield return [message, matchingPair, expectedMessage];
}
}
}
}
However, in the Unittests both Asset Properties are set to Assets.Btc
which can only mean that they are set to the default value (0). But I would have expected them to hold the actual values I did set. The values are set correctly the expectedMessage I put together is proof of it since it shows the correct values.
Can someone bring some light to what is happening here.
I guess a possible fix is to convert the struct into a class, but I want to avoid that.