Skip to content

Commit b779924

Browse files
v1.4.0 (#20)
* Add new BeJsonDeserializableInto() method to check if a stream contains a JSON object (fixes #19).
1 parent 1c07aaf commit b779924

File tree

6 files changed

+149
-3
lines changed

6 files changed

+149
-3
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.3.0
10+
default: 1.4.0
1111
VersionSuffix:
1212
type: string
1313
description: The version suffix of the library (for example rc.1)

PosInformatique.FluentAssertions.Json.sln

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7928175B
2222
tests\.editorconfig = tests\.editorconfig
2323
EndProjectSection
2424
EndProject
25+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F618D0FB-ECB8-4E1B-BAD3-5B3618FB8EB2}"
26+
EndProject
27+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{FFCF0F26-C911-4595-BEF0-9393206E5FDD}"
28+
ProjectSection(SolutionItems) = preProject
29+
.github\workflows\github-actions-ci.yaml = .github\workflows\github-actions-ci.yaml
30+
.github\workflows\github-actions-release.yml = .github\workflows\github-actions-release.yml
31+
EndProjectSection
32+
EndProject
2533
Global
2634
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2735
Debug|Any CPU = Debug|Any CPU
@@ -42,6 +50,8 @@ Global
4250
EndGlobalSection
4351
GlobalSection(NestedProjects) = preSolution
4452
{7928175B-C3B3-4F81-B956-BF4E4F816436} = {882949E5-7DCE-4EB6-8E9A-CB88FD0ED1F9}
53+
{F618D0FB-ECB8-4E1B-BAD3-5B3618FB8EB2} = {882949E5-7DCE-4EB6-8E9A-CB88FD0ED1F9}
54+
{FFCF0F26-C911-4595-BEF0-9393206E5FDD} = {F618D0FB-ECB8-4E1B-BAD3-5B3618FB8EB2}
4555
EndGlobalSection
4656
GlobalSection(ExtensibilityGlobals) = postSolution
4757
SolutionGuid = {0582B8EB-4FA4-488E-9953-9B7CEEE4E94F}

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# PosInformatique.FluentAssertions.Json
22
PosInformatique.FluentAssertions.Json is a library to assert JSON serialization using the *Fluent Assertions* library style coding.
33

4+
[![Nuget](https://img.shields.io/nuget/v/PosInformatique.FluentAssertions.Json?label=PosInformatique.FluentAssertions.Json)](https://www.nuget.org/packages/PosInformatique.FluentAssertions.Json/)
5+
46
## Installing from NuGet
57
The [PosInformatique.FluentAssertions.Json](https://www.nuget.org/packages/PosInformatique.FluentAssertions.Json/)
68
library is available directly on the

src/FluentAssertions.Json/FluentAssertions.Json.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
<PackageProjectUrl>https://github.com/PosInformatique/PosInformatique.FluentAssertions.Json</PackageProjectUrl>
1212
<PackageReadmeFile>README.md</PackageReadmeFile>
1313
<PackageReleaseNotes>
14+
1.4.0
15+
- Add new overload BeJsonDeserializableInto() method to test if a Stream contains a JSON serializable object.
16+
1417
1.3.0
1518
- Add new overload BeJsonDeserializableInto() method to test the string collections.
1619
- Add new overload BeJsonDeserializableInto() method to test the string and numeric values.

src/FluentAssertions.Json/JsonFluentAssertionsExtensions.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace FluentAssertions
1414
using FluentAssertions.Equivalency;
1515
using FluentAssertions.Numeric;
1616
using FluentAssertions.Primitives;
17+
using FluentAssertions.Streams;
1718
using PosInformatique.FluentAssertions.Json;
1819

1920
/// <summary>
@@ -142,7 +143,7 @@ public static void BeJsonDeserializableInto<T>(this StringCollectionAssertions a
142143
public static void BeJsonDeserializableInto<T>(this NumericAssertions<T> assertions, T expectedObject, JsonSerializerOptions? options = null)
143144
where T : struct, IComparable<T>
144145
{
145-
BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options));
146+
BeJsonDeserializableIntoCore(assertions.Subject!, expectedObject, GetSerializerOptions(options));
146147
}
147148

148149
/// <summary>
@@ -159,6 +160,20 @@ public static void BeJsonDeserializableInto<T>(this StringAssertions assertions,
159160
BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options));
160161
}
161162

163+
/// <summary>
164+
/// Check if the JSON subject stream is deserializable into the specified <paramref name="expectedObject"/> argument.
165+
/// </summary>
166+
/// <typeparam name="T">Type of the object to deserialize from JSON.</typeparam>
167+
/// <param name="assertions"><see cref="StreamAssertions"/> which contains the JSON subject to deserialize.</param>
168+
/// <param name="expectedObject">Expected string value deserialized expected.</param>
169+
/// <param name="options"><see cref="JsonSerializerOptions"/> to use to assert the deserialization. If not specified
170+
/// the default <see cref="IFluentAssertionsJsonConfiguration.JsonSerializerOptions"/> of the <see cref="FluentAssertionsJson.Configuration"/>
171+
/// will be used.</param>
172+
public static void BeJsonDeserializableInto<T>(this StreamAssertions assertions, T expectedObject, JsonSerializerOptions? options = null)
173+
{
174+
BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options));
175+
}
176+
162177
/// <summary>
163178
/// Check if the JSON subject object is deserializable into the specified <paramref name="expectedObject"/> argument.
164179
/// </summary>
@@ -226,7 +241,7 @@ public static void BeJsonDeserializableInto<T>(this NumericAssertions<T> asserti
226241

227242
configureOptions(optionsCopy);
228243

229-
BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, optionsCopy);
244+
BeJsonDeserializableIntoCore(assertions.Subject!, expectedObject, optionsCopy);
230245
}
231246

