增加Shop API

This commit is contained in:
chfei committed 2026-10-29 11:34:35 +08:00
1 parent 3769193696
commit 5d017740c6
83 files changed
+4451 -696

No files matched your search

@@ -5,7 +5,7 @@ using Store.Users.Dtos;
namespace Store.Users.Tests;
/// <summary>验证公共工具,以及 User DTO 仅保留 Required 的模块约定。</summary>
/// <summary>验证服务入口使用的 DTO 注解和跨字段规则。</summary>
public sealed class RequestValidatorTests
{
[Fact]
@@ -41,48 +41,39 @@ public sealed class RequestValidatorTests
public void TryValidate_ReturnsAllMissingRequiredFields()
{
Assert.False(RequestValidator.TryValidate(new UserFundsRequest(), out var errors));
Assert.Equal(3, errors.Count);
Assert.Equal(4, errors.Count);
Assert.Contains(errors, e => e.MemberNames.Contains(nameof(UserFundsRequest.Amount)));
Assert.Contains(errors, e => e.MemberNames.Contains(nameof(UserFundsRequest.UserName)));
Assert.Contains(errors, e => e.MemberNames.Contains(nameof(UserFundsRequest.RequestId)));
Assert.Contains(errors, e => e.MemberNames.Contains(nameof(UserFundsRequest.Operation)));
}
[Theory]
[InlineData(typeof(UserFundsRequest))]
[InlineData(typeof(UserEditRequest))]
[InlineData(typeof(UserCreateRequest))]
[InlineData(typeof(ChangePasswordRequest))]
[InlineData(typeof(UserSearchRequest))]
[InlineData(typeof(UserRecordSearchRequest))]
[InlineData(typeof(UserTopUpMessageRequest))]
[InlineData(typeof(UserTopUpResultRequest))]
[InlineData(typeof(UserTopUpQrcodeRequest))]
[InlineData(typeof(UserNameRequest))]
[InlineData(typeof(UserLoginRequest))]
[InlineData(typeof(UserTopUpQrcodeQuery))]
[InlineData(typeof(ShopRenewRequest))]
public void UserDtos_DeclareOnlyRequiredValidation(Type type)
public static TheoryData<object> InvalidRequests => new()
{
Assert.False(typeof(IValidatableObject).IsAssignableFrom(type));
foreach (var property in type.GetProperties())
Assert.All(property.GetCustomAttributes(typeof(ValidationAttribute), true), attribute => Assert.IsType<RequiredAttribute>(attribute));
}
new UserFundsRequest { UserName = new string('u', 21), RequestId = "id", Amount = 1, Operation = "充值" },
new UserFundsRequest { UserName = "user", RequestId = "id", Amount = -1, Operation = "充值" },
new UserFundsRequest { UserName = "user", RequestId = "id", Amount = 1.001m, Operation = "充值" },
new UserTopUpQrcodeRequest { AgentCode = "agent", QrcodeBase64 = "invalid!" },
new UserRecordSearchRequest { Page = 0 },
new UserRecordSearchRequest { StartTime = new(2025, 2, 1), EndTime = new(2025, 1, 1) },
new ShopRenewRequest { ShopId = "shop", RenewDuration = 0 },
new ShopRenewRequest { ShopId = "shop", RenewDuration = 121 },
new UserCreateRequest { UserName = "user", Password = "123" },
new UserCreateRequest { UserName = "user", Password = "password", ShopPointsPerMonth = 1 }
};
[Fact]
public void UserDto_DoesNotCheckNonEmptyParameterValues()
[Theory]
[MemberData(nameof(InvalidRequests))]
public void InvalidDto_IsRejectedAtValidationEntry(object request)
{
// 这些值非空但不合法:DTO 应通过,服务负责拒绝。
RequestValidator.Validate(new UserFundsRequest { UserName = new string('u', 21), RequestId = "id", Amount = -1, Operation = "非法操作" });
RequestValidator.Validate(new UserTopUpQrcodeRequest { AgentCode = "agent", QrcodeBase64 = "invalid!" });
RequestValidator.Validate(new UserRecordSearchRequest { Page = 0, StartTime = new(2025, 2, 1), EndTime = new(2025, 1, 1) });
RequestValidator.Validate(new ShopRenewRequest { ShopId = "shop", RenewDuration = 0 });
RequestValidator.Validate(new UserCreateRequest { UserName = "user", Password = "123", ShopPointsPerMonth = 1 });
Assert.Throws<ValidationException>(() => RequestValidator.Validate(request));
Assert.False(RequestValidator.TryValidate(request, out var errors));
Assert.NotEmpty(errors);
}
[Fact]
public void FrameworkValidator_StillSupportsOtherModulesAnnotationsAndCrossFieldRules()
{
// User 的约定不限制公共工具支持标准 DataAnnotations 的能力。
Assert.Throws<ValidationException>(() => RequestValidator.Validate(new OtherModuleRequest { Name = "toolong" }));
Assert.False(RequestValidator.TryValidate(new OtherModuleRequest { Name = "ok", Count = 0 }, out _));
var request = new OtherModuleRequest { Name = "ok", Count = 2, Start = 2, End = 1 };