Why does this assert throw a format exception when comparing structures?

c#, exception, mstest, string-formatting, unit-testing

Solution

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.

Problem

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?

Original source