Skip to content

Commit 89e549a

Browse files
committed
Replace Method, RequestUri and Version with non-nullable variants
1 parent 7313d3e commit 89e549a

6 files changed

Lines changed: 77 additions & 57 deletions

File tree

src/TestableHttpClient/Request.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
namespace TestableHttpClient;
44

5+
internal record struct Any;
6+
internal readonly struct AnyOr<T>
7+
{
8+
public readonly object? Value { get; }
9+
public AnyOr() => Value = new Any();
10+
public AnyOr(Any value) => Value = value;
11+
public AnyOr(T value) => Value = value;
12+
}
13+
514
internal record struct AnyHeader;
615
internal sealed class HeaderList : Dictionary<string, Value> { }
716
internal readonly struct Headers
@@ -31,9 +40,9 @@ public Request(UriPatternMatchingOptions uriPatternMatchingOptions)
3140

3241
public UriPatternMatchingOptions UriPatternMatchingOptions { get; }
3342

34-
public HttpMethod? Method { get; init; }
35-
public UriPattern? RequestUri { get; init; }
36-
public Version? Version { get; init; }
43+
public AnyOr<HttpMethod> Method { get; init; } = new();
44+
public UriPattern RequestUri { get; init; } = new();
45+
public AnyOr<Version> Version { get; init; } = new();
3746

3847
public Headers Headers { get; init; } = new();
3948

@@ -69,17 +78,31 @@ public bool Equals(HttpRequestMessage? other)
6978
return false;
7079
}
7180

72-
if (Method is not null && other.Method != Method)
81+
bool methodMatches = Method.Value switch
82+
{
83+
Any => true,
84+
HttpMethod value => other.Method == value,
85+
_ => throw new UnreachableException()
86+
};
87+
88+
if (!methodMatches)
7389
{
7490
return false;
7591
}
7692

77-
if (RequestUri is not null && other.RequestUri is not null && !RequestUri.Matches(other.RequestUri, UriPatternMatchingOptions))
93+
if (other.RequestUri is not null && !RequestUri.Matches(other.RequestUri, UriPatternMatchingOptions))
7894
{
7995
return false;
8096
}
8197

82-
if (Version is not null && other.Version != Version)
98+
bool versionMatches = Version.Value switch
99+
{
100+
Any => true,
101+
Version value => other.Version == value,
102+
_ => throw new UnreachableException()
103+
};
104+
105+
if (!versionMatches)
83106
{
84107
return false;
85108
}

src/TestableHttpClient/RequestBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public RequestBuilder WithMethod(HttpMethod httpMethod)
2424
{
2525
Guard.ThrowIfNull(httpMethod);
2626

27-
request = request with { Method = httpMethod };
27+
request = request with { Method = new(httpMethod) };
2828
return this;
2929
}
3030

@@ -50,7 +50,7 @@ public RequestBuilder WithVersion(Version httpVersion)
5050
{
5151
Guard.ThrowIfNull(httpVersion);
5252

53-
request = request with { Version = httpVersion };
53+
request = request with { Version = new(httpVersion) };
5454
return this;
5555
}
5656

src/TestableHttpClient/Utils/MessageBuilder.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ internal static string BuildMessage(int? expectedCount, int actualCount, Request
1212
null => actualCount > 0,
1313
_ => expectedCount == actualCount
1414
};
15-
var method = expectedRequest.Method switch
15+
var method = expectedRequest.Method.Value switch
1616
{
17-
null => "",
18-
_ => $"{expectedRequest.Method} "
17+
Any => "",
18+
HttpMethod httpMethod => $"{httpMethod} ",
19+
_ => throw new UnreachableException()
1920
};
2021

2122
var expectedMessage = expectedCount switch
@@ -26,11 +27,7 @@ internal static string BuildMessage(int? expectedCount, int actualCount, Request
2627
_ => $"{expectedCount} {method}requests"
2728
};
2829

