Skip to content

Commit a270667

Browse files
authored
Merge pull request #30 from ronaldkroon/Improve_error_messages
Improve error messages
2 parents 6958420 + 2d029d1 commit a270667

File tree

3 files changed

+152
-46
lines changed

3 files changed

+152
-46
lines changed

Src/FluentAssertions.Json/JTokenAssertions.cs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,20 @@ public JTokenAssertions(JToken subject)
5454
public AndConstraint<JTokenAssertions> BeEquivalentTo(string expected, string because = "",
5555
params object[] becauseArgs)
5656
{
57-
JToken parsedExpected = JToken.Parse(expected);
57+
JToken parsedExpected;
58+
try
59+
{
60+
parsedExpected = JToken.Parse(expected);
61+
}
62+
catch (Exception ex)
63+
{
64+
throw new ArgumentException(
65+
$"Unable to parse expected JSON string:{Environment.NewLine}" +
66+
$"{expected}{Environment.NewLine}" +
67+
"Check inner exception for more details.",
68+
nameof(expected), ex);
69+
}
70+
5871
return BeEquivalentTo(parsedExpected, because, becauseArgs);
5972
}
6073

@@ -75,9 +88,12 @@ public AndConstraint<JTokenAssertions> BeEquivalentTo(JToken expected, string be
7588
{
7689
Difference difference = JTokenDifferentiator.FindFirstDifference(Subject, expected);
7790

78-
var message = $"Expected JSON document {Format(Subject, true).Replace("{", "{{").Replace("}", "}}")}" +
79-
$" to be equivalent to {Format(expected, true).Replace("{", "{{").Replace("}", "}}")}" +
80-
$"{{reason}}, but {difference}.";
91+
var message = $"JSON document {difference}.{Environment.NewLine}" +
92+
$"Expected{Environment.NewLine}" +
93+
$"{Format(Subject, true).Replace("{", "{{").Replace("}", "}}")}{Environment.NewLine}" +
94+
$"to be equivalent to{Environment.NewLine}" +
95+
$"{Format(expected, true).Replace("{", "{{").Replace("}", "}}")}{Environment.NewLine}" +
96+
"{reason}.";
8197

8298
Execute.Assertion
8399
.ForCondition(difference == null)
@@ -99,10 +115,24 @@ public AndConstraint<JTokenAssertions> BeEquivalentTo(JToken expected, string be
99115
/// <param name="becauseArgs">
100116
/// Zero or more objects to format using the placeholders in <see paramref="because" />.
101117
/// </param>
102-
public AndConstraint<JTokenAssertions> NotBeEquivalentTo(string unexpected, string because = "", params object[] becauseArgs)
118+
public AndConstraint<JTokenAssertions> NotBeEquivalentTo(string unexpected, string because = "",
119+
params object[] becauseArgs)
103120
{
104-
JToken parsedExpected = JToken.Parse(unexpected);
105-
return NotBeEquivalentTo(parsedExpected, because, becauseArgs);
121+
JToken parsedUnexpected;
122+
try
123+
{
124+
parsedUnexpected = JToken.Parse(unexpected);
125+
}
126+
catch (Exception ex)
127+
{
128+
throw new ArgumentException(
129+
$"Unable to parse unexpected JSON string:{Environment.NewLine}" +
130+
$"{unexpected}{Environment.NewLine}" +
131+
"Check inner exception for more details.",
132+
nameof(unexpected), ex);
133+
}
134+
135+
return NotBeEquivalentTo(parsedUnexpected, because, becauseArgs);
106136
}
107137

108138
/// <summary>
@@ -408,7 +438,21 @@ public AndConstraint<JTokenAssertions> ContainSubtree(JToken subtree, string bec
408438
/// </code>
409439
public AndConstraint<JTokenAssertions> ContainSubtree(string subtree, string because = "", params object[] becauseArgs)
410440
{
411-
return ContainSubtree(JToken.Parse(subtree), because, becauseArgs);
441+
JToken subtreeToken;
442+
try
443+
{
444+
subtreeToken = JToken.Parse(subtree);
445+
}
446+
catch (Exception ex)
447+
{
448+
throw new ArgumentException(
449+
$"Unable to parse expected JSON string:{Environment.NewLine}" +
450+
$"{subtree}{Environment.NewLine}" +
451+
"Check inner exception for more details.",
452+
nameof(subtree), ex);
453+
}
454+
455+
return ContainSubtree(subtreeToken, because, becauseArgs);
412456
}
413457

414458
private bool JTokenContainsSubtree(JToken token, JToken subtree)

Src/FluentAssertions.Json/JTokenDifferentiator.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -185,21 +185,21 @@ public override string ToString()
185185
switch (Kind)
186186
{
187187
case DifferenceKind.ActualIsNull:
188-
return "it is null";
188+
return "is null";
189189
case DifferenceKind.ExpectedIsNull:
190-
return "it is not null";
190+
return "is not null";
191191
case DifferenceKind.OtherType:
192-
return $"the type is different at {Path}";
192+
return $"has a different type at {Path}";
193193
case DifferenceKind.OtherName:
194-
return $"the name is different at {Path}";
194+
return $"has a different name at {Path}";
195195
case DifferenceKind.OtherValue:
196-
return $"the value is different at {Path}";
196+
return $"has a different value at {Path}";
197197
case DifferenceKind.DifferentLength:
198-
return $"the length is different at {Path}";
198+
return $"has a different length at {Path}";
199199
case DifferenceKind.ActualMissesProperty:
200-
return $"it misses property {Path}";
200+
return $"misses property {Path}";
201201
case DifferenceKind.ExpectedMissesProperty:
202-
return $"it has extra property {Path}";
202+
return $"has extra property {Path}";
203203
default:
204204
throw new ArgumentOutOfRangeException();
205205
}

Tests/FluentAssertions.Json.Shared.Specs/JTokenAssertionsSpecs.cs

Lines changed: 92 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using FluentAssertions.Formatting;
4+
using Newtonsoft.Json;
45
using Newtonsoft.Json.Linq;
56
using Xunit;
67
using Xunit.Sdk;
@@ -75,67 +76,67 @@ public void When_objects_differ_BeEquivalentTo_should_fail()
7576
Tuple.Create(
7677
(string)null,
7778
"{ id: 2 }",
78-
"it is null")
79+
"is null")
7980
,
8081
Tuple.Create(
8182
"{ id: 1 }",
8283
(string)null,
83-
"it is not null")
84+
"is not null")
8485
,
8586
Tuple.Create(
8687
"{ items: [] }",
8788
"{ items: 2 }",
88-
"the type is different at $.items")
89+
"has a different type at $.items")
8990
,
9091
Tuple.Create(
9192
"{ items: [ \"fork\", \"knife\" , \"spoon\" ]}",
9293
"{ items: [ \"fork\", \"knife\" ]}",
93-
"the length is different at $.items")
94+
"has a different length at $.items")
9495
,
9596
Tuple.Create(
96-
"{ items: [ \"fork\", \"knife\" , \"spoon\" ]}",
9797
"{ items: [ \"fork\", \"knife\" ]}",
98-
"the length is different at $.items")
98+
"{ items: [ \"fork\", \"knife\" , \"spoon\" ]}",
99+
"has a different length at $.items")
99100
,
100101
Tuple.Create(
101102
"{ items: [ \"fork\", \"knife\" , \"spoon\" ]}",
102103
"{ items: [ \"fork\", \"spoon\", \"knife\" ]}",
103-
"the value is different at $.items[1]")
104+
"has a different value at $.items[1]")
104105
,
105106
Tuple.Create(
106107
"{ tree: { } }",
107108
"{ tree: \"oak\" }",
108-
"the type is different at $.tree")
109+
"has a different type at $.tree")
109110
,
110111
Tuple.Create(
111112
"{ tree: { leaves: 10} }",
112113
"{ tree: { branches: 5, leaves: 10 } }",
113-
"it misses property $.tree.branches")
114+
"misses property $.tree.branches")
114115
,
115116
Tuple.Create(
116117
"{ tree: { branches: 5, leaves: 10 } }",
117118
"{ tree: { leaves: 10} }",
118-
"it has extra property $.tree.branches")
119+
"has extra property $.tree.branches")
119120
,
120121
Tuple.Create(
121122
"{ tree: { leaves: 5 } }",
122123
"{ tree: { leaves: 10} }",
123-
"the value is different at $.tree.leaves")
124+
"has a different value at $.tree.leaves")
124125
,
125126
Tuple.Create(
126127
"{ eyes: \"blue\" }",
127128
"{ eyes: [] }",
128-
"the type is different at $.eyes")
129+
"has a different type at $.eyes")
129130
,
130131
Tuple.Create(
131132
"{ eyes: \"blue\" }",
132133
"{ eyes: 2 }",
133-
"the type is different at $.eyes")
134+
"has a different type at $.eyes")
134135
,
135136
Tuple.Create(
136137
"{ id: 1 }",
137138
"{ id: 2 }",
138-
"the value is different at $.id")
139+
"has a different value at $.id")
139140
};
140141

