I'm trying to assert the equality of two System.Drawing.Size
structures, and I'm getting a format exception instead of the expected assert failure.
[TestMethod] public void AssertStructs() { var struct1 = new Size(0, 0); var struct2 = new Size(1, 1); //This throws a format exception, "System.FormatException: Input string was not in a correct format." Assert.AreEqual(struct1, struct2, "Failed. Expected {0}, actually it is {1}", struct1, struct2); //This assert fails properly, "Failed. Expected {Width=0, Height=0}, actually it is {Width=1, Height=1}". Assert.AreEqual(struct1, struct2, "Failed. Expected " + struct1 + ", actually it is " + struct2); }
Is this intended behavior? Am I doing something wrong here?
A FormatException exception can be thrown for one of the following reasons: In a call to a method that converts a string to some other data type, the string doesn't conform to the required pattern. This typically occurs when calling some methods of the Convert class and the Parse and ParseExact methods of some types.
The NumberFormatException occurs when an attempt is made to convert a string with improper format into a numeric value. That means, when it is not possible to convert a string in any numeric type (float, int, etc), this exception is thrown.
In java, String format() method returns a formatted string using the given locale, specified format string, and arguments. We can concatenate the strings using this method and at the same time, we can format the output concatenated string. Syntax: There is two types of string format() method.
I've got it. And yes, it's a bug.
The problem is that there are two levels of string.Format
going on here.
The first level of formatting is something like:
string template = string.Format("Expected: {0}; Actual: {1}; Message: {2}", expected, actual, message);
Then we use string.Format
with the parameters you've supplied:
string finalMessage = string.Format(template, parameters);
(Obviously there's cultures being provided, and some sort of sanitization... but not enough.)
That looks fine - unless the expected and actual values themselves end up with braces in, after being converted to a string - which they do for Size
. For example, your first size ends up being converted to:
{Width=0, Height=0}
So the second level of formatting is something like:
string.Format("Expected: {Width=0, Height=0}; Actual: {Width=1, Height=1 }; " + "Message = Failed expected {0} actually is {1}", struct1, struct2);
... and that's what's failing. Ouch.
Indeed, we can prove this really easily by fooling the formatting to use our parameters for the expected and actual parts:
var x = "{0}"; var y = "{1}"; Assert.AreEqual<object>(x, y, "What a surprise!", "foo", "bar");
The result is:
Assert.AreEqual failed. Expected:<foo>. Actual:<bar>. What a surprise!
Clearly broken, as we weren't expecting foo
nor was the actual value bar
!
Basically this is like a SQL injection attack, but in the rather less scary context of string.Format
.
As a workaround, you can use string.Format
as StriplingWarrior suggests. That avoids the second level of formatting being performed on the result of formatting with the actual/expected values.
I think you've found a bug.
This works (throws an assert exception):
var a = 1; var b = 2; Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);
And this works (outputs the message):
var a = new{c=1}; var b = new{c=2}; Console.WriteLine(string.Format("Not equal {0} {1}", a, b));
But this doesn't work (throws a FormatException
):
var a = new{c=1}; var b = new{c=2}; Assert.AreEqual(a, b, "Not equal {0} {1}", a, b);
I can't think of any reason this would be expected behavior. I'd submit a bug report. In the meantime, here's a workaround:
var a = new{c=1}; var b = new{c=2}; Assert.AreEqual(a, b, string.Format("Not equal {0} {1}", a, b));
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