using FsCheck; using FsCheck.Xunit; using HoneyBox.Admin.Business.Models; using System.Text.Json; using Xunit; namespace HoneyBox.Tests.Services; /// /// 响应格式属性测试 /// Property 16: API Response Format Consistency - API响应格式一致性 /// Property 17: Paginated Response Format - 分页响应格式一致性 /// public class ResponseFormatPropertyTests { /// /// Property 16: ApiResponse 成功响应格式一致性 /// [Property(MaxTest = 100)] public bool Property16_ApiResponse_Success_HasConsistentFormat(PositiveInt seed) { var messages = new[] { "success", "操作成功", "OK", "完成" }; var message = messages[seed.Get % messages.Length]; var response = ApiResponse.Success(message); return response.Code == 0 && response.Message == message && response.Data == null; } /// /// Property 16: ApiResponse 带数据的成功响应格式一致性 /// [Property(MaxTest = 100)] public bool Property16_ApiResponse_SuccessWithData_HasConsistentFormat(PositiveInt seed) { var data = seed.Get; var messages = new[] { "success", "操作成功", "OK" }; var message = messages[seed.Get % messages.Length]; var response = ApiResponse.Success(data, message); return response.Code == 0 && response.Message == message && response.Data != null && (int)response.Data == data; } /// /// Property 16: ApiResponse 错误响应格式一致性 /// [Property(MaxTest = 100)] public bool Property16_ApiResponse_Error_HasConsistentFormat(PositiveInt seed) { var code = (seed.Get % 1000) + 1; // Non-zero code var messages = new[] { "error", "失败", "错误" }; var message = messages[seed.Get % messages.Length]; var response = ApiResponse.Error(code, message); return response.Code == code && response.Message == message && response.Data == null; } /// /// Property 16: ApiResponse 泛型成功响应格式一致性 /// [Property(MaxTest = 100)] public bool Property16_GenericApiResponse_Success_HasConsistentFormat(PositiveInt seed) { var data = seed.Get; var response = ApiResponse.Success(data); return response.Code == 0 && response.Message == "success" && response.Data == data; } /// /// Property 16: ApiResponse 泛型错误响应格式一致性 /// [Property(MaxTest = 100)] public bool Property16_GenericApiResponse_Error_HasConsistentFormat(PositiveInt seed) { var code = (seed.Get % 1000) + 1; var messages = new[] { "error", "失败", "错误" }; var message = messages[seed.Get % messages.Length]; var response = ApiResponse.Error(code, message); return response.Code == code && response.Message == message && EqualityComparer.Default.Equals(response.Data, default); } /// /// Property 17: PagedResult 分页响应格式一致性 /// [Property(MaxTest = 100)] public bool Property17_PagedResult_HasConsistentFormat(PositiveInt seed) { var page = (seed.Get % 10) + 1; var pageSize = (seed.Get % 50) + 1; var total = seed.Get % 1000; var items = Enumerable.Range(1, Math.Min(pageSize, Math.Max(0, total - (page - 1) * pageSize))).ToList(); var result = new PagedResult { Page = page, PageSize = pageSize, Total = total, List = items }; // 验证分页结果格式 return result.Page == page && result.PageSize == pageSize && result.Total == total && result.List != null && result.List.Count <= pageSize; } /// /// Property 17: PagedResult 总页数计算正确性 /// [Property(MaxTest = 100)] public bool Property17_PagedResult_TotalPages_CalculatedCorrectly(PositiveInt seed) { var pageSize = (seed.Get % 100) + 1; var total = seed.Get % 10000; var result = new PagedResult { Page = 1, PageSize = pageSize, Total = total, List = new List() }; var expectedTotalPages = (int)Math.Ceiling((double)total / pageSize); return result.TotalPages == expectedTotalPages; } /// /// Property 17: PagedResult 空结果处理 /// [Fact] public void Property17_PagedResult_EmptyResult_HasCorrectFormat() { var result = new PagedResult { Page = 1, PageSize = 20, Total = 0, List = new List() }; Assert.Equal(1, result.Page); Assert.Equal(20, result.PageSize); Assert.Equal(0, result.Total); Assert.Equal(0, result.TotalPages); Assert.Empty(result.List); } /// /// Property 16: BusinessErrorCodes 错误码唯一性 /// [Fact] public void Property16_BusinessErrorCodes_AreUnique() { var errorCodes = new[] { BusinessErrorCodes.ValidationFailed, BusinessErrorCodes.NotFound, BusinessErrorCodes.AuthenticationFailed, BusinessErrorCodes.PermissionDenied, BusinessErrorCodes.InternalError }; var uniqueCodes = errorCodes.Distinct().ToList(); Assert.Equal(errorCodes.Length, uniqueCodes.Count); } /// /// Property 16: BusinessErrorCodes 错误码非零 /// [Fact] public void Property16_BusinessErrorCodes_AreNonZero() { var errorCodes = new[] { BusinessErrorCodes.ValidationFailed, BusinessErrorCodes.NotFound, BusinessErrorCodes.AuthenticationFailed, BusinessErrorCodes.PermissionDenied, BusinessErrorCodes.InternalError }; foreach (var code in errorCodes) { Assert.NotEqual(0, code); } } /// /// Property 16: ApiResponse JSON 序列化格式一致性 /// [Fact] public void Property16_ApiResponse_JsonSerialization_HasExpectedFormat() { var response = ApiResponse.Success("test data", "操作成功"); var json = JsonSerializer.Serialize(response, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); var doc = JsonDocument.Parse(json); var root = doc.RootElement; Assert.True(root.TryGetProperty("code", out var codeElement)); Assert.True(root.TryGetProperty("message", out var messageElement)); Assert.True(root.TryGetProperty("data", out var dataElement)); Assert.Equal(0, codeElement.GetInt32()); Assert.Equal("操作成功", messageElement.GetString()); Assert.Equal("test data", dataElement.GetString()); } /// /// Property 17: PagedResult JSON 序列化格式一致性 /// [Fact] public void Property17_PagedResult_JsonSerialization_HasExpectedFormat() { var result = new PagedResult { Page = 1, PageSize = 10, Total = 100, List = new List { "item1", "item2" } }; var json = JsonSerializer.Serialize(result, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); var doc = JsonDocument.Parse(json); var root = doc.RootElement; Assert.True(root.TryGetProperty("page", out var pageElement)); Assert.True(root.TryGetProperty("pageSize", out var pageSizeElement)); Assert.True(root.TryGetProperty("total", out var totalElement)); Assert.True(root.TryGetProperty("totalPages", out var totalPagesElement)); Assert.True(root.TryGetProperty("list", out var listElement)); Assert.Equal(1, pageElement.GetInt32()); Assert.Equal(10, pageSizeElement.GetInt32()); Assert.Equal(100, totalElement.GetInt32()); Assert.Equal(10, totalPagesElement.GetInt32()); Assert.Equal(2, listElement.GetArrayLength()); } }