141142
foreach (var testCase in testCases)
@@ -148,9 +149,11 @@ public void When_objects_differ_BeEquivalentTo_should_fail()
148149
var expected = (expectedJson != null) ? JToken.Parse(expectedJson) : null;
149150

150151
var expectedMessage =
151-
$"Expected JSON document {Format(actual, true)} " +
152-
$"to be equivalent to {Format(expected, true)}, " +
153-
"but " + expectedDifference + ".";
152+
$"JSON document {expectedDifference}." +
153+
$"Expected" +
154+
$"{Format(actual, true)}" +
155+
$"to be equivalent to" +
156+
$"{Format(expected, true)}.";
154157

155158
//-----------------------------------------------------------------------------------------------------------
156159
// Act & Assert
@@ -172,29 +175,32 @@ public void When_properties_differ_BeEquivalentTo_should_fail()
172175
Tuple.Create<JToken, JToken, string>(
173176
new JProperty("eyes", "blue"),
174177
new JArray(),
175-
"the type is different at $")
178+
"has a different type at $")
176179
,
177180
Tuple.Create<JToken, JToken, string>(
178181
new JProperty("eyes", "blue"),
179182
new JProperty("hair", "black"),
180-
"the name is different at $")
183+
"has a different name at $")
181184
,
182185
};
183186

