using System.Text.Json;
using System.Text.Json.Serialization;
using HoneyBox.Model.Base;
using HoneyBox.Model.Models;
using HoneyBox.Model.Models.Order;
using HoneyBox.Model.Models.Goods;
using HoneyBox.Model.Models.Payment;
using HoneyBox.Model.Models.Lottery;
using Xunit;
namespace HoneyBox.Tests.Integration;
///
/// API响应格式验证测试
/// 验证所有接口响应格式与PHP API一致
/// Requirements: 18.1-18.4
///
public class ApiResponseFormatTests
{
private readonly JsonSerializerOptions _jsonOptions;
public ApiResponseFormatTests()
{
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = null, // Use JsonPropertyName attributes
WriteIndented = false
};
}
#region ApiResponse Base Format Tests
///
/// 验证ApiResponse基类使用正确的snake_case字段名
/// Requirements: 18.1, 18.3
///
[Fact]
public void ApiResponse_ShouldUseCorrectFieldNames()
{
// Arrange
var response = ApiResponse.Success("success");
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert
Assert.Contains("\"status\":", json);
Assert.Contains("\"msg\":", json);
Assert.DoesNotContain("\"Status\":", json);
Assert.DoesNotContain("\"Msg\":", json);
}
///
/// 验证ApiResponse包含data字段
/// Requirements: 18.1, 18.3
///
[Fact]
public void ApiResponseGeneric_ShouldIncludeDataField()
{
// Arrange
var response = ApiResponse.Success("test data");
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert
Assert.Contains("\"status\":", json);
Assert.Contains("\"msg\":", json);
Assert.Contains("\"data\":", json);
Assert.DoesNotContain("\"Data\":", json);
}
///
/// 验证成功响应status=1
/// Requirements: 18.1
///
[Fact]
public void ApiResponse_Success_ShouldHaveStatus1()
{
// Arrange & Act
var response = ApiResponse.Success();
// Assert
Assert.Equal(1, response.Status);
}
///
/// 验证失败响应status=0
/// Requirements: 18.1
///
[Fact]
public void ApiResponse_Fail_ShouldHaveStatus0()
{
// Arrange & Act
var response = ApiResponse.Fail("error");
// Assert
Assert.Equal(0, response.Status);
}
///
/// 验证未授权响应status=-1
/// Requirements: 18.1
///
[Fact]
public void ApiResponse_Unauthorized_ShouldHaveStatusMinus1()
{
// Arrange & Act
var response = ApiResponse.Unauthorized();
// Assert
Assert.Equal(-1, response.Status);
}
#endregion
#region Order Models Format Tests
///
/// 验证OrderMoneyRequest使用snake_case
/// Requirements: 18.2
///
[Fact]
public void OrderMoneyRequest_ShouldUseSnakeCase()
{
// Arrange
var request = new OrderMoneyRequest
{
GoodsId = 1,
Num = 1,
PrizeNum = 1,
UseMoneyIs = 1,
UseIntegralIs = 1,
UseMoney2Is = 1
};
// Act
var json = JsonSerializer.Serialize(request, _jsonOptions);
// Assert
Assert.Contains("\"goods_id\":", json);
Assert.Contains("\"num\":", json);
Assert.Contains("\"prize_num\":", json);
Assert.Contains("\"use_money_is\":", json);
Assert.Contains("\"use_integral_is\":", json);
Assert.Contains("\"use_money2_is\":", json);
}
///
/// 验证OrderCalculationDto使用snake_case
/// Requirements: 18.2
///
[Fact]
public void OrderCalculationDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new OrderCalculationDto
{
OrderTotal = "100.00",
Price = "10.00",
Money = "50.00",
Integral = "100.00",
Score = 20.00m,
UseMoney = "10.00",
UseIntegral = "5.00",
UseMoney2 = 3.00m,
CouponPrice = "2.00"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"order_total\":", json);
Assert.Contains("\"price\":", json);
Assert.Contains("\"money\":", json);
Assert.Contains("\"integral\":", json);
Assert.Contains("\"score\":", json);
Assert.Contains("\"use_money\":", json);
Assert.Contains("\"use_integral\":", json);
Assert.Contains("\"coupon_price\":", json);
}
///
/// 验证OrderBuyResponseDto使用snake_case
/// Requirements: 18.2
///
[Fact]
public void OrderBuyResponseDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new OrderBuyResponseDto
{
Status = 1,
OrderNum = "TEST001"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"status\":", json);
Assert.Contains("\"order_num\":", json);
Assert.Contains("\"res\":", json);
}
///
/// 验证OrderListDto使用snake_case
/// Requirements: 18.2
///
[Fact]
public void OrderListDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new OrderListDto
{
Id = 1,
OrderNum = "TEST001",
GoodsTitle = "Test",
GoodsImgUrl = "http://test.com/img.jpg",
OrderTotal = "100.00",
Price = "100.00",
PrizeNum = 1,
Status = 1,
AddTime = 1234567890,
PayTime = 1234567890,
OrderType = 1
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"order_num\":", json);
Assert.Contains("\"goods_title\":", json);
Assert.Contains("\"goods_imgurl\":", json);
Assert.Contains("\"order_total\":", json);
Assert.Contains("\"price\":", json);
Assert.Contains("\"prize_num\":", json);
Assert.Contains("\"status\":", json);
Assert.Contains("\"addtime\":", json);
Assert.Contains("\"pay_time\":", json);
Assert.Contains("\"order_type\":", json);
}
///
/// 验证PrizeOrderLogDto使用snake_case
/// Requirements: 18.2
///
[Fact]
public void PrizeOrderLogDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new PrizeOrderLogDto
{
Id = 1,
UserId = 1,
GoodsListTitle = "Test",
GoodsListImgUrl = "http://test.com/img.jpg",
GoodsListPrice = "100.00",
GoodsListMoney = "50.00",
Status = 0,
LuckNo = 1,
ShangId = 1
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"user_id\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"goodslist_price\":", json);
Assert.Contains("\"goodslist_money\":", json);
Assert.Contains("\"status\":", json);
Assert.Contains("\"luck_no\":", json);
Assert.Contains("\"shang_id\":", json);
}
#endregion
#region Warehouse Models Format Tests
///
/// 验证WarehouseIndexRequest使用snake_case
/// Requirements: 18.4
///
[Fact]
public void WarehouseIndexRequest_ShouldUseSnakeCase()
{
// Arrange
var request = new WarehouseIndexRequest
{
Page = 1,
PageSize = 10,
Type = 1
};
// Act
var json = JsonSerializer.Serialize(request, _jsonOptions);
// Assert
Assert.Contains("\"page\":", json);
Assert.Contains("\"page_size\":", json);
Assert.Contains("\"type\":", json);
}
///
/// 验证WarehouseItemDto使用snake_case
/// Requirements: 18.4
///
[Fact]
public void WarehouseItemDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new WarehouseItemDto
{
Id = 1,
GoodsListTitle = "Test",
GoodsListImgUrl = "http://test.com/img.jpg",
GoodsListPrice = "100.00",
GoodsListMoney = "50.00",
Status = 0,
AddTime = 1234567890,
ShangId = 1,
GoodsId = 1
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"goodslist_price\":", json);
Assert.Contains("\"goodslist_money\":", json);
Assert.Contains("\"status\":", json);
Assert.Contains("\"addtime\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"goods_id\":", json);
}
///
/// 验证RecoveryResultDto使用snake_case
/// Requirements: 18.4
///
[Fact]
public void RecoveryResultDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new RecoveryResultDto
{
TotalMoney = "100.00",
Count = 5,
RecoveryNum = "REC001",
UserMoney = "150.00"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"total_money\":", json);
Assert.Contains("\"count\":", json);
Assert.Contains("\"recovery_num\":", json);
Assert.Contains("\"user_money\":", json);
}
///
/// 验证SendRecordDto使用snake_case
/// Requirements: 18.4
///
[Fact]
public void SendRecordDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new SendRecordDto
{
Id = 1,
SendNum = "SEND001",
Name = "Test",
Mobile = "138****0000",
Address = "Test Address",
Status = 1,
StatusName = "待发货",
Count = 3,
Freight = "10.00",
AddTime = "2024-01-01 12:00:00"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"send_num\":", json);
Assert.Contains("\"name\":", json);
Assert.Contains("\"mobile\":", json);
Assert.Contains("\"address\":", json);
Assert.Contains("\"status\":", json);
Assert.Contains("\"status_name\":", json);
Assert.Contains("\"count\":", json);
Assert.Contains("\"freight\":", json);
Assert.Contains("\"addtime\":", json);
}
///
/// 验证LogisticsDto使用snake_case
/// Requirements: 18.4
///
[Fact]
public void LogisticsDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new LogisticsDto
{
CourierNumber = "SF123456",
CourierName = "顺丰速运",
CourierCode = "SF",
Count = 3,
SendNum = "SEND001",
DeliveryStatus = "已签收"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"courier_number\":", json);
Assert.Contains("\"courier_name\":", json);
Assert.Contains("\"courier_code\":", json);
Assert.Contains("\"count\":", json);
Assert.Contains("\"send_num\":", json);
Assert.Contains("\"delivery_status\":", json);
}
#endregion
#region PageResponse Format Tests
///
/// 验证PageResponse使用snake_case
/// Requirements: 18.2, 18.4
///
[Fact]
public void PageResponse_ShouldUseSnakeCase()
{
// Arrange
var response = new PageResponse
{
Data = new List(),
LastPage = 10,
Total = 100,
Page = 1,
PageSize = 10
};
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert
Assert.Contains("\"data\":", json);
Assert.Contains("\"last_page\":", json);
Assert.Contains("\"total\":", json);
Assert.Contains("\"page\":", json);
Assert.Contains("\"page_size\":", json);
}
#endregion
#region WechatPayParams Format Tests
///
/// 验证WechatPayParamsDto使用正确的字段名(微信API要求的camelCase)
/// Requirements: 18.2
///
[Fact]
public void WechatPayParamsDto_ShouldUseCamelCaseForWechatApi()
{
// Arrange
var dto = new WechatPayParamsDto
{
AppId = "wx123456",
TimeStamp = "1234567890",
NonceStr = "abc123",
Package = "prepay_id=xxx",
SignType = "RSA",
PaySign = "sign123"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert - 微信支付参数使用camelCase是正确的
Assert.Contains("\"appId\":", json);
Assert.Contains("\"timeStamp\":", json);
Assert.Contains("\"nonceStr\":", json);
Assert.Contains("\"package\":", json);
Assert.Contains("\"signType\":", json);
Assert.Contains("\"paySign\":", json);
}
#endregion
#region Complete Response Serialization Tests
///
/// 验证完整的订单金额计算响应格式
/// Requirements: 18.1, 18.2
///
[Fact]
public void CompleteOrderCalculationResponse_ShouldMatchPhpFormat()
{
// Arrange
var data = new OrderCalculationDto
{
OrderTotal = "100.00",
Price = "10.00",
Goods = new GoodsInfoDto { Id = 1, Title = "Test" },
Money = "50.00",
Integral = "100.00",
Score = 20.00m
};
var response = ApiResponse.Success(data);
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert - 验证顶层结构
Assert.Contains("\"status\":1", json);
Assert.Contains("\"msg\":\"success\"", json);
Assert.Contains("\"data\":", json);
// Assert - 验证数据字段
Assert.Contains("\"order_total\":\"100.00\"", json);
Assert.Contains("\"price\":\"10.00\"", json);
Assert.Contains("\"goods\":", json);
Assert.Contains("\"money\":\"50.00\"", json);
Assert.Contains("\"integral\":\"100.00\"", json);
Assert.Contains("\"score\":20", json);
}
///
/// 验证完整的仓库首页响应格式
/// Requirements: 18.3, 18.4
///
[Fact]
public void CompleteWarehouseIndexResponse_ShouldMatchPhpFormat()
{
// Arrange
var data = new WarehouseIndexResponseDto
{
Total = 100,
Data = new List
{
new WarehouseGoodsGroupDto
{
GoodsId = 1,
GoodsTitle = "Test",
OrderList = new List
{
new WarehouseItemDto
{
Id = 1,
GoodsListTitle = "Prize",
GoodsListImgUrl = "http://test.com/img.jpg",
GoodsListPrice = "100.00",
GoodsListMoney = "50.00",
Status = 0
}
}
}
},
LastPage = 10
};
var response = ApiResponse.Success(data);
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert - 验证顶层结构
Assert.Contains("\"status\":1", json);
Assert.Contains("\"msg\":\"success\"", json);
Assert.Contains("\"data\":", json);
// Assert - 验证数据字段
Assert.Contains("\"total\":", json);
Assert.Contains("\"last_page\":", json);
Assert.Contains("\"goods_id\":", json);
Assert.Contains("\"goods_title\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"goodslist_price\":", json);
Assert.Contains("\"goodslist_money\":", json);
}
#endregion
#region Payment System Response Format Tests - Requirements 10.1-10.4
///
/// 验证WechatPayResult使用正确的字段名
/// Requirements: 10.1, 10.3
///
[Fact]
public void WechatPayResult_ShouldUseCorrectFieldNames()
{
// Arrange
var result = new WechatPayResult
{
Status = 1,
Msg = "success",
Data = new WechatPayData
{
AppId = "wx123456",
TimeStamp = "1234567890",
NonceStr = "abc123",
Package = "prepay_id=xxx",
SignType = "MD5",
PaySign = "sign123",
IsWeixin = 1
}
};
// Act
var json = JsonSerializer.Serialize(result, _jsonOptions);
// Assert - 验证顶层结构使用snake_case
Assert.Contains("\"status\":", json);
Assert.Contains("\"msg\":", json);
Assert.Contains("\"data\":", json);
Assert.DoesNotContain("\"Status\":", json);
Assert.DoesNotContain("\"Msg\":", json);
Assert.DoesNotContain("\"Data\":", json);
}
///
/// 验证WechatPayData使用正确的字段名(微信API要求的camelCase)
/// Requirements: 10.2, 10.4
///
[Fact]
public void WechatPayData_ShouldUseCamelCaseForWechatApi()
{
// Arrange
var data = new WechatPayData
{
AppId = "wx123456",
TimeStamp = "1234567890",
NonceStr = "abc123",
Package = "prepay_id=xxx",
SignType = "MD5",
PaySign = "sign123",
IsWeixin = 1
};
// Act
var json = JsonSerializer.Serialize(data, _jsonOptions);
// Assert - 微信支付参数使用camelCase(与PHP API一致)
Assert.Contains("\"appId\":", json);
Assert.Contains("\"timeStamp\":", json);
Assert.Contains("\"nonceStr\":", json);
Assert.Contains("\"package\":", json);
Assert.Contains("\"signType\":", json);
Assert.Contains("\"paySign\":", json);
Assert.Contains("\"is_weixin\":", json); // is_weixin使用snake_case
}
///
/// 验证WechatPayResult成功响应status=1
/// Requirements: 10.3
///
[Fact]
public void WechatPayResult_Success_ShouldHaveStatus1()
{
// Arrange
var result = new WechatPayResult
{
Status = 1,
Msg = "success",
Data = new WechatPayData()
};
// Assert
Assert.Equal(1, result.Status);
}
///
/// 验证WechatPayResult失败响应status=0
/// Requirements: 10.3
///
[Fact]
public void WechatPayResult_Fail_ShouldHaveStatus0()
{
// Arrange
var result = new WechatPayResult
{
Status = 0,
Msg = "支付失败"
};
// Assert
Assert.Equal(0, result.Status);
}
///
/// 验证WechatPayRequest使用snake_case
/// Requirements: 10.2
///
[Fact]
public void WechatPayRequest_ShouldUseSnakeCase()
{
// Arrange
var request = new WechatPayRequest
{
OrderNo = "TEST001",
Amount = 100.00m,
Body = "商品购买",
Attach = "order_yfs",
OpenId = "openid123",
UserId = 1
};
// Act
var json = JsonSerializer.Serialize(request, _jsonOptions);
// Assert
Assert.Contains("\"order_no\":", json);
Assert.Contains("\"amount\":", json);
Assert.Contains("\"body\":", json);
Assert.Contains("\"attach\":", json);
Assert.Contains("\"open_id\":", json);
Assert.Contains("\"user_id\":", json);
}
///
/// 验证PaymentRecordDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void PaymentRecordDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new HoneyBox.Model.Models.Payment.PaymentRecordDto
{
Id = 1,
UserId = 1,
OrderNum = "TEST001",
ChangeMoney = "100.00",
Content = "支付测试",
PayType = 1,
PayTypeText = "微信支付",
CreatedAt = 1234567890
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"user_id\":", json);
Assert.Contains("\"order_num\":", json);
Assert.Contains("\"change_money\":", json);
Assert.Contains("\"content\":", json);
Assert.Contains("\"pay_type\":", json);
Assert.Contains("\"pay_type_text\":", json);
Assert.Contains("\"created_at\":", json);
}
///
/// 验证完整的微信支付响应格式与PHP API一致
/// Requirements: 10.1-10.4
///
[Fact]
public void CompleteWechatPayResponse_ShouldMatchPhpFormat()
{
// Arrange - 模拟PHP API返回的格式
// PHP: return ['status' => 1, 'data' => $res];
// $res = ['appId' => ..., 'timeStamp' => ..., 'nonceStr' => ..., 'package' => ..., 'signType' => ..., 'paySign' => ...]
var result = new WechatPayResult
{
Status = 1,
Msg = "success",
Data = new WechatPayData
{
AppId = "wx1234567890abcdef",
TimeStamp = "1735776000",
NonceStr = "abc123def456",
Package = "prepay_id=wx123456789",
SignType = "MD5",
PaySign = "ABCDEF1234567890",
IsWeixin = 1
}
};
// Act
var json = JsonSerializer.Serialize(result, _jsonOptions);
// Assert - 验证顶层结构
Assert.Contains("\"status\":1", json);
Assert.Contains("\"msg\":\"success\"", json);
Assert.Contains("\"data\":", json);
// Assert - 验证支付参数字段名(与PHP一致)
Assert.Contains("\"appId\":\"wx1234567890abcdef\"", json);
Assert.Contains("\"timeStamp\":\"1735776000\"", json);
Assert.Contains("\"nonceStr\":\"abc123def456\"", json);
Assert.Contains("\"package\":\"prepay_id=wx123456789\"", json);
Assert.Contains("\"signType\":\"MD5\"", json);
Assert.Contains("\"paySign\":\"ABCDEF1234567890\"", json);
Assert.Contains("\"is_weixin\":1", json);
}
///
/// 验证微信支付失败响应格式
/// Requirements: 10.1, 10.3
///
[Fact]
public void WechatPayFailResponse_ShouldMatchPhpFormat()
{
// Arrange - 模拟PHP API返回的失败格式
// PHP: return ['status' => 0, 'msg' => '支付失败'];
var result = new WechatPayResult
{
Status = 0,
Msg = "网络故障,请稍后重试(支付参数错误)"
};
// Act
var json = JsonSerializer.Serialize(result, _jsonOptions);
// Assert - 验证结构正确(不验证具体中文内容,因为JSON会转义Unicode)
Assert.Contains("\"status\":0", json);
Assert.Contains("\"msg\":", json);
// data字段应该为null
Assert.Contains("\"data\":null", json);
// 验证反序列化后内容正确
var deserialized = JsonSerializer.Deserialize(json, _jsonOptions);
Assert.NotNull(deserialized);
Assert.Equal(0, deserialized.Status);
Assert.Equal("网络故障,请稍后重试(支付参数错误)", deserialized.Msg);
}
///
/// 验证支付回调XML响应格式
/// Requirements: 10.1
///
[Fact]
public void NotifyXmlResponse_ShouldMatchWechatFormat()
{
// Arrange - 微信要求的XML响应格式
var successXml = "";
var failXml = "";
// Assert - 验证XML格式正确
Assert.Contains("", successXml);
Assert.Contains("", successXml);
Assert.Contains("", failXml);
}
#endregion
#region Lottery System Response Format Tests - Requirements 10.1-10.4
///
/// 验证PrizeOrderLogRequest使用snake_case
/// Requirements: 10.2
///
[Fact]
public void LotteryPrizeOrderLogRequest_ShouldUseSnakeCase()
{
// Arrange
var request = new HoneyBox.Model.Models.Lottery.PrizeOrderLogRequest
{
OrderNum = "TEST001"
};
// Act
var json = JsonSerializer.Serialize(request, _jsonOptions);
// Assert
Assert.Contains("\"order_num\":", json);
Assert.DoesNotContain("\"OrderNum\":", json);
}
///
/// 验证InfiniteShangLogRequest使用snake_case
/// Requirements: 10.2
///
[Fact]
public void InfiniteShangLogRequest_ShouldUseSnakeCase()
{
// Arrange
var request = new InfiniteShangLogRequest
{
GoodsId = 1,
ShangId = 10,
IsMibao = 0,
Page = 1,
PageSize = 10
};
// Act
var json = JsonSerializer.Serialize(request, _jsonOptions);
// Assert
Assert.Contains("\"goods_id\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"is_mibao\":", json);
Assert.Contains("\"page\":", json);
Assert.Contains("\"page_size\":", json);
}
///
/// 验证DailyPrizeRecordsRequest使用snake_case
/// Requirements: 10.2
///
[Fact]
public void DailyPrizeRecordsRequest_ShouldUseSnakeCase()
{
// Arrange
var request = new DailyPrizeRecordsRequest
{
GoodsId = 1,
Page = 1,
PageSize = 10
};
// Act
var json = JsonSerializer.Serialize(request, _jsonOptions);
// Assert
Assert.Contains("\"goods_id\":", json);
Assert.Contains("\"page\":", json);
Assert.Contains("\"page_size\":", json);
}
///
/// 验证ItemCardDrawRequest使用snake_case
/// Requirements: 10.2
///
[Fact]
public void ItemCardDrawRequest_ShouldUseSnakeCase()
{
// Arrange
var request = new ItemCardDrawRequest
{
GoodsId = 1,
OrderListIds = "1,2,3"
};
// Act
var json = JsonSerializer.Serialize(request, _jsonOptions);
// Assert
Assert.Contains("\"goods_id\":", json);
Assert.Contains("\"order_list_ids\":", json);
}
///
/// 验证InfiniteShangLogResponseDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void InfiniteShangLogResponseDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new InfiniteShangLogResponseDto
{
Category = new List
{
new() { ShangId = 0, ShangTitle = "全部" },
new() { ShangId = 10, ShangTitle = "A赏" }
},
Data = new List(),
LastPage = 1,
Total = 10
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"category\":", json);
Assert.Contains("\"data\":", json);
Assert.Contains("\"last_page\":", json);
Assert.Contains("\"total\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"shang_title\":", json);
}
///
/// 验证InfiniteShangLogItemDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void InfiniteShangLogItemDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new InfiniteShangLogItemDto
{
Id = 1,
UserId = 1,
GoodslistTitle = "测试奖品",
GoodslistImgurl = "http://test.com/img.jpg",
GoodslistPrice = "100.00",
GoodslistMoney = "50.00",
ShangId = 10,
ShangTitle = "A赏",
ShangColor = "#FF0000",
PrizeNum = 1,
Addtime = "2024-01-01 12:00:00",
LuckNo = 1,
Doubling = 1,
IsLingzhu = 0,
UserInfo = new LotteryUserInfoDto
{
Nickname = "测***户",
HeadImg = "avatar.jpg"
}
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"user_id\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"goodslist_price\":", json);
Assert.Contains("\"goodslist_money\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"shang_title\":", json);
Assert.Contains("\"shang_color\":", json);
Assert.Contains("\"prize_num\":", json);
Assert.Contains("\"addtime\":", json);
Assert.Contains("\"luck_no\":", json);
Assert.Contains("\"doubling\":", json);
Assert.Contains("\"is_lingzhu\":", json);
Assert.Contains("\"user_info\":", json);
Assert.Contains("\"nickname\":", json);
Assert.Contains("\"headimg\":", json);
}
///
/// 验证DailyPrizeRecordItemDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void DailyPrizeRecordItemDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new DailyPrizeRecordItemDto
{
Id = 1,
UserId = 1,
GoodslistTitle = "测试奖品",
GoodslistImgurl = "http://test.com/img.jpg",
ShangId = 10,
ShangTitle = "A赏",
Addtime = "2024-01-01 12:00:00"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"user_id\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"shang_title\":", json);
Assert.Contains("\"addtime\":", json);
}
///
/// 验证InfinitePrizeRecordsResponseDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void InfinitePrizeRecordsResponseDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new InfinitePrizeRecordsResponseDto
{
Data = new List(),
CurrentPage = 1,
LastPage = 10,
PerPage = 10,
Total = 100
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"data\":", json);
Assert.Contains("\"current_page\":", json);
Assert.Contains("\"last_page\":", json);
Assert.Contains("\"per_page\":", json);
Assert.Contains("\"total\":", json);
}
///
/// 验证InfinitePrizeRecordItemDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void InfinitePrizeRecordItemDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new InfinitePrizeRecordItemDto
{
UserId = 1,
GoodslistTitle = "测试奖品",
GoodslistImgurl = "http://test.com/img.jpg",
Addtime = "2024-01-01 12:00:00"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"user_id\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"addtime\":", json);
}
///
/// 验证ItemCardDrawResponseDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void ItemCardDrawResponseDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new ItemCardDrawResponseDto
{
Status = 0,
OrderNum = "TEST001",
Prizes = new List
{
new()
{
Id = 1,
Title = "测试奖品",
ImgUrl = "http://test.com/img.jpg",
ShangId = 10,
ShangTitle = "A赏",
ShangColor = "#FF0000",
Price = "100.00",
ScMoney = "50.00",
PrizeCode = "PRIZE001",
LuckNo = 1
}
},
RemainingCards = 5
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"status\":", json);
Assert.Contains("\"order_num\":", json);
Assert.Contains("\"prizes\":", json);
Assert.Contains("\"remaining_cards\":", json);
Assert.Contains("\"id\":", json);
Assert.Contains("\"title\":", json);
Assert.Contains("\"img_url\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"shang_title\":", json);
Assert.Contains("\"shang_color\":", json);
Assert.Contains("\"price\":", json);
Assert.Contains("\"sc_money\":", json);
Assert.Contains("\"prize_code\":", json);
Assert.Contains("\"luck_no\":", json);
}
///
/// 验证PrizeOrderLogResponseDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void PrizeOrderLogResponseDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new PrizeOrderLogResponseDto
{
Data = new List
{
new()
{
Id = 1,
UserId = 1,
GoodsListTitle = "测试奖品",
GoodsListImgUrl = "http://test.com/img.jpg",
GoodsListPrice = "100.00",
GoodsListMoney = "50.00",
Status = 0,
LuckNo = 1,
ShangId = 10,
ShangTitle = "A赏",
Doubling = 1,
IsLingzhu = 0,
GoodsListType = 1,
GoodsListId = 1,
ParentGoodsListId = 0,
PrizeNum = 1,
AddTime = 1234567890
}
},
ItemCardCount = 5,
PrizeNum = 1
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"data\":", json);
Assert.Contains("\"item_card_count\":", json);
Assert.Contains("\"prize_num\":", json);
Assert.Contains("\"id\":", json);
Assert.Contains("\"user_id\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"goodslist_price\":", json);
Assert.Contains("\"goodslist_money\":", json);
Assert.Contains("\"status\":", json);
Assert.Contains("\"luck_no\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"shang_title\":", json);
Assert.Contains("\"doubling\":", json);
Assert.Contains("\"is_lingzhu\":", json);
Assert.Contains("\"goodslist_type\":", json);
Assert.Contains("\"goodslist_id\":", json);
Assert.Contains("\"parent_goods_list_id\":", json);
Assert.Contains("\"addtime\":", json);
}
///
/// 验证InfinitePrizeOrderLogResponseDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void InfinitePrizeOrderLogResponseDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new InfinitePrizeOrderLogResponseDto
{
UserInfo = new UserBasicInfoDto
{
Nickname = "测试用户",
HeadImg = "avatar.jpg"
},
Data = new List(),
ItemCardCount = 5,
PrizeNum = 1
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"user_info\":", json);
Assert.Contains("\"data\":", json);
Assert.Contains("\"item_card_count\":", json);
Assert.Contains("\"prize_num\":", json);
Assert.Contains("\"nickname\":", json);
Assert.Contains("\"headimg\":", json);
}
///
/// 验证完整的无限赏中奖记录响应格式与PHP API一致
/// Requirements: 10.1-10.4
///
[Fact]
public void CompleteInfiniteShangLogResponse_ShouldMatchPhpFormat()
{
// Arrange - 模拟PHP API返回的格式
var data = new InfiniteShangLogResponseDto
{
Category = new List
{
new() { ShangId = 0, ShangTitle = "全部" },
new() { ShangId = 10, ShangTitle = "A赏" }
},
Data = new List
{
new()
{
Id = 1,
UserId = 1,
GoodslistTitle = "测试奖品",
GoodslistImgurl = "http://test.com/img.jpg",
GoodslistPrice = "100.00",
GoodslistMoney = "50.00",
ShangId = 10,
ShangTitle = "A赏",
ShangColor = "#FF0000",
PrizeNum = 1,
Addtime = "2024-01-01 12:00:00",
LuckNo = 1,
Doubling = 1,
IsLingzhu = 0,
UserInfo = new LotteryUserInfoDto
{
Nickname = "测***户",
HeadImg = "avatar.jpg"
}
}
},
LastPage = 1,
Total = 1
};
var response = ApiResponse.Success(data);
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert - 验证顶层结构
Assert.Contains("\"status\":1", json);
Assert.Contains("\"msg\":\"success\"", json);
Assert.Contains("\"data\":", json);
// Assert - 验证数据字段使用snake_case
Assert.Contains("\"category\":", json);
Assert.Contains("\"last_page\":", json);
Assert.Contains("\"total\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"shang_title\":", json);
Assert.Contains("\"user_id\":", json);
Assert.Contains("\"goodslist_title\":", json);
Assert.Contains("\"goodslist_imgurl\":", json);
Assert.Contains("\"goodslist_price\":", json);
Assert.Contains("\"goodslist_money\":", json);
Assert.Contains("\"shang_color\":", json);
Assert.Contains("\"prize_num\":", json);
Assert.Contains("\"addtime\":", json);
Assert.Contains("\"luck_no\":", json);
Assert.Contains("\"doubling\":", json);
Assert.Contains("\"is_lingzhu\":", json);
Assert.Contains("\"user_info\":", json);
Assert.Contains("\"nickname\":", json);
Assert.Contains("\"headimg\":", json);
}
///
/// 验证完整的道具卡抽奖响应格式与PHP API一致
/// Requirements: 10.1-10.4
///
[Fact]
public void CompleteItemCardDrawResponse_ShouldMatchPhpFormat()
{
// Arrange
var data = new ItemCardDrawResponseDto
{
Status = 0,
OrderNum = "MH_20240101120000001",
Prizes = new List
{
new()
{
Id = 1,
Title = "A赏奖品",
ImgUrl = "http://test.com/prize.jpg",
ShangId = 10,
ShangTitle = "A赏",
ShangColor = "#FF0000",
Price = "100.00",
ScMoney = "50.00",
PrizeCode = "PRIZE20240101001",
LuckNo = 88
}
},
RemainingCards = 4
};
var response = ApiResponse.Success(data, "重抽成功");
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert - 验证顶层结构
Assert.Contains("\"status\":1", json);
Assert.Contains("\"data\":", json);
// Assert - 验证数据字段使用snake_case
Assert.Contains("\"order_num\":", json);
Assert.Contains("\"prizes\":", json);
Assert.Contains("\"remaining_cards\":", json);
Assert.Contains("\"img_url\":", json);
Assert.Contains("\"shang_id\":", json);
Assert.Contains("\"shang_title\":", json);
Assert.Contains("\"shang_color\":", json);
Assert.Contains("\"sc_money\":", json);
Assert.Contains("\"prize_code\":", json);
Assert.Contains("\"luck_no\":", json);
}
///
/// 验证抽奖系统失败响应格式
/// Requirements: 10.1, 10.3
///
[Fact]
public void LotteryFailResponse_ShouldMatchPhpFormat()
{
// Arrange - 模拟PHP API返回的失败格式
var response = ApiResponse.Fail("盒子不存在");
// Act
var json = JsonSerializer.Serialize(response, _jsonOptions);
// Assert
Assert.Contains("\"status\":0", json);
Assert.Contains("\"msg\":", json);
// 验证反序列化后内容正确
var deserialized = JsonSerializer.Deserialize>(json, _jsonOptions);
Assert.NotNull(deserialized);
Assert.Equal(0, deserialized.Status);
Assert.Equal("盒子不存在", deserialized.Msg);
}
///
/// 验证ShangInfoDto使用snake_case(用于赏品等级信息)
/// Requirements: 10.2
///
[Fact]
public void ShangInfoDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new ShangInfoDto
{
Id = 10,
Title = "A赏",
ImgUrl = "http://test.com/shang.jpg",
Color = "#FF0000",
SpecialImgUrl = "http://test.com/special.jpg"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"id\":", json);
Assert.Contains("\"title\":", json);
Assert.Contains("\"img_url\":", json);
Assert.Contains("\"color\":", json);
Assert.Contains("\"special_img_url\":", json);
}
///
/// 验证LotteryUserInfoDto使用snake_case
/// Requirements: 10.2
///
[Fact]
public void LotteryUserInfoDto_ShouldUseSnakeCase()
{
// Arrange
var dto = new LotteryUserInfoDto
{
Nickname = "测***户",
HeadImg = "avatar.jpg"
};
// Act
var json = JsonSerializer.Serialize(dto, _jsonOptions);
// Assert
Assert.Contains("\"nickname\":", json);
Assert.Contains("\"headimg\":", json);
}
#endregion
}