232247
/// <summary>
@@ -277,11 +292,27 @@ private static void BeJsonSerializableIntoCore<TBase>(ObjectAssertions assertion
277292
}
278293
}
279294

295+
private static void BeJsonDeserializableIntoCore<T>(Stream subject, T expectedObject, JsonSerializerOptions options)
296+
{
297+
using var memoryStream = new MemoryStream();
298+
299+
subject.CopyTo(memoryStream);
300+
301+
var deserializedObject = JsonSerializer.Deserialize<T>(memoryStream.ToArray(), options);
302+
303+
AreEquivalent(deserializedObject, expectedObject);
304+
}
305+
280306
private static void BeJsonDeserializableIntoCore<T>(object subject, T expectedObject, JsonSerializerOptions options)
281307
{
282308
var jsonText = JsonSerializer.Serialize(subject, options);
283309
var deserializedObject = JsonSerializer.Deserialize<T>(jsonText, options);
284310

311+
AreEquivalent(deserializedObject, expectedObject);
312+
}
313+
314+
private static void AreEquivalent<T>(T deserializedObject, T expectedObject)
315+
{
285316
deserializedObject.Should().BeEquivalentTo(expectedObject, opt =>
286317
{
287318
opt.Using<object>(ctx =>

tests/FluentAssertions.Json.Tests/JsonFluentAssertionsExtensionsTest.cs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,106 @@ public void BeJsonDeserializableInto()
848848
json.Should().BeJsonDeserializableInto(expectedObject);
849849
}
850850

851+
[Fact]
852+
public void BeJsonDeserializableInto_FromStream()
853+
{
854+
var json = new
855+
{
856+
string_property = "The string value",
857+
int32_property = 1234,
858+
boolean_property = true,
859+
null_property = (string)null,
860+
inner_object = new
861+
{
862+
inner_string_property = "Inner string value",
863+
},
864+
collection_int = new[]
865+
{
866+
10,
867+
20,
868+
},
869+
collection_object = new[]
870+
{
871+
new
872+
{
873+
inner_string_property = "Inner object 1",
874+
},
875+
new
876+
{
877+
inner_string_property = "Inner object 2",
878+
},
879+
},
880+
};
881+
882+
using var stream = new MemoryStream();
883+
884+
JsonSerializer.Serialize(stream, json);
885+
886+
stream.Position = 0;
887+
888+
var expectedObject = new JsonSerializableClass()
889+
{
890+
StringProperty = "The string value",
891+
Int32Property = 1234,
892+
BooleanProperty = true,
893+
NullProperty = null,
894+
InnerObject = new JsonSerializableClassInnerObject()
895+
{
896+
InnerStringProperty = "Inner string value",
897+
},
898+
CollectionInt32 = new List<int>
899+
{
900+
10,
901+
20,
902+
},
903+
CollectionObjects = new List<JsonSerializableClassInnerObject>()
904+
{
905+
new JsonSerializableClassInnerObject()
906+
{
907+
InnerStringProperty = "Inner object 1",
908+
},
909+
new JsonSerializableClassInnerObject()
910+
{
911+
InnerStringProperty = "Inner object 2",
912+
},
913+
},
914+
};
915+
916+
stream.Should().BeJsonDeserializableInto(expectedObject);
917+
}
918+
919+
[Fact]
920+
public void BeJsonDeserializableInto_FromStream_WithSpecificOptions()
921+
{
922+
var json = new
923+
{
924+
int32_property = 10,
925+
enum_property = "B",
926+
};
927+
928+
using var stream = new MemoryStream();
929+
930+
JsonSerializer.Serialize(stream, json);
931+
932+
stream.Position = 0;
933+
934+
var options = new JsonSerializerOptions()
935+
{
936+
Converters =
937+
{
938+
new JsonStringEnumConverter(),
939+
},
940+
};
941+
942+
stream.Should().BeJsonDeserializableInto(
943+
new JsonSerializableClassWithEnum()
944+
{
945+
Int32Property = 10,
946+
EnumProperty = EnumTest.B,
947+
},
948+
options);
949+
}
950+
851951
[Fact]
852952
public void BeJsonDeserializableInto_WithSubjectNullAndExpectedNull()
853953
{

0 commit comments

Comments
 (0)