184187
foreach (var testCase in testCases)
185188
{
186-
var a = testCase.Item1;
187-
var b = testCase.Item2;
188-
189+
var actual = testCase.Item1;
190+
var expected = testCase.Item2;
191+
var expectedDifference = testCase.Item3;
192+
189193
var expectedMessage =
190-
$"Expected JSON document {Format(a, true)} " +
191-
$"to be equivalent to {Format(b, true)}, " +
192-
"but " + testCase.Item3 + ".";
194+
$"JSON document {expectedDifference}." +
195+
$"Expected" +
196+
$"{Format(actual, true)}" +
197+
$"to be equivalent to" +
198+
$"{Format(expected, true)}.";
193199

194200
//-----------------------------------------------------------------------------------------------------------
195201
// Act & Assert
196202
//-----------------------------------------------------------------------------------------------------------
197-
a.Should().Invoking(x => x.BeEquivalentTo(b))
203+
actual.Should().Invoking(x => x.BeEquivalentTo(expected))
198204
.Should().Throw<XunitException>()
199205
.WithMessage(expectedMessage);
200206
}
@@ -312,6 +318,42 @@ public void When_checking_whether_a_JToken_is_equivalent_to_the_string_represent
312318
//-----------------------------------------------------------------------------------------------------------
313319
actualJSON.Should().BeEquivalentTo(jsonString);
314320
}
321+
322+
[Fact]
323+
public void When_checking_equivalency_with_an_invalid_expected_string_it_should_provide_a_clear_error_message()
324+
{
325+
//-----------------------------------------------------------------------------------------------------------
326+
// Arrange
327+
//-----------------------------------------------------------------------------------------------------------
328+
var actualJson = JToken.Parse("{ \"id\": null }");
329+
var expectedString = "{ invalid JSON }";
330+
331+
//-----------------------------------------------------------------------------------------------------------
332+
// Act & Assert
333+
//-----------------------------------------------------------------------------------------------------------
334+
actualJson.Should().Invoking(x => x.BeEquivalentTo(expectedString))
335+
.Should().Throw<ArgumentException>()
336+
.WithMessage($"Unable to parse expected JSON string:{expectedString}*")
337+
.WithInnerException<JsonReaderException>();
338+
}
339+
340+
[Fact]
341+
public void When_checking_non_equivalency_with_an_invalid_unexpected_string_it_should_provide_a_clear_error_message()
342+
{
343+
//-----------------------------------------------------------------------------------------------------------
344+
// Arrange
345+
//-----------------------------------------------------------------------------------------------------------
346+
var actualJson = JToken.Parse("{ \"id\": null }");
347+
var unexpectedString = "{ invalid JSON }";
348+
349+
//-----------------------------------------------------------------------------------------------------------
350+
// Act & Assert
351+
//-----------------------------------------------------------------------------------------------------------
352+
actualJson.Should().Invoking(x => x.NotBeEquivalentTo(unexpectedString))
353+
.Should().Throw<ArgumentException>()
354+
.WithMessage($"Unable to parse unexpected JSON string:{unexpectedString}*")
355+
.WithInnerException<JsonReaderException>();
356+
}
315357

