using System; using System.Linq; using System.Net; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Logging.Abstractions; using NetClient.Abstractions; using NetClient.Exceptions; using NetClient.Implementations; using NetClient.Test.TestDoubles; namespace NetClient.Test.Tests; [TestClass] public class NetClientBasicTests { private static DefaultNetClient CreateClient(HttpMessageHandler handler) { var http = new HttpClient(handler) { BaseAddress = new Uri("https://example.com") }; IHttpContentSerializer serializer = new TestJsonSerializer(new JsonSerializerOptions(JsonSerializerDefaults.Web) { PropertyNameCaseInsensitive = true }); var logger = NullLogger.Instance; return new DefaultNetClient(http, serializer, logger); } private sealed record EchoDto(string Method, string Path, string? Query, string? Name); [TestMethod] public async Task GetAsync_Deserializes_And_Builds_Query() { var handler = new TestHttpMessageHandler(req => { Assert.AreEqual(HttpMethod.Get, req.Method); Assert.AreEqual("https://example.com/api/echo", $"{req.RequestUri!.Scheme}://{req.RequestUri.Host}{req.RequestUri.AbsolutePath}"); var q = req.RequestUri!.Query.TrimStart('?').Split('&', StringSplitOptions.RemoveEmptyEntries); CollectionAssert.IsSubsetOf(new[] { "id=1", "name=foo" }, q); var json = $"{{\"method\":\"{req.Method}\",\"path\":\"{req.RequestUri!.AbsolutePath}\",\"query\":\"{req.RequestUri!.Query.TrimStart('?')}\",\"name\":\"foo\"}}"; return Task.FromResult(TestHttpMessageHandler.Json(HttpStatusCode.OK, json)); }); var client = CreateClient(handler); var dto = await client.GetAsync("/api/echo", new { id = 1, name = "foo" }); Assert.IsNotNull(dto); Assert.AreEqual("GET", dto!.Method); Assert.AreEqual("/api/echo", dto.Path); Assert.IsTrue(dto.Query!.Contains("id=1")); Assert.IsTrue(dto.Query!.Contains("name=foo")); Assert.AreEqual("foo", dto.Name); } private sealed record OkDto(bool ok); [TestMethod] public async Task PostAsync_Sends_Json_With_ContentType() { var handler = new TestHttpMessageHandler(async req => { Assert.AreEqual(HttpMethod.Post, req.Method); Assert.AreEqual("application/json", req.Content!.Headers.ContentType!.MediaType); Assert.AreEqual("utf-8", req.Content!.Headers.ContentType!.CharSet?.ToLowerInvariant()); var body = await req.Content!.ReadAsStringAsync(); Assert.IsTrue(body.Contains("\"name\":\"bar\"")); return TestHttpMessageHandler.Json(HttpStatusCode.OK, "{\"ok\":true}"); }); var client = CreateClient(handler); var res = await client.PostAsync("/api/items", new { name = "bar" }); Assert.IsNotNull(res); Assert.AreEqual(true, res!.ok); } [TestMethod] public async Task Error_Throws_ApiException_With_Content() { var handler = new TestHttpMessageHandler(req => Task.FromResult(TestHttpMessageHandler.Text(HttpStatusCode.InternalServerError, "oops"))); var client = CreateClient(handler); try { await client.GetAsync("/api/error"); Assert.Fail("Expected ApiException"); } catch (ApiException ex) { Assert.AreEqual(HttpStatusCode.InternalServerError, ex.StatusCode); StringAssert.Contains(ex.ResponseContent ?? string.Empty, "oops"); } } }