Files

113 lines
4.3 KiB
C#

using System.ComponentModel.DataAnnotations;
using MAX.Framework.Commons;
using Store.Users.Entities;
namespace Store.Users.Tests;
public sealed class UserRecordTests
{
private static readonly DateTime Time = new(2025, 1, 15, 12, 0, 0);
[Fact]
public async Task PointsQuery_AppliesAccountOperationShopAndInclusiveTimeRange()
{
using var context = new UserTestContext();
await context.Db.Insert(new[]
{
Points("main", "充值", "shop-1", Time),
Points("main", "充值", "shop-2", Time),
Points("main", "消费", "shop-1", Time),
Points("main", "充值", "shop-1", Time.AddSeconds(-1)),
Points("other", "充值", "shop-1", Time)
}).ExecuteAffrowsAsync();
var page = await context.Users.Points("main", new()
{
Operation = "充值", ShopId = "shop-1", StartTime = Time, EndTime = Time
}, default);
var record = Assert.Single(page.Items);
Assert.Equal(1, page.Total);
Assert.Equal("main", record.UserName);
Assert.Equal(Time, record.AddTime);
}
[Fact]
public async Task PointsQuery_PaginatesWithStableDescendingIdOrder()
{
using var context = new UserTestContext();
await context.Db.Insert(new[]
{
Points("main", "充值", "shop-1", Time),
Points("main", "充值", "shop-2", Time),
Points("main", "充值", "shop-3", Time)
}).ExecuteAffrowsAsync();
var page = await context.Users.Points("main", new() { Page = 2, PageSize = 1 }, default);
Assert.Equal(3, page.Total);
Assert.Equal("shop-2", Assert.Single(page.Items).ShopId);
}
[Fact]
public async Task BalanceQuery_FiltersTypeOrderAndTime_AndExcludesDeletedRecords()
{
using var context = new UserTestContext();
await context.Db.Insert(new[]
{
Payment("main", 1, "order", Time),
Payment("main", 0, "order", Time),
Payment("main", 1, "different", Time),
Payment("main", 1, "order", Time.AddSeconds(1)),
Payment("other", 1, "order", Time),
Payment("main", 1, "order", Time, deleted: true)
}).ExecuteAffrowsAsync();
var page = await context.Users.Balance("main", new()
{
PaymentType = 1, OrderId = "order", StartTime = Time, EndTime = Time
}, default);
var record = Assert.Single(page.Items);
Assert.Equal(1, page.Total);
Assert.Equal("main", record.UserName);
Assert.Equal(0, record.IsDeleted);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task OrdinaryUser_CannotQuerySomeoneElsesFundsHistory(bool points)
{
using var context = new UserTestContext();
context.CurrentUser.UserName = "main";
var error = await Assert.ThrowsAsync<AppException>(async () =>
{
if (points) await context.Users.Points("other", new(), default);
else await context.Users.Balance("other", new(), default);
});
Assert.Equal(403, error.Code);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task ReversedDateRange_IsRejected(bool points)
{
using var context = new UserTestContext();
await Assert.ThrowsAsync<ValidationException>(async () =>
{
var request = new Store.Users.Contracts.Dtos.UserRecordSearchRequest { StartTime = Time, EndTime = Time.AddSeconds(-1) };
if (points) await context.Users.Points("main", request, default);
else await context.Users.Balance("main", request, default);
});
}
private static UserPointsRecordEntity Points(string user, string operation, string shop, DateTime time) => new()
{
UserName = user, UserNick = user, OptionType = operation, OperatorType = "管理员", OperatorName = "admin",
DeltaPoints = 10m, NewPoints = 10m, ShopId = shop, AddTime = time
};
private static UserPaymentRecordEntity Payment(string user, int type, string order, DateTime time, bool deleted = false) => new()
{
UserName = user, Type = type, Amount = 10m, Balance = 10m, OrderId = order, CreateTime = time,
CreateBy = "admin", UpdateBy = "", PlatformCode = "", Remark = "", CounterpartyAccountName = "",
RefundFlowNo = "", IsDeleted = deleted ? 1 : 0
};
}