using Store.Users.Contracts.Enums; using System.ComponentModel.DataAnnotations; using Store.Users.Contracts.Dtos; namespace Store.Users.Tests; /// 确认服务入口执行 DTO 的长度和范围校验,拒绝无效写入。 public sealed class UserServiceValidationTests { [Theory] [InlineData(0)] [InlineData(-1)] public async Task NonPositiveId_IsRejectedByService(int id) { using var context = new UserTestContext(); await Assert.ThrowsAsync(() => context.Users.Delete(id, default)); await Assert.ThrowsAsync(() => context.Users.Update(new() { Id = id }, false, default)); } [Theory] [InlineData("nickname")] [InlineData("mobile")] [InlineData("company")] [InlineData("notes")] [InlineData("card")] [InlineData("authority")] [InlineData("forbidden")] [InlineData("oem")] [InlineData("group")] [InlineData("level")] [InlineData("monthly")] [InlineData("postage")] [InlineData("refund")] [InlineData("gift")] [InlineData("logistics")] public async Task InvalidEdit_IsRejectedBeforePersistence(string field) { using var context = new UserTestContext(); var request = new UserUpdateRequest { Id = context.Main.Id }; switch (field) { case "nickname": request.NickName = new string('x', 51); break; case "mobile": request.Mobile = new string('x', 31); break; case "company": request.CompanyName = new string('x', 101); break; case "notes": request.Notes = new string('x', 256); break; case "card": request.CardId = new string('x', 51); break; case "authority": request.Authority = new string('x', 1001); break; case "forbidden": request.ForbiddenPage = new string('x', 1001); break; case "oem": request.OemId = new string('x', 51); break; case "group": request.GroupId = 0; break; case "level": request.SaLevel = (UserAdminLevel)2; break; case "monthly": request.ShopPointsPerMonth = 29; break; case "postage": request.PostagePerOrder = 2.1m; break; case "refund": request.RefundPostagePerOrder = 2.4m; break; case "gift": request.GiftOemAmountPerOrder = -1m; break; case "logistics": request.SyncLogisticsPerOrder = -1m; break; } await Assert.ThrowsAsync(() => context.Users.Update(request, false, default)); Assert.Empty(context.Sessions.SignedOut); Assert.Equal("main", (await context.Read("main")).NickName); } [Theory] [InlineData("username")] [InlineData("password-short")] [InlineData("password-long")] public async Task InvalidCreateLength_IsRejectedByService(string field) { using var context = new UserTestContext(); var request = new UserCreateRequest { UserName = "created", Password = "password" }; if (field == "username") request.UserName = new string('u', 21); if (field == "password-short") request.Password = "123"; if (field == "password-long") request.Password = new string('p', 129); await Assert.ThrowsAsync(() => context.Users.Create(request, false, default)); Assert.Null(await context.Read(request.UserName)); } }