29-
var requestUri = expectedRequest.RequestUri switch
30-
{
31-
null => "",
32-
_ => BuildRequestUri(expectedRequest.RequestUri)
33-
};
30+
var requestUri = BuildRequestUri(expectedRequest.RequestUri);
3431

3532
var headers = expectedRequest.Headers.Value switch
3633
{

test/TestableHttpClient.Tests/RequestBuilderExtensionsTests.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ public void Get_ShouldSetHttpMethodAndRequestUri()
2626
{
2727
Request request = sut.Get("https://localhost").Build();
2828

29-
Assert.Equal(HttpMethod.Get, request.Method);
29+
Assert.Equal(HttpMethod.Get, request.Method.Value);
3030
Assert.Equal(UriPatternParser.Parse("https://localhost"), request.RequestUri);
31-
Assert.Null(request.Version);
31+
Assert.Equal(new Any(), request.Version.Value);
3232
Assert.Equal(new AnyHeader(), request.Headers.Value);
3333
Assert.Equal(new AnyContent(), request.Content.Value);
3434
}
@@ -57,9 +57,9 @@ public void Post_ShouldBuildCorrectRequest()
5757
{
5858
Request request = sut.Post("https://localhost", "{\"hello\":1}").Build();
5959

60-
Assert.Equal(HttpMethod.Post, request.Method);
60+
Assert.Equal(HttpMethod.Post, request.Method.Value);
6161
Assert.Equal(UriPatternParser.Parse("https://localhost"), request.RequestUri);
62-
Assert.Null(request.Version);
62+
Assert.Equal(new Any(), request.Version.Value);
6363
Assert.Equal(new AnyHeader(), request.Headers.Value);
6464
Assert.Equal(new Pattern("{\"hello\":1}"), request.Content.Value);
6565
}
@@ -83,9 +83,9 @@ public void PostAsJson_WithNullContent_ShouldBuildCorrectRequest()
8383
{
8484
Request request = sut.PostAsJson("https://localhost", null).Build();
8585

86-
Assert.Equal(HttpMethod.Post, request.Method);
86+
Assert.Equal(HttpMethod.Post, request.Method.Value);
8787
Assert.Equal(UriPatternParser.Parse("https://localhost"), request.RequestUri);
88-
Assert.Null(request.Version);
88+
Assert.Equal(new Any(), request.Version.Value);
8989
Assert.Equivalent(new Dictionary<string, Value>() { ["Content-Type"] = Value.Pattern("application/json*") }, request.Headers.Value);
9090
Assert.Equal(new Pattern("null"), request.Content.Value);
9191
}
@@ -95,9 +95,9 @@ public void PostAsJson_ShouldBuildCorrectRequest()
9595
{
9696
Request request = sut.PostAsJson("https://localhost", new { hello = 1 }).Build();
9797

98-
Assert.Equal(HttpMethod.Post, request.Method);
98+
Assert.Equal(HttpMethod.Post, request.Method.Value);
9999
Assert.Equal(UriPatternParser.Parse("https://localhost"), request.RequestUri);
100-
Assert.Null(request.Version);
100+
Assert.Equal(new Any(), request.Version.Value);
101101
Assert.Equivalent(new Dictionary<string, Value>() { ["Content-Type"] = Value.Pattern("application/json*") }, request.Headers.Value);
102102
Assert.Equal(new Pattern("{\"hello\":1}"), request.Content.Value);
103103
}
@@ -115,9 +115,9 @@ public void WithJsonContent_WithNullContent_ShouldBuildCorrectRequest()
115115
{
116116
Request request = sut.WithJsonContent(null).Build();
117117

118-
Assert.Null(request.Method);
119-
Assert.Null(request.RequestUri);
120-
Assert.Null(request.Version);
118+
Assert.Equal(new Any(), request.Method.Value);
119+
Assert.Equal(UriPattern.Any, request.RequestUri);
120+
Assert.Equal(new Any(), request.Version.Value);
121121
Assert.Equivalent(new Dictionary<string, Value>() { ["Content-Type"] = Value.Pattern("application/json*") }, request.Headers.Value);
122122
Assert.Equal(new Pattern("null"), request.Content.Value);
123123
}
@@ -127,9 +127,9 @@ public void WithJsonContent_ShouldBuildCorrectRequest()
127127
{
128128
Request request = sut.WithJsonContent(new { hello = 1 }).Build();
129129

130-
Assert.Null(request.Method);
131-
Assert.Null(request.RequestUri);
132-
Assert.Null(request.Version);
130+
Assert.Equal(new Any(), request.Method.Value);
131+
Assert.Equal(UriPattern.Any, request.RequestUri);
132+
Assert.Equal(new Any(), request.Version.Value);
133133
Assert.Equivalent(new Dictionary<string, Value>() { ["Content-Type"] = Value.Pattern("application/json*") }, request.Headers.Value);
134134
Assert.Equal(new Pattern("{\"hello\":1}"), request.Content.Value);
135135
}
@@ -144,9 +144,9 @@ public void WithJsonContent_WithCustomOptions_ShouldBuildCorrectRequest()
144144
};
145145
Request request = sut.WithJsonContent(new { hello = 1 }, options).Build();
146146

