Skip to content

Commit

Permalink
Merge pull request #63 from jnyrup/JTokenDifferentiator
Browse files Browse the repository at this point in the history
Make `JTokenDifferentiator` an instance class
  • Loading branch information
jnyrup committed Feb 26, 2022
2 parents 3f466e3 + e9e4310 commit 600b0af
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 38 deletions.
3 changes: 2 additions & 1 deletion Src/FluentAssertions.Json/JTokenAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ public JTokenAssertions(JToken subject)
string because = "",
params object[] becauseArgs)
{
Difference difference = JTokenDifferentiator.FindFirstDifference(Subject, expected, ignoreExtraProperties, config);
var differentiator = new JTokenDifferentiator(ignoreExtraProperties, config);
Difference difference = differentiator.FindFirstDifference(Subject, expected);

var expectation = ignoreExtraProperties ? "was expected to contain" : "was expected to be equivalent to";

Expand Down
77 changes: 40 additions & 37 deletions Src/FluentAssertions.Json/JTokenDifferentiator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@

namespace FluentAssertions.Json
{
// REFACTOR: Change to non-static and make parameters fields
internal static class JTokenDifferentiator
internal class JTokenDifferentiator
{
public static Difference FindFirstDifference(JToken actual, JToken expected, bool ignoreExtraProperties, Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private readonly bool ignoreExtraProperties;

private readonly Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config;

public JTokenDifferentiator(bool ignoreExtraProperties,
Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
{
this.ignoreExtraProperties = ignoreExtraProperties;
this.config = config;
}

public Difference FindFirstDifference(JToken actual, JToken expected)
{
var path = new JPath();

Expand All @@ -28,24 +38,22 @@ public static Difference FindFirstDifference(JToken actual, JToken expected, boo
return new Difference(DifferenceKind.ExpectedIsNull, path);
}

return FindFirstDifference(actual, expected, path, ignoreExtraProperties, config);
return FindFirstDifference(actual, expected, path);
}

private static Difference FindFirstDifference(JToken actual, JToken expected, JPath path, bool ignoreExtraProperties, Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference FindFirstDifference(JToken actual, JToken expected, JPath path)
{
return actual switch
{
JArray actualArray => FindJArrayDifference(actualArray, expected, path, ignoreExtraProperties, config),
JObject actualObject => FindJObjectDifference(actualObject, expected, path, ignoreExtraProperties, config),
JProperty actualProperty => FindJPropertyDifference(actualProperty, expected, path, ignoreExtraProperties, config),
JValue actualValue => FindValueDifference(actualValue, expected, path, config),
JArray actualArray => FindJArrayDifference(actualArray, expected, path),
JObject actualObject => FindJObjectDifference(actualObject, expected, path),
JProperty actualProperty => FindJPropertyDifference(actualProperty, expected, path),
JValue actualValue => FindValueDifference(actualValue, expected, path),
_ => throw new NotSupportedException(),
};
}

private static Difference FindJArrayDifference(JArray actualArray, JToken expected, JPath path,
bool ignoreExtraProperties,
Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference FindJArrayDifference(JArray actualArray, JToken expected, JPath path)
{
if (expected is not JArray expectedArray)
{
Expand All @@ -54,15 +62,15 @@ private static Difference FindFirstDifference(JToken actual, JToken expected, JP

if (ignoreExtraProperties)
{
return CompareExpectedItems(actualArray, expectedArray, path, config);
return CompareExpectedItems(actualArray, expectedArray, path);
}
else
{
return CompareItems(actualArray, expectedArray, path, config);
return CompareItems(actualArray, expectedArray, path);
}
}

private static Difference CompareExpectedItems(JArray actual, JArray expected, JPath path, Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference CompareExpectedItems(JArray actual, JArray expected, JPath path)
{
JToken[] actualChildren = actual.Children().ToArray();
JToken[] expectedChildren = expected.Children().ToArray();
Expand All @@ -74,7 +82,7 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J
bool match = false;
for (int actualIndex = matchingIndex; actualIndex < actualChildren.Length; actualIndex++)
{
var difference = FindFirstDifference(actualChildren[actualIndex], expectedChild, true, config);
var difference = FindFirstDifference(actualChildren[actualIndex], expectedChild);

if (difference == null)
{
Expand All @@ -88,7 +96,7 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J
{
if (matchingIndex >= actualChildren.Length)
{
if (actualChildren.Any(actualChild => FindFirstDifference(actualChild, expectedChild, true, config) == null))
if (actualChildren.Any(actualChild => FindFirstDifference(actualChild, expectedChild) == null))
{
return new Difference(DifferenceKind.WrongOrder, path.AddIndex(expectedIndex));
}
Expand All @@ -97,15 +105,14 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J
}

return FindFirstDifference(actualChildren[matchingIndex], expectedChild,
path.AddIndex(expectedIndex), true, config);
path.AddIndex(expectedIndex));
}
}

return null;
}

private static Difference CompareItems(JArray actual, JArray expected, JPath path,
Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference CompareItems(JArray actual, JArray expected, JPath path)
{
JToken[] actualChildren = actual.Children().ToArray();
JToken[] expectedChildren = expected.Children().ToArray();
Expand All @@ -117,8 +124,7 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J

for (int i = 0; i < actualChildren.Length; i++)
{
Difference firstDifference = FindFirstDifference(actualChildren[i], expectedChildren[i],
path.AddIndex(i), false, config);
Difference firstDifference = FindFirstDifference(actualChildren[i], expectedChildren[i], path.AddIndex(i));

if (firstDifference != null)
{
Expand All @@ -129,20 +135,17 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J
return null;
}

private static Difference FindJObjectDifference(JObject actual, JToken expected, JPath path, bool ignoreExtraProperties,
Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference FindJObjectDifference(JObject actual, JToken expected, JPath path)
{
if (expected is not JObject expectedObject)
{
return new Difference(DifferenceKind.OtherType, path, Describe(actual.Type), Describe(expected.Type));
}

return CompareProperties(actual?.Properties(), expectedObject.Properties(), path, ignoreExtraProperties, config);
return CompareProperties(actual?.Properties(), expectedObject.Properties(), path);
}

private static Difference CompareProperties(IEnumerable<JProperty> actual, IEnumerable<JProperty> expected, JPath path,
bool ignoreExtraProperties,
Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference CompareProperties(IEnumerable<JProperty> actual, IEnumerable<JProperty> expected, JPath path)
{
var actualDictionary = actual?.ToDictionary(p => p.Name, p => p.Value) ?? new Dictionary<string, JToken>();
var expectedDictionary = expected?.ToDictionary(p => p.Name, p => p.Value) ?? new Dictionary<string, JToken>();
Expand All @@ -168,7 +171,7 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J
JToken actualValue = actualDictionary[expectedPair.Key];

Difference firstDifference = FindFirstDifference(actualValue, expectedPair.Value,
path.AddProperty(expectedPair.Key), ignoreExtraProperties, config);
path.AddProperty(expectedPair.Key));

if (firstDifference != null)
{
Expand All @@ -179,9 +182,7 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J
return null;
}

private static Difference FindJPropertyDifference(JProperty actualProperty, JToken expected, JPath path,
bool ignoreExtraProperties,
Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference FindJPropertyDifference(JProperty actualProperty, JToken expected, JPath path)
{
if (expected is not JProperty expectedProperty)
{
Expand All @@ -193,20 +194,20 @@ private static Difference CompareExpectedItems(JArray actual, JArray expected, J
return new Difference(DifferenceKind.OtherName, path);
}

return FindFirstDifference(actualProperty.Value, expectedProperty.Value, path, ignoreExtraProperties, config);
return FindFirstDifference(actualProperty.Value, expectedProperty.Value, path);
}

private static Difference FindValueDifference(JValue actualValue, JToken expected, JPath path, Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference FindValueDifference(JValue actualValue, JToken expected, JPath path)
{
if (expected is not JValue expectedValue)
{
return new Difference(DifferenceKind.OtherType, path, Describe(actualValue.Type), Describe(expected.Type));
}

return CompareValues(actualValue, expectedValue, path, config);
return CompareValues(actualValue, expectedValue, path);
}

private static Difference CompareValues(JValue actual, JValue expected, JPath path, Func<IJsonAssertionOptions<object>, IJsonAssertionOptions<object>> config)
private Difference CompareValues(JValue actual, JValue expected, JPath path)
{
if (actual.Type != expected.Type)
{
Expand All @@ -216,7 +217,9 @@ private static Difference CompareValues(JValue actual, JValue expected, JPath pa
bool hasMismatches;
using (var scope = new AssertionScope())
{
actual.Value.Should().BeEquivalentTo(expected.Value, options => (JsonAssertionOptions<object>)config.Invoke(new JsonAssertionOptions<object>(options)));
actual.Value.Should().BeEquivalentTo(expected.Value, options =>
(JsonAssertionOptions<object>)config.Invoke(new JsonAssertionOptions<object>(options)));

hasMismatches = scope.Discard().Length > 0;
}

Expand Down

0 comments on commit 600b0af

Please sign in to comment.