316358
[Fact]
317359
public void When_specifying_a_reason_why_object_should_be_equivalent_it_should_use_that_in_the_error_message()
@@ -323,10 +365,12 @@ public void When_specifying_a_reason_why_object_should_be_equivalent_it_should_u
323365
var expected = JToken.Parse("{ child: { expected: 'bar' } }");
324366

325367
var expectedMessage =
326-
$"Expected JSON document {Format(subject, true)} " +
327-
$"to be equivalent to {Format(expected, true)} " +
328-
"because we want to test the failure message, " +
329-
"but it misses property $.child.expected.";
368+
$"JSON document misses property $.child.expected." +
369+
$"Expected" +
370+
$"{Format(subject, true)}" +
371+
$"to be equivalent to" +
372+
$"{Format(expected, true)} " +
373+
"because we want to test the failure message.";
330374

331375
//-----------------------------------------------------------------------------------------------------------
332376
// Act & Assert
@@ -1021,6 +1065,24 @@ public void When_property_types_dont_match_ContainSubtree_should_fail()
10211065
act.Should().Throw<XunitException>();
10221066
}
10231067

1068+
[Fact]
1069+
public void When_checking_subtree_with_an_invalid_expected_string_it_should_provide_a_clear_error_message()
1070+
{
1071+
//-----------------------------------------------------------------------------------------------------------
1072+
// Arrange
1073+
//-----------------------------------------------------------------------------------------------------------
1074+
var actualJson = JToken.Parse("{ \"id\": null }");
1075+
var invalidSubtree = "{ invalid JSON }";
1076+
1077+
//-----------------------------------------------------------------------------------------------------------
1078+
// Act & Assert
1079+
//-----------------------------------------------------------------------------------------------------------
1080+
actualJson.Should().Invoking(x => x.ContainSubtree(invalidSubtree))
1081+
.Should().Throw<ArgumentException>()
1082+
.WithMessage($"Unable to parse expected JSON string:{invalidSubtree}*")
1083+
.WithInnerException<JsonReaderException>();
1084+
}
1085+
10241086
#endregion
10251087

10261088
private static string Format(JToken value, bool useLineBreaks = false)

0 commit comments

Comments
 (0)