using FsCheck;
using FsCheck.Xunit;
using Xunit;
using XiangYi.Application.Interfaces;
using XiangYi.Application.Services;
namespace XiangYi.Application.Tests.Services;
///
/// MemberService属性测试 - 家庭版绑定数量限制
///
public class FamilyBindLimitPropertyTests
{
///
/// **Feature: backend-api, Property 18: 家庭版绑定数量限制**
/// **Validates: Requirements 7.3**
///
/// *For any* 家庭版会员绑定操作, 绑定用户数量不应超过2个(不含主账号)
///
[Property(MaxTest = 100)]
public Property FamilyBind_ShouldNotExceedMaxLimit()
{
// 生成当前绑定数量(0-5,包含超出限制的情况)
var currentBindCountArb = Gen.Choose(0, 5);
return Prop.ForAll(
currentBindCountArb.ToArbitrary(),
currentBindCount =>
{
// Arrange
var maxBindCount = IMemberService.MaxFamilyBindCount; // 2
// Act
var canBind = MemberService.CanBindFamilyMember(currentBindCount, maxBindCount);
var countAfterBind = MemberService.CalculateFamilyBindCountAfterBind(currentBindCount, maxBindCount);
// Assert
if (currentBindCount >= maxBindCount)
{
// 已达到或超过限制,不能再绑定
return !canBind && countAfterBind == -1;
}
else
{
// 未达到限制,可以绑定,绑定后数量+1
return canBind && countAfterBind == currentBindCount + 1;
}
});
}
///
/// 家庭版绑定 - 绑定后数量不应超过最大限制
///
[Property(MaxTest = 100)]
public Property FamilyBind_CountAfterBind_ShouldNotExceedMax()
{
var currentBindCountArb = Gen.Choose(0, IMemberService.MaxFamilyBindCount - 1);
return Prop.ForAll(
currentBindCountArb.ToArbitrary(),
currentBindCount =>
{
var maxBindCount = IMemberService.MaxFamilyBindCount;
var countAfterBind = MemberService.CalculateFamilyBindCountAfterBind(currentBindCount, maxBindCount);
// 绑定后数量应该不超过最大限制
return countAfterBind <= maxBindCount;
});
}
///
/// 家庭版绑定 - 达到限制时应拒绝绑定
///
[Property(MaxTest = 100)]
public Property FamilyBind_AtMaxLimit_ShouldReject()
{
return Prop.ForAll(
Arb.Default.PositiveInt(),
_ =>
{
var maxBindCount = IMemberService.MaxFamilyBindCount;
var currentBindCount = maxBindCount; // 已达到最大限制
var canBind = MemberService.CanBindFamilyMember(currentBindCount, maxBindCount);
var countAfterBind = MemberService.CalculateFamilyBindCountAfterBind(currentBindCount, maxBindCount);
// 达到限制时应该拒绝绑定
return !canBind && countAfterBind == -1;
});
}
///
/// 家庭版绑定 - 超过限制时应拒绝绑定
///
[Property(MaxTest = 100)]
public Property FamilyBind_OverMaxLimit_ShouldReject()
{
// 生成超过限制的数量
var overLimitCountArb = Gen.Choose(IMemberService.MaxFamilyBindCount + 1, 10);
return Prop.ForAll(
overLimitCountArb.ToArbitrary(),
currentBindCount =>
{
var maxBindCount = IMemberService.MaxFamilyBindCount;
var canBind = MemberService.CanBindFamilyMember(currentBindCount, maxBindCount);
var countAfterBind = MemberService.CalculateFamilyBindCountAfterBind(currentBindCount, maxBindCount);
// 超过限制时应该拒绝绑定
return !canBind && countAfterBind == -1;
});
}
///
/// 家庭版绑定 - 从0开始绑定应该成功
///
[Property(MaxTest = 100)]
public Property FamilyBind_FromZero_ShouldSucceed()
{
return Prop.ForAll(
Arb.Default.PositiveInt(),
_ =>
{
var maxBindCount = IMemberService.MaxFamilyBindCount;
var currentBindCount = 0;
var canBind = MemberService.CanBindFamilyMember(currentBindCount, maxBindCount);
var countAfterBind = MemberService.CalculateFamilyBindCountAfterBind(currentBindCount, maxBindCount);
// 从0开始应该可以绑定
return canBind && countAfterBind == 1;
});
}
///
/// 家庭版绑定 - 每次绑定应该正好增加1
///
[Property(MaxTest = 100)]
public Property FamilyBind_ShouldIncrementByOne()
{
var validBindCountArb = Gen.Choose(0, IMemberService.MaxFamilyBindCount - 1);
return Prop.ForAll(
validBindCountArb.ToArbitrary(),
currentBindCount =>
{
var maxBindCount = IMemberService.MaxFamilyBindCount;
var countAfterBind = MemberService.CalculateFamilyBindCountAfterBind(currentBindCount, maxBindCount);
// 绑定后应该正好增加1
return countAfterBind == currentBindCount + 1;
});
}
///
/// 家庭版绑定 - 最大绑定数量应该是2
///
[Fact]
public void FamilyBind_MaxBindCount_ShouldBeThree()
{
Assert.Equal(2, IMemberService.MaxFamilyBindCount);
}
///
/// 家庭版绑定 - 绑定1个后还能再绑定1个
///
[Property(MaxTest = 100)]
public Property FamilyBind_AfterBindingOne_CanBindOneMore()
{
return Prop.ForAll(
Arb.Default.PositiveInt(),
_ =>
{
var maxBindCount = IMemberService.MaxFamilyBindCount;
// 绑定第一个
var countAfterFirst = MemberService.CalculateFamilyBindCountAfterBind(0, maxBindCount);
var canBindSecond = MemberService.CanBindFamilyMember(countAfterFirst, maxBindCount);
// 绑定第二个
var countAfterSecond = MemberService.CalculateFamilyBindCountAfterBind(countAfterFirst, maxBindCount);
var canBindThird = MemberService.CanBindFamilyMember(countAfterSecond, maxBindCount);
// 绑定1个后应该还能绑定1个,但绑定2个后不能再绑定
return countAfterFirst == 1
&& canBindSecond
&& countAfterSecond == 2
&& !canBindThird;
});
}
}