|
3 | 3 | using System.Linq; |
4 | 4 | using Newtonsoft.Json.Linq; |
5 | 5 |
|
6 | | -namespace FluentAssertions.Json.Common |
| 6 | +namespace FluentAssertions.Json.Common; |
| 7 | + |
| 8 | +internal static class JTokenExtensions |
7 | 9 | { |
8 | | - internal static class JTokenExtensions |
9 | | - { |
10 | | - private static readonly JTokenComparer Comparer = new(); |
| 10 | + private static readonly JTokenComparer Comparer = new(); |
11 | 11 |
|
12 | | - /// <summary> |
13 | | - /// Recursively sorts the properties of JObject instances by name and |
14 | | - /// the elements of JArray instances by their string representation, |
15 | | - /// producing a normalized JToken for consistent comparison |
16 | | - /// </summary> |
17 | | - public static JToken Normalize(this JToken token) |
| 12 | + /// <summary> |
| 13 | + /// Recursively sorts the properties of JObject instances by name and |
| 14 | + /// the elements of JArray instances by their string representation, |
| 15 | + /// producing a normalized JToken for consistent comparison |
| 16 | + /// </summary> |
| 17 | + public static JToken Normalize(this JToken token) |
| 18 | + { |
| 19 | + return token switch |
18 | 20 | { |
19 | | - return token switch |
20 | | - { |
21 | | - JObject obj => new JObject(obj.Properties().OrderBy(p => p.Name).Select(p => new JProperty(p.Name, Normalize(p.Value)))), |
22 | | - JArray array => new JArray(array.Select(Normalize).OrderBy(x => x, Comparer)), |
23 | | - _ => token |
24 | | - }; |
25 | | - } |
| 21 | + JObject obj => new JObject(obj.Properties().OrderBy(p => p.Name, StringComparer.Ordinal).Select(p => new JProperty(p.Name, Normalize(p.Value)))), |
| 22 | + JArray array => new JArray(array.Select(Normalize).OrderBy(x => x, Comparer)), |
| 23 | + _ => token |
| 24 | + }; |
| 25 | + } |
26 | 26 |
|
27 | | - private sealed class JTokenComparer : IComparer<JToken> |
| 27 | + private sealed class JTokenComparer : IComparer<JToken> |
| 28 | + { |
| 29 | + public int Compare(JToken x, JToken y) |
28 | 30 | { |
29 | | - public int Compare(JToken x, JToken y) |
| 31 | + if (ReferenceEquals(x, y)) |
30 | 32 | { |
31 | | - if (ReferenceEquals(x, y)) |
32 | | - return 0; |
33 | | - |
34 | | - if (x is null) |
35 | | - return -1; |
36 | | - |
37 | | - if (y is null) |
38 | | - return 1; |
39 | | - |
40 | | - var typeComparison = x.Type.CompareTo(y.Type); |
41 | | - if (typeComparison != 0) |
42 | | - return typeComparison; |
43 | | - |
44 | | - return x switch |
45 | | - { |
46 | | - JArray a => Compare(a, (JArray)y), |
47 | | - JObject o => Compare(o, (JObject)y), |
48 | | - JProperty p => Compare(p, (JProperty)y), |
49 | | - JValue v => Compare(v, (JValue)y), |
50 | | - JConstructor c => Compare(c, (JConstructor)y), |
51 | | - _ => string.Compare(x.ToString(), y.ToString(), StringComparison.Ordinal) |
52 | | - }; |
| 33 | + return 0; |
53 | 34 | } |
54 | 35 |
|
55 | | - private static int Compare(JValue x, JValue y) => Comparer<object>.Default.Compare(x.Value, y.Value); |
56 | | - |
57 | | - private static int Compare(JConstructor x, JConstructor y) |
| 36 | + if (x is null) |
58 | 37 | { |
59 | | - var nameComparison = string.Compare(x.Name, y.Name, StringComparison.Ordinal); |
60 | | - return nameComparison != 0 ? nameComparison : Compare(x, (JContainer)y); |
| 38 | + return -1; |
61 | 39 | } |
62 | 40 |
|
63 | | - private static int Compare(JContainer x, JContainer y) |
| 41 | + if (y is null) |
64 | 42 | { |
65 | | - var countComparison = x.Count.CompareTo(y.Count); |
66 | | - if (countComparison != 0) |
67 | | - return countComparison; |
| 43 | + return 1; |
| 44 | + } |
68 | 45 |
|
69 | | - return x |
70 | | - .Select((t, i) => Comparer.Compare(t, y[i])) |
71 | | - .FirstOrDefault(itemComparison => itemComparison != 0); |
| 46 | + var typeComparison = x.Type.CompareTo(y.Type); |
| 47 | + if (typeComparison != 0) |
| 48 | + { |
| 49 | + return typeComparison; |
72 | 50 | } |
73 | 51 |
|
74 | | - private static int Compare(JObject x, JObject y) |
| 52 | + return x switch |
75 | 53 | { |
76 | | - var countComparison = x.Count.CompareTo(y.Count); |
77 | | - if (countComparison != 0) |
78 | | - return countComparison; |
| 54 | + JArray a => Compare(a, (JArray)y), |
| 55 | + JObject o => Compare(o, (JObject)y), |
| 56 | + JProperty p => Compare(p, (JProperty)y), |
| 57 | + JValue v => Compare(v, (JValue)y), |
| 58 | + JConstructor c => Compare(c, (JConstructor)y), |
| 59 | + _ => string.CompareOrdinal(x.ToString(), y.ToString()) |
| 60 | + }; |
| 61 | + } |
| 62 | + |
| 63 | + private static int Compare(JValue x, JValue y) => Comparer<object>.Default.Compare(x.Value, y.Value); |
| 64 | + |
| 65 | + private static int Compare(JConstructor x, JConstructor y) |
| 66 | + { |
| 67 | + var nameComparison = string.CompareOrdinal(x.Name, y.Name); |
| 68 | + return nameComparison != 0 ? nameComparison : Compare(x, (JContainer)y); |
| 69 | + } |
79 | 70 |
|
80 | | - return x.Properties() |
81 | | - .OrderBy(p => p.Name) |
82 | | - .Zip(y.Properties().OrderBy(p => p.Name), (px, py) => Compare(px, py)) |
83 | | - .FirstOrDefault(itemComparison => itemComparison != 0); |
| 71 | + private static int Compare(JContainer x, JContainer y) |
| 72 | + { |
| 73 | + var countComparison = x.Count.CompareTo(y.Count); |
| 74 | + if (countComparison != 0) |
| 75 | + { |
| 76 | + return countComparison; |
84 | 77 | } |
85 | 78 |
|
86 | | - private static int Compare(JProperty x, JProperty y) |
| 79 | + return x |
| 80 | + .Select((t, i) => Comparer.Compare(t, y[i])) |
| 81 | + .FirstOrDefault(itemComparison => itemComparison != 0); |
| 82 | + } |
| 83 | + |
| 84 | + private static int Compare(JObject x, JObject y) |
| 85 | + { |
| 86 | + var countComparison = x.Count.CompareTo(y.Count); |
| 87 | + if (countComparison != 0) |
87 | 88 | { |
88 | | - var nameComparison = string.Compare(x.Name, y.Name, StringComparison.Ordinal); |
89 | | - return nameComparison != 0 ? nameComparison : Comparer.Compare(x.Value, y.Value); |
| 89 | + return countComparison; |
90 | 90 | } |
| 91 | + |
| 92 | + return x.Properties() |
| 93 | + .OrderBy(p => p.Name, StringComparer.Ordinal) |
| 94 | + .Zip(y.Properties().OrderBy(p => p.Name, StringComparer.Ordinal), (px, py) => Compare(px, py)) |
| 95 | + .FirstOrDefault(itemComparison => itemComparison != 0); |
| 96 | + } |
| 97 | + |
| 98 | + private static int Compare(JProperty x, JProperty y) |
| 99 | + { |
| 100 | + var nameComparison = string.CompareOrdinal(x.Name, y.Name); |
| 101 | + return nameComparison != 0 ? nameComparison : Comparer.Compare(x.Value, y.Value); |
91 | 102 | } |
92 | 103 | } |
93 | 104 | } |
0 commit comments