- 
      
- 
        Save haacked/1610603 to your computer and use it in GitHub Desktop. 
| public static class TestHelpers | |
| { | |
| public static void ShouldEqualWithDiff(this string actualValue, string expectedValue) | |
| { | |
| ShouldEqualWithDiff(actualValue, expectedValue, DiffStyle.Full, Console.Out); | |
| } | |
| public static void ShouldEqualWithDiff(this string actualValue, string expectedValue, DiffStyle diffStyle) | |
| { | |
| ShouldEqualWithDiff(actualValue, expectedValue, diffStyle, Console.Out); | |
| } | |
| public static void ShouldEqualWithDiff(this string actualValue, string expectedValue, DiffStyle diffStyle, TextWriter output) | |
| { | |
| if(actualValue == null || expectedValue == null) | |
| { | |
| //Assert.AreEqual(expectedValue, actualValue); | |
| Assert.Equal(expectedValue, actualValue); | |
| return; | |
| } | |
| if (actualValue.Equals(expectedValue, StringComparison.Ordinal)) return; | |
| output.WriteLine(" Idx Expected Actual"); | |
| output.WriteLine("-------------------------"); | |
| int maxLen = Math.Max(actualValue.Length, expectedValue.Length); | |
| int minLen = Math.Min(actualValue.Length, expectedValue.Length); | |
| for (int i = 0; i < maxLen; i++) | |
| { | |
| if (diffStyle != DiffStyle.Minimal || i >= minLen || actualValue[i] != expectedValue[i]) | |
| { | |
| output.WriteLine("{0} {1,-3} {2,-4} {3,-3} {4,-4} {5,-3}", | |
| i < minLen && actualValue[i] == expectedValue[i] ? " " : "*", // put a mark beside a differing row | |
| i, // the index | |
| i < expectedValue.Length ? ((int)expectedValue[i]).ToString() : "", // character decimal value | |
| i < expectedValue.Length ? expectedValue[i].ToSafeString() : "", // character safe string | |
| i < actualValue.Length ? ((int)actualValue[i]).ToString() : "", // character decimal value | |
| i < actualValue.Length ? actualValue[i].ToSafeString() : "" // character safe string | |
| ); | |
| } | |
| } | |
| output.WriteLine(); | |
| //Assert.AreEqual(expectedValue, actualValue); | |
| Assert.Equal(expectedValue, actualValue); | |
| } | |
| private static string ToSafeString(this char c) | |
| { | |
| if (Char.IsControl(c) || Char.IsWhiteSpace(c)) | |
| { | |
| switch (c) | |
| { | |
| case '\r': | |
| return @"\r"; | |
| case '\n': | |
| return @"\n"; | |
| case '\t': | |
| return @"\t"; | |
| case '\a': | |
| return @"\a"; | |
| case '\v': | |
| return @"\v"; | |
| case '\f': | |
| return @"\f"; | |
| default: | |
| return String.Format("\\u{0:X};", (int)c); | |
| } | |
| } | |
| return c.ToString(CultureInfo.InvariantCulture); | |
| } | |
| } | |
| public enum DiffStyle | |
| { | |
| Full, | |
| Minimal | |
| } | 
@jarshwah Thanks! Are you sure that makes a difference? There are many cases where the C# compiler can optimize calls like this. For example, since it knows that actualValue and expectedValue don't change, it can evaluate the length and max once. I don't know if it does it in this particular case, but would be interesting to check the IL and measure it to see if it really does make a difference. :)
I forked and made some modifications to your snippet, here it is: https://gist.github.com/1615334
- Extended the list of safe strings according to: http://sinairv.wordpress.com/2010/08/08/code-snippet-representing-strings-with-all-their-characters-visible/
- Moved all tabular formatting to the main method using String.Format
- added support for minimal diff representation
- checked for null input strings
- and a little more
PS. how can I send a pull request for a gist?
@sinairv thanks! I'll take a look at it. Unfortunately, gistts don't support pull requests.
@haacked & @sinairv, for readability, I would suggest removing the call to string.Format & using the overload output.WriteLine(string format, params object[] args)
output.WriteLine("{0} {1,-3} {2,-4} {3,-3}  {4,-4} {5,-3}",
    i < minLen && actual[i] == expected[i] ? " " : "*", // put a mark beside a differing row
    i, // the index
    i < expected.Length ? ((int)expected[i]).ToString() : "", // character decimal value
    i < expected.Length ? expected[i].ToSafeString() : "", // character safe string
    i < actual.Length ? ((int)actual[i]).ToString() : "", // character decimal value
    i < actual.Length ? actual[i].ToSafeString() : "" // character safe string
);@dotnetzebra good suggestion. I made the change.
Thx man.
This helper class help me A LOT with some tricky tests.
I like this. Helped me out a lot.
Maybe consider creating a NuGet package just for this source file. You can create NuGet packages for source pretty easily. I am doing just that now with common files I used to drag around.
http://www.rhyous.com/2016/03/03/nuget-for-source-using-add-as-link-1
Not knowing C#, I learned with your example the meaning of the prefix @ before a string literal in C# = no escaped char sequences.