Skip to content

Commit daa1993

Browse files
committed
tests
1 parent ad172b5 commit daa1993

File tree

11 files changed

+2080
-7
lines changed

11 files changed

+2080
-7
lines changed
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
using System.Collections.Generic;
2+
using FluentAssertions;
3+
using ManagedCode.Communication.Extensions;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Xunit;
6+
7+
namespace ManagedCode.Communication.Tests.Extensions;
8+
9+
public class ProblemExtensionsTests
10+
{
11+
[Fact]
12+
public void ToProblemDetails_ShouldConvertProblemToProblemDetails()
13+
{
14+
// Arrange
15+
var problem = Problem.Create("https://httpstatuses.io/400", "Bad Request", 400, "Invalid input", "/api/users");
16+
problem.Extensions["traceId"] = "12345";
17+
problem.Extensions["timestamp"] = "2024-01-01T00:00:00Z";
18+
19+
// Act
20+
var problemDetails = problem.ToProblemDetails();
21+
22+
// Assert
23+
problemDetails.Should().NotBeNull();
24+
problemDetails.Type.Should().Be("https://httpstatuses.io/400");
25+
problemDetails.Title.Should().Be("Bad Request");
26+
problemDetails.Status.Should().Be(400);
27+
problemDetails.Detail.Should().Be("Invalid input");
28+
problemDetails.Instance.Should().Be("/api/users");
29+
problemDetails.Extensions.Should().ContainKey("traceId");
30+
problemDetails.Extensions["traceId"].Should().Be("12345");
31+
problemDetails.Extensions.Should().ContainKey("timestamp");
32+
problemDetails.Extensions["timestamp"].Should().Be("2024-01-01T00:00:00Z");
33+
}
34+
35+
[Fact]
36+
public void ToProblemDetails_WithZeroStatusCode_ShouldSetStatusToNull()
37+
{
38+
// Arrange
39+
var problem = new Problem
40+
{
41+
Type = "https://example.com/error",
42+
Title = "Error",
43+
StatusCode = 0,
44+
Detail = "Something went wrong"
45+
};
46+
47+
// Act
48+
var problemDetails = problem.ToProblemDetails();
49+
50+
// Assert
51+
problemDetails.Status.Should().BeNull();
52+
}
53+
54+
[Fact]
55+
public void FromProblemDetails_ShouldConvertProblemDetailsToProblem()
56+
{
57+
// Arrange
58+
var problemDetails = new ProblemDetails
59+
{
60+
Type = "https://httpstatuses.io/404",
61+
Title = "Not Found",
62+
Status = 404,
63+
Detail = "Resource not found",
64+
Instance = "/api/items/123"
65+
};
66+
problemDetails.Extensions["correlationId"] = "abc-123";
67+
problemDetails.Extensions["userId"] = 42;
68+
69+
// Act
70+
var problem = ProblemExtensions.FromProblemDetails(problemDetails);
71+
72+
// Assert
73+
problem.Should().NotBeNull();
74+
problem.Type.Should().Be("https://httpstatuses.io/404");
75+
problem.Title.Should().Be("Not Found");
76+
problem.StatusCode.Should().Be(404);
77+
problem.Detail.Should().Be("Resource not found");
78+
problem.Instance.Should().Be("/api/items/123");
79+
problem.Extensions.Should().ContainKey("correlationId");
80+
problem.Extensions["correlationId"].Should().Be("abc-123");
81+
problem.Extensions.Should().ContainKey("userId");
82+
problem.Extensions["userId"].Should().Be(42);
83+
}
84+
85+
[Fact]
86+
public void FromProblemDetails_WithNullStatus_ShouldSetStatusCodeToZero()
87+
{
88+
// Arrange
89+
var problemDetails = new ProblemDetails
90+
{
91+
Type = "https://example.com/error",
92+
Title = "Error",
93+
Status = null,
94+
Detail = "Something went wrong"
95+
};
96+
97+
// Act
98+
var problem = ProblemExtensions.FromProblemDetails(problemDetails);
99+
100+
// Assert
101+
problem.StatusCode.Should().Be(0);
102+
}
103+
104+
[Fact]
105+
public void AsProblemDetails_ShouldConvertProblemToProblemDetails()
106+
{
107+
// Arrange
108+
var problem = Problem.Create("type", "title", 400, "detail");
109+
110+
// Act
111+
var problemDetails = problem.AsProblemDetails();
112+
113+
// Assert
114+
problemDetails.Should().NotBeNull();
115+
problemDetails.Type.Should().Be("type");
116+
problemDetails.Title.Should().Be("title");
117+
problemDetails.Status.Should().Be(400);
118+
problemDetails.Detail.Should().Be("detail");
119+
}
120+
121+
[Fact]
122+
public void AsProblem_ShouldConvertProblemDetailsToProblem()
123+
{
124+
// Arrange
125+
var problemDetails = new ProblemDetails
126+
{
127+
Type = "type",
128+
Title = "title",
129+
Status = 500,
130+
Detail = "detail"
131+
};
132+
133+
// Act
134+
var problem = problemDetails.AsProblem();
135+
136+
// Assert
137+
problem.Should().NotBeNull();
138+
problem.Type.Should().Be("type");
139+
problem.Title.Should().Be("title");
140+
problem.StatusCode.Should().Be(500);
141+
problem.Detail.Should().Be("detail");
142+
}
143+
144+
[Fact]
145+
public void ToFailedResult_FromProblemDetails_ShouldCreateFailedResult()
146+
{
147+
// Arrange
148+
var problemDetails = new ProblemDetails
149+
{
150+
Type = "https://httpstatuses.io/400",
151+
Title = "Validation Error",
152+
Status = 400,
153+
Detail = "Invalid input data"
154+
};
155+
156+
// Act
157+
var result = problemDetails.ToFailedResult();
158+
159+
// Assert
160+
result.IsFailed.Should().BeTrue();
161+
result.IsSuccess.Should().BeFalse();
162+
result.Problem.Should().NotBeNull();
163+
result.Problem!.Type.Should().Be("https://httpstatuses.io/400");
164+
result.Problem.Title.Should().Be("Validation Error");
165+
result.Problem.StatusCode.Should().Be(400);
166+
result.Problem.Detail.Should().Be("Invalid input data");
167+
}
168+
169+
[Fact]
170+
public void ToFailedResultT_FromProblemDetails_ShouldCreateFailedResultT()
171+
{
172+
// Arrange
173+
var problemDetails = new ProblemDetails
174+
{
175+
Type = "https://httpstatuses.io/404",
176+
Title = "Not Found",
177+
Status = 404,
178+
Detail = "User not found"
179+
};
180+
181+
// Act
182+
var result = problemDetails.ToFailedResult<string>();
183+
184+
// Assert
185+
result.IsFailed.Should().BeTrue();
186+
result.IsSuccess.Should().BeFalse();
187+
result.Value.Should().BeNull();
188+
result.Problem.Should().NotBeNull();
189+
result.Problem!.Type.Should().Be("https://httpstatuses.io/404");
190+
result.Problem.Title.Should().Be("Not Found");
191+
result.Problem.StatusCode.Should().Be(404);
192+
result.Problem.Detail.Should().Be("User not found");
193+
}
194+
195+
[Fact]
196+
public void ToFailedResult_FromProblem_ShouldCreateFailedResult()
197+
{
198+
// Arrange
199+
var problem = Problem.Create("https://httpstatuses.io/500", "Server Error", 500, "Internal error occurred");
200+
201+
// Act
202+
var result = problem.ToFailedResult();
203+
204+
// Assert
205+
result.IsFailed.Should().BeTrue();
206+
result.IsSuccess.Should().BeFalse();
207+
result.Problem.Should().Be(problem);
208+
}
209+
210+
[Fact]
211+
public void ToFailedResultT_FromProblem_ShouldCreateFailedResultT()
212+
{
213+
// Arrange
214+
var problem = Problem.Create("https://httpstatuses.io/403", "Forbidden", 403, "Access denied");
215+
216+
// Act
217+
var result = problem.ToFailedResult<int>();
218+
219+
// Assert
220+
result.IsFailed.Should().BeTrue();
221+
result.IsSuccess.Should().BeFalse();
222+
result.Value.Should().Be(default(int));
223+
result.Problem.Should().Be(problem);
224+
}
225+
226+
[Fact]
227+
public void RoundTrip_ProblemToProblemDetailsAndBack_ShouldPreserveAllData()
228+
{
229+
// Arrange
230+
var originalProblem = Problem.Create("https://httpstatuses.io/409", "Conflict", 409, "Resource conflict", "/api/resource/123");
231+
originalProblem.Extensions["error_code"] = "RESOURCE_LOCKED";
232+
originalProblem.Extensions["retry_after"] = 30;
233+
originalProblem.Extensions["nested"] = new Dictionary<string, object> { ["key"] = "value" };
234+
235+
// Act
236+
var problemDetails = originalProblem.ToProblemDetails();
237+
var convertedProblem = problemDetails.AsProblem();
238+
239+
// Assert
240+
convertedProblem.Type.Should().Be(originalProblem.Type);
241+
convertedProblem.Title.Should().Be(originalProblem.Title);
242+
convertedProblem.StatusCode.Should().Be(originalProblem.StatusCode);
243+
convertedProblem.Detail.Should().Be(originalProblem.Detail);
244+
convertedProblem.Instance.Should().Be(originalProblem.Instance);
245+
convertedProblem.Extensions.Should().BeEquivalentTo(originalProblem.Extensions);
246+
}
247+
248+
[Fact]
249+
public void RoundTrip_ProblemDetailsWithNullValues_ShouldHandleGracefully()
250+
{
251+
// Arrange
252+
var problemDetails = new ProblemDetails
253+
{
254+
Type = null,
255+
Title = null,
256+
Status = null,
257+
Detail = null,
258+
Instance = null
259+
};
260+
261+
// Act
262+
var problem = problemDetails.AsProblem();
263+
var convertedProblemDetails = problem.AsProblemDetails();
264+
265+
// Assert
266+
problem.Type.Should().BeNull();
267+
problem.Title.Should().BeNull();
268+
problem.StatusCode.Should().Be(0);
269+
problem.Detail.Should().BeNull();
270+
problem.Instance.Should().BeNull();
271+
272+
convertedProblemDetails.Type.Should().BeNull();
273+
convertedProblemDetails.Title.Should().BeNull();
274+
convertedProblemDetails.Status.Should().BeNull();
275+
convertedProblemDetails.Detail.Should().BeNull();
276+
convertedProblemDetails.Instance.Should().BeNull();
277+
}
278+
279+
[Fact]
280+
public void ToFailedResult_WithComplexExtensions_ShouldPreserveAllData()
281+
{
282+
// Arrange
283+
var problemDetails = new ProblemDetails
284+
{
285+
Type = "https://httpstatuses.io/422",
286+
Title = "Unprocessable Entity",
287+
Status = 422,
288+
Detail = "Validation failed"
289+
};
290+
problemDetails.Extensions["errors"] = new Dictionary<string, List<string>>
291+
{
292+
["email"] = new List<string> { "Invalid format", "Already exists" },
293+
["password"] = new List<string> { "Too short" }
294+
};
295+
296+
// Act
297+
var result = problemDetails.ToFailedResult();
298+
299+
// Assert
300+
result.Problem!.Extensions.Should().ContainKey("errors");
301+
var errors = result.Problem.Extensions["errors"] as Dictionary<string, List<string>>;
302+
errors.Should().NotBeNull();
303+
errors!["email"].Should().Contain("Invalid format");
304+
errors["email"].Should().Contain("Already exists");
305+
errors["password"].Should().Contain("Too short");
306+
}
307+
}

0 commit comments

Comments
 (0)