Skip to content

Commit 5e99780

Browse files
authored
Merge pull request #61 from danilolutz/feat/project-enhancement
feat: project general enhancement
2 parents 294d462 + a2ec432 commit 5e99780

File tree

23 files changed

+2251
-913
lines changed

23 files changed

+2251
-913
lines changed
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
using CoreZipCode.Interfaces;
2+
using Moq;
3+
using Moq.Protected;
4+
using System;
5+
using System.Net;
6+
using System.Net.Http;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Xunit;
10+
11+
namespace CoreZipCode.Tests.Interfaces
12+
{
13+
public class ApiHandlerTest
14+
{
15+
[Fact]
16+
public void Constructor_Without_Parameters_Should_Create_Instance()
17+
{
18+
var handler = new ApiHandler();
19+
20+
Assert.NotNull(handler);
21+
}
22+
23+
[Fact]
24+
public void Constructor_With_HttpClient_Should_Create_Instance()
25+
{
26+
var httpClient = new HttpClient();
27+
28+
var handler = new ApiHandler(httpClient);
29+
30+
Assert.NotNull(handler);
31+
}
32+
33+
[Fact]
34+
public void Constructor_With_Null_HttpClient_Should_Throw_ArgumentNullException()
35+
{
36+
Assert.Throws<ArgumentNullException>(() => new ApiHandler(null));
37+
}
38+
39+
[Fact]
40+
public async Task CallApiAsync_With_Null_Url_Should_Return_BadRequest()
41+
{
42+
var handler = new ApiHandler();
43+
44+
var result = await handler.CallApiAsync(null);
45+
46+
Assert.True(result.IsFailure);
47+
Assert.Equal(HttpStatusCode.BadRequest, result.Error.StatusCode);
48+
Assert.Equal("URL cannot be null or empty.", result.Error.Message);
49+
}
50+
51+
[Fact]
52+
public async Task CallApiAsync_With_Empty_Url_Should_Return_BadRequest()
53+
{
54+
var handler = new ApiHandler();
55+
56+
var result = await handler.CallApiAsync(string.Empty);
57+
58+
Assert.True(result.IsFailure);
59+
Assert.Equal(HttpStatusCode.BadRequest, result.Error.StatusCode);
60+
Assert.Equal("URL cannot be null or empty.", result.Error.Message);
61+
}
62+
63+
[Fact]
64+
public async Task CallApiAsync_With_Whitespace_Url_Should_Return_BadRequest()
65+
{
66+
var handler = new ApiHandler();
67+
68+
var result = await handler.CallApiAsync(" ");
69+
70+
Assert.True(result.IsFailure);
71+
Assert.Equal(HttpStatusCode.BadRequest, result.Error.StatusCode);
72+
Assert.Equal("URL cannot be null or empty.", result.Error.Message);
73+
}
74+
75+
[Fact]
76+
public async Task CallApiAsync_With_Success_Response_Should_Return_Success()
77+
{
78+
var expectedBody = "{\"data\":\"test\"}";
79+
var handlerMock = new Mock<HttpMessageHandler>();
80+
handlerMock
81+
.Protected()
82+
.Setup<Task<HttpResponseMessage>>(
83+
"SendAsync",
84+
ItExpr.IsAny<HttpRequestMessage>(),
85+
ItExpr.IsAny<CancellationToken>()
86+
)
87+
.ReturnsAsync(new HttpResponseMessage
88+
{
89+
StatusCode = HttpStatusCode.OK,
90+
Content = new StringContent(expectedBody)
91+
});
92+
var httpClient = new HttpClient(handlerMock.Object);
93+
var handler = new ApiHandler(httpClient);
94+
95+
var result = await handler.CallApiAsync("https://test.com");
96+
97+
Assert.True(result.IsSuccess);
98+
Assert.Equal(expectedBody, result.Value);
99+
}
100+
101+
[Fact]
102+
public async Task CallApiAsync_With_NonSuccess_Response_Should_Return_Failure()
103+
{
104+
var responseBody = "{\"error\":\"not found\"}";
105+
var handlerMock = new Mock<HttpMessageHandler>();
106+
handlerMock
107+
.Protected()
108+
.Setup<Task<HttpResponseMessage>>(
109+
"SendAsync",
110+
ItExpr.IsAny<HttpRequestMessage>(),
111+
ItExpr.IsAny<CancellationToken>()
112+
)
113+
.ReturnsAsync(new HttpResponseMessage
114+
{
115+
StatusCode = HttpStatusCode.NotFound,
116+
ReasonPhrase = "Not Found",
117+
Content = new StringContent(responseBody)
118+
});
119+
var httpClient = new HttpClient(handlerMock.Object);
120+
var handler = new ApiHandler(httpClient);
121+
122+
var result = await handler.CallApiAsync("https://test.com");
123+
124+
Assert.True(result.IsFailure);
125+
Assert.Equal(HttpStatusCode.NotFound, result.Error.StatusCode);
126+
Assert.Contains("404", result.Error.Message);
127+
Assert.Contains("NotFound", result.Error.Message);
128+
Assert.Equal(responseBody, result.Error.ResponseBody);
129+
}
130+
131+
[Fact]
132+
public async Task CallApiAsync_With_HttpRequestException_Should_Return_ServiceUnavailable()
133+
{
134+
var handlerMock = new Mock<HttpMessageHandler>();
135+
handlerMock
136+
.Protected()
137+
.Setup<Task<HttpResponseMessage>>(
138+
"SendAsync",
139+
ItExpr.IsAny<HttpRequestMessage>(),
140+
ItExpr.IsAny<CancellationToken>()
141+
)
142+
.ThrowsAsync(new HttpRequestException("Connection failed"));
143+
var httpClient = new HttpClient(handlerMock.Object);
144+
var handler = new ApiHandler(httpClient);
145+
146+
var result = await handler.CallApiAsync("https://test.com");
147+
148+
Assert.True(result.IsFailure);
149+
Assert.Equal(HttpStatusCode.ServiceUnavailable, result.Error.StatusCode);
150+
Assert.Equal("Network or connection error.", result.Error.Message);
151+
}
152+
153+
[Fact]
154+
public async Task CallApiAsync_With_TaskCanceledException_Should_Return_RequestTimeout()
155+
{
156+
var handlerMock = new Mock<HttpMessageHandler>();
157+
handlerMock
158+
.Protected()
159+
.Setup<Task<HttpResponseMessage>>(
160+
"SendAsync",
161+
ItExpr.IsAny<HttpRequestMessage>(),
162+
ItExpr.IsAny<CancellationToken>()
163+
)
164+
.ThrowsAsync(new TaskCanceledException("The request timed out"));
165+
var httpClient = new HttpClient(handlerMock.Object);
166+
var handler = new ApiHandler(httpClient);
167+
168+
var result = await handler.CallApiAsync("https://test.com");
169+
170+
Assert.True(result.IsFailure);
171+
Assert.Equal(HttpStatusCode.RequestTimeout, result.Error.StatusCode);
172+
Assert.Equal("Request timed out.", result.Error.Message);
173+
}
174+
175+
[Fact]
176+
public async Task CallApiAsync_With_OperationCanceledException_Should_Return_BadRequest()
177+
{
178+
var handlerMock = new Mock<HttpMessageHandler>();
179+
handlerMock
180+
.Protected()
181+
.Setup<Task<HttpResponseMessage>>(
182+
"SendAsync",
183+
ItExpr.IsAny<HttpRequestMessage>(),
184+
ItExpr.IsAny<CancellationToken>()
185+
)
186+
.ThrowsAsync(new OperationCanceledException("Operation was cancelled"));
187+
var httpClient = new HttpClient(handlerMock.Object);
188+
var handler = new ApiHandler(httpClient);
189+
190+
var result = await handler.CallApiAsync("https://test.com");
191+
192+
Assert.True(result.IsFailure);
193+
Assert.Equal(HttpStatusCode.BadRequest, result.Error.StatusCode);
194+
Assert.Equal("Request was cancelled.", result.Error.Message);
195+
}
196+
197+
[Fact]
198+
public async Task CallApiAsync_With_Generic_Exception_Should_Return_InternalServerError()
199+
{
200+
var handlerMock = new Mock<HttpMessageHandler>();
201+
handlerMock
202+
.Protected()
203+
.Setup<Task<HttpResponseMessage>>(
204+
"SendAsync",
205+
ItExpr.IsAny<HttpRequestMessage>(),
206+
ItExpr.IsAny<CancellationToken>()
207+
)
208+
.ThrowsAsync(new InvalidOperationException("Something went wrong"));
209+
var httpClient = new HttpClient(handlerMock.Object);
210+
var handler = new ApiHandler(httpClient);
211+
212+
var result = await handler.CallApiAsync("https://test.com");
213+
214+
Assert.True(result.IsFailure);
215+
Assert.Equal(HttpStatusCode.InternalServerError, result.Error.StatusCode);
216+
Assert.Equal("Unexpected error.", result.Error.Message);
217+
}
218+
219+
[Fact]
220+
public async Task CallApiAsync_With_Multiple_Success_Codes_Should_Return_Success()
221+
{
222+
var testCases = new[]
223+
{
224+
HttpStatusCode.OK,
225+
HttpStatusCode.Created,
226+
HttpStatusCode.Accepted,
227+
HttpStatusCode.NoContent
228+
};
229+
230+
foreach (var statusCode in testCases)
231+
{
232+
var handlerMock = new Mock<HttpMessageHandler>();
233+
handlerMock
234+
.Protected()
235+
.Setup<Task<HttpResponseMessage>>(
236+
"SendAsync",
237+
ItExpr.IsAny<HttpRequestMessage>(),
238+
ItExpr.IsAny<CancellationToken>()
239+
)
240+
.ReturnsAsync(new HttpResponseMessage
241+
{
242+
StatusCode = statusCode,
243+
Content = new StringContent("success")
244+
});
245+
var httpClient = new HttpClient(handlerMock.Object);
246+
var handler = new ApiHandler(httpClient);
247+
248+
var result = await handler.CallApiAsync("https://test.com");
249+
250+
Assert.True(result.IsSuccess);
251+
}
252+
}
253+
254+
[Fact]
255+
public async Task CallApiAsync_With_Multiple_Error_Codes_Should_Return_Failure()
256+
{
257+
var testCases = new[]
258+
{
259+
HttpStatusCode.BadRequest,
260+
HttpStatusCode.Unauthorized,
261+
HttpStatusCode.Forbidden,
262+
HttpStatusCode.NotFound,
263+
HttpStatusCode.InternalServerError,
264+
HttpStatusCode.BadGateway,
265+
HttpStatusCode.ServiceUnavailable
266+
};
267+
268+
foreach (var statusCode in testCases)
269+
{
270+
var handlerMock = new Mock<HttpMessageHandler>();
271+
handlerMock
272+
.Protected()
273+
.Setup<Task<HttpResponseMessage>>(
274+
"SendAsync",
275+
ItExpr.IsAny<HttpRequestMessage>(),
276+
ItExpr.IsAny<CancellationToken>()
277+
)
278+
.ReturnsAsync(new HttpResponseMessage
279+
{
280+
StatusCode = statusCode,
281+
Content = new StringContent("error")
282+
});
283+
var httpClient = new HttpClient(handlerMock.Object);
284+
var handler = new ApiHandler(httpClient);
285+
286+
var result = await handler.CallApiAsync("https://test.com");
287+
288+
Assert.True(result.IsFailure);
289+
Assert.Equal(statusCode, result.Error.StatusCode);
290+
}
291+
}
292+
}
293+
}

0 commit comments

Comments
 (0)