Skip to content

Commit 0d30a9d

Browse files
authored
chore: update to Mockolate v1.4.0 (#62)
Updates Mockolate dependency to v1.4.0 and adapts the JSON HttpContent matching API to the newer `It.IsHttpContent()` fluent pattern. ### Key Changes: - Bumped Mockolate package version from 1.2.0 to 1.4.0. - Replaced `It.IsJsonContent()` / `WithBody*` with `It.IsHttpContent().WithJson*` across tests and docs. - Refactored JSON matching implementation to hang off `ItExtensions.IHttpContentParameter` via extension members.
1 parent b028f7a commit 0d30a9d

6 files changed

Lines changed: 133 additions & 179 deletions

File tree

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<ItemGroup>
66
<PackageVersion Include="aweXpect" Version="2.30.0" />
77
<PackageVersion Include="aweXpect.Core" Version="2.27.0" />
8-
<PackageVersion Include="Mockolate" Version="1.2.0" />
8+
<PackageVersion Include="Mockolate" Version="1.4.0" />
99
</ItemGroup>
1010
<ItemGroup>
1111
<PackageVersion Include="Nullable" Version="1.3.1" />

README.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,22 +85,17 @@ await That(mock.VerifyMock).AllSetupsAreUsed();
8585

8686
#### JSON Content
8787

88-
With `It.IsJsonContent()`, you can precisely verify JSON content in HTTP requests during your tests. This feature is
88+
You can precisely verify JSON content in HTTP requests during your tests. This feature is
8989
especially useful for testing HTTP clients and web APIs.
9090

9191
```csharp
9292
// Verifies that a request was sent with a JSON body equivalent to { "foo": 1, "bar": "baz" }
9393
httpClient.SetupMock.Method
94-
.PostAsync(It.IsAny<Uri>(), It.IsJsonContent().WithBodyMatching(new { foo = 1, bar = \"baz\" }))
94+
.PostAsync(It.IsAny<Uri>(), It.IsHttpContent().WithJsonMatching(new { foo = 1, bar = \"baz\" }))
9595
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
9696

9797
// You can also provide a string representation of the JSON and it ignores formatting differences or property order
9898
httpClient.SetupMock.Method
99-
.PostAsync(It.IsAny<Uri>(), It.IsJsonContent().WithBody("{\"bar\": \"baz\", \"foo\": 1}"))
99+
.PostAsync(It.IsAny<Uri>(), It.IsHttpContent().WithJson("{\"bar\": \"baz\", \"foo\": 1}"))
100100
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));
101-
102-
// In addition, you can specify the expected media type
103-
httpClient.SetupMock.Method
104-
.PostAsync(It.IsAny<Uri>(), It.IsJsonContent("application/json"))
105-
.ReturnsAsync(...);
106101
```

Source/aweXpect.Mockolate/Web/ItExtensions.HttpContent.IsJsonContent.cs

Lines changed: 96 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -15,101 +15,129 @@ namespace Mockolate.Web;
1515
public static class AweXpectItExtensions
1616
{
1717
/// <inheritdoc cref="ItExtensions" />
18-
extension(It _)
18+
extension(ItExtensions.IHttpContentParameter parameter)
1919
{
2020
/// <summary>
21-
/// Expects the <see cref="HttpContent" /> parameter to be a JSON content.
21+
/// Expects the <see cref="HttpContent" /> to have a body equal to the given <paramref name="json" />.
2222
/// </summary>
23-
public static IJsonContentParameter IsJsonContent()
24-
=> new JsonContentParameter();
25-
26-
/// <summary>
27-
/// Expects the <see cref="HttpContent" /> parameter to be a JSON content
28-
/// with the given <paramref name="mediaType" />.
29-
/// </summary>
30-
public static IJsonContentParameter IsJsonContent(string mediaType)
31-
=> new JsonContentParameter().WithMediaType(mediaType);
32-
}
33-
34-
/// <summary>
35-
/// Further expectations on the JSON <see cref="HttpContent" />.
36-
/// </summary>
37-
public interface IJsonContentParameter : ItExtensions.IHttpContentParameter<IJsonContentParameter>
38-
{
39-
/// <summary>
40-
/// Expects the <see cref="StringContent" /> to have a body equal to the given <paramref name="json" />.
41-
/// </summary>
42-
IJsonContentBodyParameter WithBody(string json, JsonDocumentOptions? options = null);
23+
public IJsonContentBodyParameter WithJson(string json, JsonDocumentOptions? options = null)
24+
{
25+
JsonContentParameter jsonContentParameter = new(parameter);
26+
jsonContentParameter.WithBody(json, options);
27+
parameter.WithString(b => jsonContentParameter.Matches(b));
28+
return jsonContentParameter;
29+
}
4330

4431
/// <summary>
45-
/// Expects the <see cref="StringContent" /> to have a JSON body which matches the <paramref name="expected" /> value.
32+
/// Expects the <see cref="HttpContent" /> to have a JSON body which matches the <paramref name="expected" /> value.
4633
/// </summary>
47-
IJsonContentBodyParameter WithBodyMatching(object? expected, JsonDocumentOptions? options = null);
34+
public IJsonContentBodyParameter WithJsonMatching(object? expected, JsonDocumentOptions? options = null)
35+
{
36+
JsonContentParameter jsonContentParameter = new(parameter);
37+
jsonContentParameter.WithBodyMatching(expected, options);
38+
parameter.WithString(b => jsonContentParameter.Matches(b));
39+
return jsonContentParameter;
40+
}
4841

4942
/// <summary>
50-
/// Expects the <see cref="StringContent" /> to have a JSON body which matches the <paramref name="expected" /> value.
43+
/// Expects the <see cref="HttpContent" /> to have a JSON body which matches the <paramref name="expected" /> value.
5144
/// </summary>
52-
IJsonContentBodyParameter WithBodyMatching<T>(IEnumerable<T> expected, JsonDocumentOptions? options = null);
45+
public IJsonContentBodyParameter WithJsonMatching<T>(IEnumerable<T> expected,
46+
JsonDocumentOptions? options = null)
47+
{
48+
JsonContentParameter jsonContentParameter = new(parameter);
49+
jsonContentParameter.WithBodyMatching(expected, options);
50+
parameter.WithString(b => jsonContentParameter.Matches(b));
51+
return jsonContentParameter;
52+
}
5353
}
5454

5555
/// <summary>
5656
/// Further expectations on the matching of a JSON body of the <see cref="HttpContent" />.
5757
/// </summary>
58-
public interface IJsonContentBodyParameter : IJsonContentParameter
58+
public interface IJsonContentBodyParameter : ItExtensions.IHttpContentParameter
5959
{
6060
/// <summary>
6161
/// Ignores additional properties in JSON objects when comparing.
6262
/// </summary>
6363
IJsonContentBodyParameter IgnoringAdditionalProperties(bool ignoreAdditionalProperties = true);
6464
}
6565

66-
private sealed class JsonContentParameter : HttpContentParameter<IJsonContentParameter>, IJsonContentBodyParameter
66+
private sealed class JsonContentParameter : IJsonContentBodyParameter, IParameter
6767
{
68+
private readonly ItExtensions.IHttpContentParameter _parameter;
69+
6870
private string? _body;
6971
private bool _ignoringAdditionalProperties = true;
7072
private JsonDocumentOptions? _jsonDocumentOptions;
7173

72-
/// <inheritdoc cref="HttpContentParameter{TParameter}.GetThis" />
73-
protected override IJsonContentParameter GetThis => this;
74-
75-
/// <inheritdoc cref="IJsonContentParameter.WithBody(string, JsonDocumentOptions?)" />
76-
public IJsonContentBodyParameter WithBody(string json,
77-
JsonDocumentOptions? options = null)
74+
public JsonContentParameter(ItExtensions.IHttpContentParameter parameter)
7875
{
79-
_body = json;
80-
_jsonDocumentOptions = options;
81-
return this;
76+
_parameter = parameter;
8277
}
8378

84-
/// <inheritdoc cref="IJsonContentParameter.WithBodyMatching(object, JsonDocumentOptions?)" />
85-
public IJsonContentBodyParameter WithBodyMatching(object? expected,
86-
JsonDocumentOptions? options = null)
87-
=> WithBody(JsonSerializer.Serialize(expected, JsonSerializerOptions.Default), options);
88-
89-
public IJsonContentBodyParameter WithBodyMatching<T>(IEnumerable<T> expected,
90-
JsonDocumentOptions? options = null)
91-
=> WithBody(JsonSerializer.Serialize<object>(expected, JsonSerializerOptions.Default), options);
92-
9379
/// <inheritdoc cref="IJsonContentBodyParameter.IgnoringAdditionalProperties(bool)" />
9480
public IJsonContentBodyParameter IgnoringAdditionalProperties(bool ignoreAdditionalProperties = true)
9581
{
9682
_ignoringAdditionalProperties = ignoreAdditionalProperties;
9783
return this;
9884
}
9985

100-
protected override bool Matches(HttpContent value)
101-
{
102-
if (!base.Matches(value))
103-
{
104-
return false;
105-
}
86+
public IParameter<HttpContent?> Do(Action<HttpContent?> callback)
87+
=> _parameter.Do(callback);
88+
89+
public ItExtensions.IHttpContentHeaderParameter WithHeaders(
90+
params IEnumerable<(string Name, HttpHeaderValue Value)> headers)
91+
=> _parameter.WithHeaders(headers);
92+
93+
public ItExtensions.IHttpContentHeaderParameter WithHeaders(string headers)
94+
=> _parameter.WithHeaders(headers);
95+
96+
public ItExtensions.IHttpContentHeaderParameter WithHeaders(string name, HttpHeaderValue value)
97+
=> _parameter.WithHeaders(name, value);
98+
99+
public ItExtensions.IHttpContentParameter WithString(Func<string, bool> predicate)
100+
=> _parameter.WithString(predicate);
101+
102+
public ItExtensions.IStringContentBodyParameter WithString(string expected)
103+
=> _parameter.WithString(expected);
104+
105+
public ItExtensions.IStringContentBodyMatchingParameter WithStringMatching(string pattern)
106+
=> _parameter.WithStringMatching(pattern);
107+
108+
public ItExtensions.IHttpContentParameter WithBytes(byte[] bytes)
109+
=> _parameter.WithBytes(bytes);
110+
111+
public ItExtensions.IHttpContentParameter WithBytes(Func<byte[], bool> predicate)
112+
=> _parameter.WithBytes(predicate);
113+
114+
public ItExtensions.IFormDataContentParameter WithFormData(string key, HttpFormDataValue value)
115+
=> _parameter.WithFormData(key, value);
116+
117+
public ItExtensions.IFormDataContentParameter WithFormData(
118+
params IEnumerable<(string Key, HttpFormDataValue Value)> values)
119+
=> _parameter.WithFormData(values);
120+
121+
public ItExtensions.IFormDataContentParameter WithFormData(string values)
122+
=> _parameter.WithFormData(values);
123+
124+
public ItExtensions.IHttpContentParameter WithMediaType(string? mediaType)
125+
=> _parameter.WithMediaType(mediaType);
126+
127+
public void InvokeCallbacks(object? value)
128+
=> ((IParameter)_parameter).InvokeCallbacks(value);
106129

130+
public bool Matches(object? value)
131+
=> ((IParameter)_parameter).Matches(value);
132+
133+
public bool Matches(string value)
134+
{
107135
if (_body is not null)
108136
{
109137
try
110138
{
111139
JsonDocumentOptions options = _jsonDocumentOptions ?? GetDefaultOptions();
112-
using JsonDocument actualDocument = JsonDocument.Parse(value.ReadAsStream(), options);
140+
using JsonDocument actualDocument = JsonDocument.Parse(value, options);
113141
using JsonDocument expectedDocument = JsonDocument.Parse(_body, options);
114142

115143
if (!Compare(actualDocument.RootElement, expectedDocument.RootElement,
@@ -127,6 +155,21 @@ protected override bool Matches(HttpContent value)
127155
return true;
128156
}
129157

158+
public void WithBody(string json,
159+
JsonDocumentOptions? options = null)
160+
{
161+
_body = json;
162+
_jsonDocumentOptions = options;
163+
}
164+
165+
public void WithBodyMatching(object? expected,
166+
JsonDocumentOptions? options = null)
167+
=> WithBody(JsonSerializer.Serialize(expected, JsonSerializerOptions.Default), options);
168+
169+
public void WithBodyMatching<T>(IEnumerable<T> expected,
170+
JsonDocumentOptions? options = null)
171+
=> WithBody(JsonSerializer.Serialize<object>(expected, JsonSerializerOptions.Default), options);
172+
130173
private static JsonDocumentOptions GetDefaultOptions() => new()
131174
{
132175
AllowTrailingCommas = true,
@@ -225,60 +268,6 @@ private static bool CompareJsonNumber(JsonElement actualElement, JsonElement exp
225268
return false;
226269
}
227270
}
228-
229-
private abstract class HttpContentParameter<TParameter>
230-
: ItExtensions.IHttpContentParameter<TParameter>, IParameter
231-
{
232-
private List<Action<HttpContent?>>? _callbacks;
233-
private string? _mediaType;
234-
235-
/// <summary>
236-
/// Returns <c>this</c> typed as <typeparamref name="TParameter" /> for fluent API.
237-
/// </summary>
238-
protected abstract TParameter GetThis { get; }
239-
240-
/// <inheritdoc cref="ItExtensions.IHttpContentParameter{TParameter}.WithMediaType(string?)" />
241-
public TParameter WithMediaType(string? mediaType)
242-
{
243-
_mediaType = mediaType;
244-
return GetThis;
245-
}
246-
247-
/// <inheritdoc cref="IParameter{T}.Do(Action{T})" />
248-
public IParameter<HttpContent?> Do(Action<HttpContent?> callback)
249-
{
250-
_callbacks ??= [];
251-
_callbacks.Add(callback);
252-
return this;
253-
}
254-
255-
/// <inheritdoc cref="IParameter.Matches(object?)" />
256-
public bool Matches(object? value)
257-
=> value is HttpContent typedValue && Matches(typedValue);
258-
259-
/// <inheritdoc cref="IParameter.InvokeCallbacks(object?)" />
260-
public void InvokeCallbacks(object? value)
261-
{
262-
if (value is HttpContent httpContent)
263-
{
264-
_callbacks?.ForEach(a => a.Invoke(httpContent));
265-
}
266-
}
267-
268-
/// <summary>
269-
/// Checks whether the given <see cref="HttpContent" /> <paramref name="value" /> matches the expectations.
270-
/// </summary>
271-
protected virtual bool Matches(HttpContent value)
272-
{
273-
if (_mediaType is not null &&
274-
value.Headers.ContentType?.MediaType?.Equals(_mediaType, StringComparison.OrdinalIgnoreCase) != true)
275-
{
276-
return false;
277-
}
278-
279-
return true;
280-
}
281-
}
282271
}
283272
#pragma warning restore S2325 // Methods and properties that don't access instance data should be static
284273
#endif

Tests/aweXpect.Mockolate.Api.Tests/Expected/aweXpect.Mockolate_net10.0.txt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,15 @@ namespace Mockolate.Web
44
{
55
public static class AweXpectItExtensions
66
{
7-
public interface IJsonContentBodyParameter : Mockolate.Parameters.IParameter<System.Net.Http.HttpContent?>, Mockolate.Web.AweXpectItExtensions.IJsonContentParameter, Mockolate.Web.ItExtensions.IHttpContentParameter<Mockolate.Web.AweXpectItExtensions.IJsonContentParameter>
7+
public interface IJsonContentBodyParameter : Mockolate.Parameters.IParameter<System.Net.Http.HttpContent?>, Mockolate.Web.ItExtensions.IHttpContentParameter, Mockolate.Web.ItExtensions.IHttpHeaderParameter<Mockolate.Web.ItExtensions.IHttpContentHeaderParameter>
88
{
99
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter IgnoringAdditionalProperties(bool ignoreAdditionalProperties = true);
1010
}
11-
public interface IJsonContentParameter : Mockolate.Parameters.IParameter<System.Net.Http.HttpContent?>, Mockolate.Web.ItExtensions.IHttpContentParameter<Mockolate.Web.AweXpectItExtensions.IJsonContentParameter>
11+
extension(Mockolate.Web.ItExtensions.IHttpContentParameter parameter)
1212
{
13-
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithBody(string json, System.Text.Json.JsonDocumentOptions? options = default);
14-
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithBodyMatching(object? expected, System.Text.Json.JsonDocumentOptions? options = default);
15-
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithBodyMatching<T>(System.Collections.Generic.IEnumerable<T> expected, System.Text.Json.JsonDocumentOptions? options = default);
16-
}
17-
extension(Mockolate.It _)
18-
{
19-
Mockolate.Web.AweXpectItExtensions.IJsonContentParameter IsJsonContent();
20-
Mockolate.Web.AweXpectItExtensions.IJsonContentParameter IsJsonContent(string mediaType);
13+
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithJson(string json, System.Text.Json.JsonDocumentOptions? options = default);
14+
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithJsonMatching(object? expected, System.Text.Json.JsonDocumentOptions? options = default);
15+
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithJsonMatching<T>(System.Collections.Generic.IEnumerable<T> expected, System.Text.Json.JsonDocumentOptions? options = default);
2116
}
2217
}
2318
}

Tests/aweXpect.Mockolate.Api.Tests/Expected/aweXpect.Mockolate_net8.0.txt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,15 @@ namespace Mockolate.Web
44
{
55
public static class AweXpectItExtensions
66
{
7-
public interface IJsonContentBodyParameter : Mockolate.Parameters.IParameter<System.Net.Http.HttpContent?>, Mockolate.Web.AweXpectItExtensions.IJsonContentParameter, Mockolate.Web.ItExtensions.IHttpContentParameter<Mockolate.Web.AweXpectItExtensions.IJsonContentParameter>
7+
public interface IJsonContentBodyParameter : Mockolate.Parameters.IParameter<System.Net.Http.HttpContent?>, Mockolate.Web.ItExtensions.IHttpContentParameter, Mockolate.Web.ItExtensions.IHttpHeaderParameter<Mockolate.Web.ItExtensions.IHttpContentHeaderParameter>
88
{
99
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter IgnoringAdditionalProperties(bool ignoreAdditionalProperties = true);
1010
}
11-
public interface IJsonContentParameter : Mockolate.Parameters.IParameter<System.Net.Http.HttpContent?>, Mockolate.Web.ItExtensions.IHttpContentParameter<Mockolate.Web.AweXpectItExtensions.IJsonContentParameter>
11+
extension(Mockolate.Web.ItExtensions.IHttpContentParameter parameter)
1212
{
13-
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithBody(string json, System.Text.Json.JsonDocumentOptions? options = default);
14-
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithBodyMatching(object? expected, System.Text.Json.JsonDocumentOptions? options = default);
15-
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithBodyMatching<T>(System.Collections.Generic.IEnumerable<T> expected, System.Text.Json.JsonDocumentOptions? options = default);
16-
}
17-
extension(Mockolate.It _)
18-
{
19-
Mockolate.Web.AweXpectItExtensions.IJsonContentParameter IsJsonContent();
20-
Mockolate.Web.AweXpectItExtensions.IJsonContentParameter IsJsonContent(string mediaType);
13+
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithJson(string json, System.Text.Json.JsonDocumentOptions? options = default);
14+
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithJsonMatching(object? expected, System.Text.Json.JsonDocumentOptions? options = default);
15+
Mockolate.Web.AweXpectItExtensions.IJsonContentBodyParameter WithJsonMatching<T>(System.Collections.Generic.IEnumerable<T> expected, System.Text.Json.JsonDocumentOptions? options = default);
2116
}
2217
}
2318
}

0 commit comments

Comments
 (0)