Skip to content

Commit

Permalink
v1.4.0 (#20)
Browse files Browse the repository at this point in the history
* Add new BeJsonDeserializableInto() method to check if a stream contains a JSON object (fixes #19).
  • Loading branch information
GillesTourreau authored Oct 28, 2024
1 parent 1c07aaf commit b779924
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/github-actions-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
type: string
description: The version of the library
required: true
default: 1.3.0
default: 1.4.0
VersionSuffix:
type: string
description: The version suffix of the library (for example rc.1)
Expand Down
10 changes: 10 additions & 0 deletions PosInformatique.FluentAssertions.Json.sln
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7928175B
tests\.editorconfig = tests\.editorconfig
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{F618D0FB-ECB8-4E1B-BAD3-5B3618FB8EB2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{FFCF0F26-C911-4595-BEF0-9393206E5FDD}"
ProjectSection(SolutionItems) = preProject
.github\workflows\github-actions-ci.yaml = .github\workflows\github-actions-ci.yaml
.github\workflows\github-actions-release.yml = .github\workflows\github-actions-release.yml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -42,6 +50,8 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7928175B-C3B3-4F81-B956-BF4E4F816436} = {882949E5-7DCE-4EB6-8E9A-CB88FD0ED1F9}
{F618D0FB-ECB8-4E1B-BAD3-5B3618FB8EB2} = {882949E5-7DCE-4EB6-8E9A-CB88FD0ED1F9}
{FFCF0F26-C911-4595-BEF0-9393206E5FDD} = {F618D0FB-ECB8-4E1B-BAD3-5B3618FB8EB2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0582B8EB-4FA4-488E-9953-9B7CEEE4E94F}
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# PosInformatique.FluentAssertions.Json
PosInformatique.FluentAssertions.Json is a library to assert JSON serialization using the *Fluent Assertions* library style coding.

[![Nuget](https://img.shields.io/nuget/v/PosInformatique.FluentAssertions.Json?label=PosInformatique.FluentAssertions.Json)](https://www.nuget.org/packages/PosInformatique.FluentAssertions.Json/)

## Installing from NuGet
The [PosInformatique.FluentAssertions.Json](https://www.nuget.org/packages/PosInformatique.FluentAssertions.Json/)
library is available directly on the
Expand Down
3 changes: 3 additions & 0 deletions src/FluentAssertions.Json/FluentAssertions.Json.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<PackageProjectUrl>https://github.com/PosInformatique/PosInformatique.FluentAssertions.Json</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>
1.4.0
- Add new overload BeJsonDeserializableInto() method to test if a Stream contains a JSON serializable object.

1.3.0
- Add new overload BeJsonDeserializableInto() method to test the string collections.
- Add new overload BeJsonDeserializableInto() method to test the string and numeric values.
Expand Down
35 changes: 33 additions & 2 deletions src/FluentAssertions.Json/JsonFluentAssertionsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace FluentAssertions
using FluentAssertions.Equivalency;
using FluentAssertions.Numeric;
using FluentAssertions.Primitives;
using FluentAssertions.Streams;
using PosInformatique.FluentAssertions.Json;

/// <summary>
Expand Down Expand Up @@ -142,7 +143,7 @@ public static void BeJsonDeserializableInto<T>(this StringCollectionAssertions a
public static void BeJsonDeserializableInto<T>(this NumericAssertions<T> assertions, T expectedObject, JsonSerializerOptions? options = null)
where T : struct, IComparable<T>
{
BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options));
BeJsonDeserializableIntoCore(assertions.Subject!, expectedObject, GetSerializerOptions(options));
}

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

/// <summary>
/// Check if the JSON subject stream is deserializable into the specified <paramref name="expectedObject"/> argument.
/// </summary>
/// <typeparam name="T">Type of the object to deserialize from JSON.</typeparam>
/// <param name="assertions"><see cref="StreamAssertions"/> which contains the JSON subject to deserialize.</param>
/// <param name="expectedObject">Expected string value deserialized expected.</param>
/// <param name="options"><see cref="JsonSerializerOptions"/> to use to assert the deserialization. If not specified
/// the default <see cref="IFluentAssertionsJsonConfiguration.JsonSerializerOptions"/> of the <see cref="FluentAssertionsJson.Configuration"/>
/// will be used.</param>
public static void BeJsonDeserializableInto<T>(this StreamAssertions assertions, T expectedObject, JsonSerializerOptions? options = null)
{
BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, GetSerializerOptions(options));
}

/// <summary>
/// Check if the JSON subject object is deserializable into the specified <paramref name="expectedObject"/> argument.
/// </summary>
Expand Down Expand Up @@ -226,7 +241,7 @@ public static void BeJsonDeserializableInto<T>(this NumericAssertions<T> asserti

configureOptions(optionsCopy);

BeJsonDeserializableIntoCore(assertions.Subject, expectedObject, optionsCopy);
BeJsonDeserializableIntoCore(assertions.Subject!, expectedObject, optionsCopy);
}

/// <summary>
Expand Down Expand Up @@ -277,11 +292,27 @@ private static void BeJsonSerializableIntoCore<TBase>(ObjectAssertions assertion
}
}

private static void BeJsonDeserializableIntoCore<T>(Stream subject, T expectedObject, JsonSerializerOptions options)
{
using var memoryStream = new MemoryStream();

subject.CopyTo(memoryStream);

var deserializedObject = JsonSerializer.Deserialize<T>(memoryStream.ToArray(), options);

AreEquivalent(deserializedObject, expectedObject);
}

private static void BeJsonDeserializableIntoCore<T>(object subject, T expectedObject, JsonSerializerOptions options)
{
var jsonText = JsonSerializer.Serialize(subject, options);
var deserializedObject = JsonSerializer.Deserialize<T>(jsonText, options);

AreEquivalent(deserializedObject, expectedObject);
}

private static void AreEquivalent<T>(T deserializedObject, T expectedObject)
{
deserializedObject.Should().BeEquivalentTo(expectedObject, opt =>
{
opt.Using<object>(ctx =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,106 @@ public void BeJsonDeserializableInto()
json.Should().BeJsonDeserializableInto(expectedObject);
}

[Fact]
public void BeJsonDeserializableInto_FromStream()
{
var json = new
{
string_property = "The string value",
int32_property = 1234,
boolean_property = true,
null_property = (string)null,
inner_object = new
{
inner_string_property = "Inner string value",
},
collection_int = new[]
{
10,
20,
},
collection_object = new[]
{
new
{
inner_string_property = "Inner object 1",
},
new
{
inner_string_property = "Inner object 2",
},
},
};

using var stream = new MemoryStream();

JsonSerializer.Serialize(stream, json);

stream.Position = 0;

var expectedObject = new JsonSerializableClass()
{
StringProperty = "The string value",
Int32Property = 1234,
BooleanProperty = true,
NullProperty = null,
InnerObject = new JsonSerializableClassInnerObject()
{
InnerStringProperty = "Inner string value",
},
CollectionInt32 = new List<int>
{
10,
20,
},
CollectionObjects = new List<JsonSerializableClassInnerObject>()
{
new JsonSerializableClassInnerObject()
{
InnerStringProperty = "Inner object 1",
},
new JsonSerializableClassInnerObject()
{
InnerStringProperty = "Inner object 2",
},
},
};

stream.Should().BeJsonDeserializableInto(expectedObject);
}

[Fact]
public void BeJsonDeserializableInto_FromStream_WithSpecificOptions()
{
var json = new
{
int32_property = 10,
enum_property = "B",
};

using var stream = new MemoryStream();

JsonSerializer.Serialize(stream, json);

stream.Position = 0;

var options = new JsonSerializerOptions()
{
Converters =
{
new JsonStringEnumConverter(),
},
};

stream.Should().BeJsonDeserializableInto(
new JsonSerializableClassWithEnum()
{
Int32Property = 10,
EnumProperty = EnumTest.B,
},
options);
}

[Fact]
public void BeJsonDeserializableInto_WithSubjectNullAndExpectedNull()
{
Expand Down

0 comments on commit b779924

Please sign in to comment.