using System.Net; using System.Text.Json; using Moq; using Moq.Protected; using XafPet.Desktop.PetEngine; using Xunit; namespace XafPet.Desktop.Tests; public class ApiClientTests { private static ApiClient CreateClientWithResponse(HttpStatusCode code, string json, string authToken = "test-token") { var handler = new Mock(); handler.Protected() .Setup>("SendAsync", ItExpr.IsAny(), ItExpr.IsAny()) .ReturnsAsync(new HttpResponseMessage(code) { Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json") }); var http = new HttpClient(handler.Object); return new ApiClient(http, "http://localhost:9082", authToken); } [Fact] public async Task GetTodayTasks_ReturnsTaskList() { var json = """ { "code": 200, "message": "ok", "data": [ { "id": 1, "title": "喝水", "status": "PENDING", "dueDate": "2026-10-10" } ] } """; var client = CreateClientWithResponse(HttpStatusCode.OK, json); var tasks = await client.GetTodayTasksAsync(); Assert.Single(tasks); Assert.Equal("喝水", tasks[0].Title); Assert.Equal("PENDING", tasks[0].Status); } [Fact] public async Task GetEnergyOverview_ReturnsDimensions() { var json = """ { "code": 200, "message": "ok", "data": { "dimensions": [ { "dimension": "身", "value": 80, "color": "#FF8C42" }, { "dimension": "智", "value": 45, "color": "#6366F1" } ] } } """; var client = CreateClientWithResponse(HttpStatusCode.OK, json); var overview = await client.GetEnergyOverviewAsync(); Assert.Equal(2, overview.Dimensions.Count); Assert.Equal(80, overview.Dimensions[0].Value); } [Fact] public async Task GetDailyCheckin_ReturnsStatus() { var json = """ { "code": 200, "message": "ok", "data": { "checked": true, "items": ["water", "exercise"] } } """; var client = CreateClientWithResponse(HttpStatusCode.OK, json); var status = await client.GetDailyCheckinAsync(); Assert.True(status.Checked); Assert.Contains("water", status.Items); } [Fact] public async Task CompleteDrinkWater_PostsCorrectEndpoint() { var json = """{ "code": 200, "message": "打卡成功", "data": null }"""; var client = CreateClientWithResponse(HttpStatusCode.OK, json); var result = await client.CompleteDrinkWaterAsync(); Assert.Equal("打卡成功", result.Message); } [Fact] public async Task NonSuccessCode_ThrowsApiException() { var json = """{ "code": 500, "message": "服务器错误", "data": null }"""; var client = CreateClientWithResponse(HttpStatusCode.OK, json); await Assert.ThrowsAsync(() => client.GetTodayTasksAsync()); } }