Skip to content

Commit f75ffe1

Browse files
v1.6.0
- Improves the BeJsonSerializableInto() and BeJsonDeserializableInto() methods to use C# raw string literal.
1 parent 771f370 commit f75ffe1

File tree

6 files changed

+1157
-37
lines changed

6 files changed

+1157
-37
lines changed

.github/workflows/github-actions-release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
type: string
88
description: The version of the library
99
required: true
10-
default: 1.5.0
10+
default: 1.6.0
1111
VersionSuffix:
1212
type: string
1313
description: The version suffix of the library (for example rc.1)

README.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,31 @@ public void Serialization()
116116
And when an exception is occured, the exception message contains the JSON path of the property which is error:
117117
![Pretty exception](https://raw.githubusercontent.com/PosInformatique/PosInformatique.FluentAssertions.Json/main/docs/PrettyExceptionSample.png)
118118

119+
Since the version 1.6.0 it is possible to use a [raw string literal](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string)
120+
with a JSON content in the string:
121+
122+
```csharp
123+
[Fact]
124+
public void Serialization()
125+
{
126+
var customer = new Customer()
127+
{
128+
Id = 1234,
129+
Name = "Gilles TOURREAU",
130+
Gender = Gender.Male,
131+
};
132+
133+
customer.Should().BeJsonSerializableInto(
134+
"""
135+
{
136+
"id": 1234,
137+
"name": "Gilles TOURREAU",
138+
"gender": 100
139+
}
140+
""");
141+
}
142+
```
143+
119144
### Test the deserialization of a JSON object to a .NET Object
120145
You can in the same way test the deserialization JSON object into a .NET object.
121146

@@ -139,7 +164,32 @@ public void Deserialization()
139164
}
140165
```
141166

142-
## Test polymorphisme serialization with property discriminator
167+
Since the version 1.6.0 it is possible to use a [raw string literal](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string)
168+
with a JSON string content as input of the `Should()` to assert:
169+
170+
```
171+
[Fact]
172+
public void Deserialization()
173+
{
174+
var json =
175+
"""
176+
{
177+
"id": 1234,
178+
"name": "Gilles TOURREAU",
179+
"gender": 100
180+
}
181+
""";
182+
183+
json.Should().BeJsonDeserializableInto(new Customer()
184+
{
185+
Id = 1234,
186+
Name = "Gilles TOURREAU",
187+
Gender = Gender.Male,
188+
});
189+
}
190+
```
191+
192+
## Test polymorphism serialization with property discriminator
143193
With the .NET 7.0 version of the `System.Text.Json` it is possible to serialize and deserialize JSON object
144194
with property discriminators for polymorphism scenario
145195
(See the [How to serialize properties of derived classes with System.Text.Json](https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism?pivots=dotnet-7-0))

src/FluentAssertions.Json/JsonElementComparer.cs

Lines changed: 148 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,168 @@ namespace PosInformatique.FluentAssertions.Json
1212

1313
internal static class JsonElementComparer
1414
{
15-
public static IReadOnlyList<string> Compare(JsonDocument document, object? expected)
15+
public static IReadOnlyList<string> CompareWithDocument(JsonDocument document, JsonDocument expected)
1616
{
17-
return Compare(document.RootElement, expected, "$");
17+
return CompareWithElement(document.RootElement, expected.RootElement, "$");
1818
}
1919

20-
public static IReadOnlyList<string> Compare(JsonElement element, object? expected, string initialPath)
20+
public static IReadOnlyList<string> CompareWithElement(JsonElement element, JsonElement expected, string initialPath)
2121
{
2222
var errors = new List<string>();
2323

2424
var path = new Stack<string>();
2525

2626
path.Push(initialPath);
2727

28-
Compare(element, expected, path, errors);
28+
CompareWithElement(element, expected, path, errors);
2929

3030
path.Pop();
3131

3232
return errors;
3333
}
3434

35-
private static void Compare(JsonElement element, object? expected, Stack<string> path, List<string> errors)
35+
public static IReadOnlyList<string> CompareWithObject(JsonDocument document, object? expected)
36+
{
37+
return CompareWithObject(document.RootElement, expected, "$");
38+
}
39+
40+
public static IReadOnlyList<string> CompareWithObject(JsonElement element, object? expected, string initialPath)
41+
{
42+
var errors = new List<string>();
43+
44+
var path = new Stack<string>();
45+
46+
path.Push(initialPath);
47+
48+
CompareWithObject(element, expected, path, errors);
49+
50+
path.Pop();
51+
52+
return errors;
53+
}
54+
55+
private static void CompareWithElement(JsonElement element, JsonElement expected, Stack<string> path, List<string> errors)
56+
{
57+
if (element.ValueKind != expected.ValueKind)
58+
{
59+
errors.Add($"{GetPath(path)}: Expected property to be '{expected.ValueKind}' type instead of '{element.ValueKind}' type.");
60+
return;
61+
}
62+
63+
if (element.ValueKind == JsonValueKind.String)
64+
{
65+
var value = element.GetString();
66+
var expectedStringValue = expected.GetString();
67+
68+
if (value != expectedStringValue)
69+
{
70+
errors.Add($"{GetPath(path)}: Expected '{expected}' instead of '{value}'.");
71+
return;
72+
}
73+
}
74+
else if (element.ValueKind == JsonValueKind.Number)
75+
{
76+
var value = element.GetDouble();
77+
var expectedDoubleValue = expected.GetDouble();
78+
79+
if (value != expectedDoubleValue)
80+
{
81+
errors.Add($"{GetPath(path)}: Expected '{expected}' instead of '{value}'.");
82+
return;
83+
}
84+
}
85+
else if (element.ValueKind == JsonValueKind.Object)
86+
{
87+
var expectedPropertyEnumerator = expected.EnumerateObject();
88+
89+
foreach (var property in element.EnumerateObject())
90+
{
91+
if (!expectedPropertyEnumerator.MoveNext())
92+
{
93+
errors.Add($"{GetPath(path)}: Expected no property but found '{property.Name}' property.");
94+
continue;
95+
}
96+
97+
var expectedProperty = expectedPropertyEnumerator.Current;
98+
99+
if (property.Name != expectedProperty.Name)
100+
{
101+
errors.Add($"{GetPath(path)}: Expected property with the '{expectedProperty.Name}' name but found '{property.Name}' instead.");
102+
continue;
103+
}
104+
105+
path.Push("." + property.Name);
106+
107+
var expectedValueOfProperty = expectedProperty.Value;
108+
109+
CompareWithElement(property.Value, expectedValueOfProperty, path, errors);
110+
111+
path.Pop();
112+
}
113+
114+
if (expectedPropertyEnumerator.MoveNext())
115+
{
116+
errors.Add($"{GetPath(path)}: Expected '{expectedPropertyEnumerator.Current.Name}' property but found no property.");
117+
return;
118+
}
119+
}
120+
else if (element.ValueKind == JsonValueKind.Array)
121+
{
122+
var expectedArrayEnumerator = expected.EnumerateArray();
123+
var index = 0;
124+
125+
foreach (var item in element.EnumerateArray())
126+
{
127+
if (!expectedArrayEnumerator.MoveNext())
128+
{
129+
var actualCount = element.EnumerateArray().Count();
130+
131+
errors.Add($"{GetPath(path)}: Expected {index} item(s) but found {actualCount}.");
132+
continue;
133+
}
134+
135+
var expectedItem = expectedArrayEnumerator.Current;
136+
137+
path.Push($"[{index}]");
138+
139+
CompareWithElement(item, expectedItem, path, errors);
140+
141+
path.Pop();
142+
143+
index++;
144+
}
145+
146+
if (expectedArrayEnumerator.MoveNext())
147+
{
148+
var expectedCount = expected.GetArrayLength();
149+
150+
errors.Add($"{GetPath(path)}: Expected {expectedCount} item(s) but found {index}.");
151+
return;
152+
}
153+
}
154+
else if (element.ValueKind == JsonValueKind.True)
155+
{
156+
var expectedBooleanValue = expected.GetBoolean();
157+
158+
if (expectedBooleanValue != true)
159+
{
160+
errors.Add($"{GetPath(path)}: Expected '{expectedBooleanValue}' instead of '{true}'.");
161+
return;
162+
}
163+
}
164+
else if (element.ValueKind == JsonValueKind.False)
165+
{
166+
var expectedBooleanValue = expected.GetBoolean();
167+
168+
if (expectedBooleanValue != false)
169+
{
170+
errors.Add($"{GetPath(path)}: Expected '{expectedBooleanValue}' instead of '{false}'.");
171+
return;
172+
}
173+
}
174+
}
175+
176+
private static void CompareWithObject(JsonElement element, object? expected, Stack<string> path, List<string> errors)
36177
{
37178
if (element.ValueKind == JsonValueKind.String)
38179
{
@@ -98,7 +239,7 @@ private static void Compare(JsonElement element, object? expected, Stack<string>
98239

99240
var expectedValueOfProperty = expectedProperty.GetValue(expected);
100241

101-
Compare(property.Value, expectedValueOfProperty, path, errors);
242+
CompareWithObject(property.Value, expectedValueOfProperty, path, errors);
102243

103244
path.Pop();
104245
}
@@ -134,7 +275,7 @@ private static void Compare(JsonElement element, object? expected, Stack<string>
134275

135276
path.Push($"[{index}]");
136277

137-
Compare(item, expectedItem, path, errors);
278+
CompareWithObject(item, expectedItem, path, errors);
138279

139280
path.Pop();
140281

0 commit comments

Comments
 (0)