147-
Assert.Null(request.Method);
148-
Assert.Null(request.RequestUri);
149-
Assert.Null(request.Version);
147+
Assert.Equal(new Any(), request.Method.Value);
148+
Assert.Equal(UriPattern.Any, request.RequestUri);
149+
Assert.Equal(new Any(), request.Version.Value);
150150
Assert.Equivalent(new Dictionary<string, Value>() { ["Content-Type"] = Value.Pattern("application/json*") }, request.Headers.Value);
151151
Assert.Equal(new Pattern("""
152152
{
@@ -174,9 +174,9 @@ public void WithFormUrlEncodedContent_ShouldBuildCorrectRequest()
174174
{
175175
Request request = sut.WithFormUrlEncodedContent([new KeyValuePair<string?, string?>("username", "alice")]).Build();
176176

177-
Assert.Null(request.Method);
178-
Assert.Null(request.RequestUri);
179-
Assert.Null(request.Version);
177+
Assert.Equal(new Any(), request.Method.Value);
178+
Assert.Equal(UriPattern.Any,request.RequestUri);
179+
Assert.Equal(new Any(), request.Version.Value);
180180
Assert.Equivalent(new Dictionary<string, Value>() { ["Content-Type"] = Value.Pattern("application/x-www-form-urlencoded*") }, request.Headers.Value);
181181
Assert.Equal(new Pattern("username=alice"), request.Content.Value);
182182
}

test/TestableHttpClient.Tests/RequestBuilderTests.cs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ public void Build_ByDefault_CreatesEmptyRequest()
1111
{
1212
Request request = sut.Build();
1313

14-
Assert.Null(request.Method);
15-
Assert.Null(request.RequestUri);
16-
Assert.Null(request.Version);
14+
Assert.Equal(new Any(), request.Method.Value);
15+
Assert.Equal(UriPattern.Any, request.RequestUri);
16+
Assert.Equal(new Any(), request.Version.Value);
1717
Assert.Equal(new AnyHeader(), request.Headers.Value);
1818
Assert.Equal(new AnyContent(), request.Content.Value);
1919
}
@@ -29,9 +29,9 @@ public void WithMethod_CreatesRequestWithMethod()
2929
{
3030
Request request = sut.WithMethod(HttpMethod.Post).Build();
3131

32-
Assert.Equal(HttpMethod.Post, request.Method);
33-
Assert.Null(request.RequestUri);
34-
Assert.Null(request.Version);
32+
Assert.Equal(HttpMethod.Post, request.Method.Value);
33+
Assert.Equal(UriPattern.Any, request.RequestUri);
34+
Assert.Equal(new Any(), request.Version.Value);
3535
Assert.Equal(new AnyHeader(), request.Headers.Value);
3636
Assert.Equal(new AnyContent(), request.Content.Value);
3737
}
@@ -53,9 +53,9 @@ public void WithRequestUri_UriPattern_ShouldSetRequestUri()
5353
{
5454
Request request = sut.WithRequestUri("http*//test.example").Build();
5555

56-
Assert.Null(request.Method);
56+
Assert.Equal(new Any(), request.Method.Value);
5757
Assert.Equal(UriPatternParser.Parse("http*//test.example"), request.RequestUri);
58-
Assert.Null(request.Version);
58+
Assert.Equal(new Any(), request.Version.Value);
5959
Assert.Equal(new AnyHeader(), request.Headers.Value);
6060
Assert.Equal(new AnyContent(), request.Content.Value);
6161
}
@@ -71,9 +71,9 @@ public void WithVersion_CreatesRequestWithVersion()
7171
{
7272
Request request = sut.WithVersion(HttpVersion.Version11).Build();
7373

74-
Assert.Null(request.Method);
75-
Assert.Null(request.RequestUri);
76-
Assert.Equal(HttpVersion.Version11, request.Version);
74+
Assert.Equal(new Any(), request.Method.Value);
75+
Assert.Equal(UriPattern.Any, request.RequestUri);
76+
Assert.Equal(HttpVersion.Version11, request.Version.Value);
7777
Assert.Equal(new AnyHeader(), request.Headers.Value);
7878
Assert.Equal(new AnyContent(), request.Content.Value);
7979
}
@@ -97,9 +97,9 @@ public void WithHeader_ValidHeaderNameNoValue_CreatesRequestWithHeaderWithAnyVal
9797
{
9898
Request request = sut.WithHeader("Content-Length").Build();
9999

100-
Assert.Null(request.Method);
101-
Assert.Null(request.RequestUri);
102-
Assert.Null(request.Version);
100+
Assert.Equal(new Any(), request.Method.Value);
101+
Assert.Equal(UriPattern.Any, request.RequestUri);
102+
Assert.Equal(new Any(), request.Version.Value);
103103
Assert.Equal(new Dictionary<string, Value>() { ["Content-Length"] = Value.Any() }, request.Headers.Value);
104104
Assert.Equal(new AnyContent(), request.Content.Value);
105105
}
@@ -121,9 +121,9 @@ public void WithHeader_ValidHeaderNamePatternValue_CreatesRequestWithHeaderWithA
121121
{
122122
Request request = sut.WithHeader("Content-Length", "*").Build();
123123

124-
Assert.Null(request.Method);
125-
Assert.Null(request.RequestUri);
126-
Assert.Null(request.Version);
124+
Assert.Equal(new Any(), request.Method.Value);
125+
Assert.Equal(UriPattern.Any, request.RequestUri);
126+
Assert.Equal(new Any(), request.Version.Value);
127127
Assert.Equal(new Dictionary<string, Value>() { ["Content-Length"] = Value.Pattern("*") }, request.Headers.Value);
128128
Assert.Equal(new AnyContent(), request.Content.Value);
129129
}
@@ -139,9 +139,9 @@ public void WithContent_CreatesRequestWithContent()
139139
{
140140
Request request = sut.WithContent("content").Build();
141141

142-
Assert.Null(request.Method);
143-
Assert.Null(request.RequestUri);
144-
Assert.Null(request.Version);
142+
Assert.Equal(new Any(), request.Method.Value);
143+
Assert.Equal(UriPattern.Any, request.RequestUri);
144+
Assert.Equal(new Any(), request.Version.Value);
145145
Assert.Equal(new AnyHeader(), request.Headers.Value);
146146
Assert.Equal(new Pattern("content"), request.Content.Value);
147147
}

test/TestableHttpClient.Tests/Utils/MessageBuilderTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void BuildMessage_VariableExpectedCountZeroActualCountRequestSpecifyingMe
5555
{
5656
Request request = new(new())
5757
{
58-
Method = HttpMethod.Get,
58+
Method = new(HttpMethod.Get),
5959
};
6060

6161
var result = MessageBuilder.BuildMessage(expectedCount, 0, request);

0 commit comments

Comments
 (0)