298 lines
10 KiB
C#
298 lines
10 KiB
C#
using FsCheck;
|
||
using FsCheck.Xunit;
|
||
using Xunit;
|
||
using XiangYi.Application.Services;
|
||
using XiangYi.Core.Entities.Biz;
|
||
using XiangYi.Core.Enums;
|
||
|
||
namespace XiangYi.Application.Tests.Services;
|
||
|
||
/// <summary>
|
||
/// ReportService属性测试 - 举报记录完整性
|
||
/// </summary>
|
||
public class ReportCompletenessPropertyTests
|
||
{
|
||
// 预定义的举报原因列表
|
||
private static readonly string[] ValidReasons = new[]
|
||
{
|
||
"虚假信息", "骚扰行为", "不当言论", "欺诈行为", "色情内容", "广告推销"
|
||
};
|
||
|
||
// 预定义的有效举报类型
|
||
private static readonly int[] ValidReportTypes = new[]
|
||
{
|
||
(int)ReportType.User, (int)ReportType.Message, (int)ReportType.Profile
|
||
};
|
||
|
||
/// <summary>
|
||
/// **Feature: backend-api, Property 26: 举报记录完整性**
|
||
/// **Validates: Requirements 16.1**
|
||
///
|
||
/// *For any* 创建的举报记录, 应包含举报人、被举报人、举报原因、举报时间等必要字段
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_ShouldHaveAllRequiredFields()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
// 使用随机数生成不同的测试数据
|
||
var seed = positiveInt.Get;
|
||
var reporterId = (seed % 500) + 1;
|
||
var reportedUserId = ((seed % 500) + 501);
|
||
var reportType = ValidReportTypes[seed % ValidReportTypes.Length];
|
||
var reason = ValidReasons[seed % ValidReasons.Length];
|
||
|
||
// Act - 创建举报记录
|
||
var report = ReportService.CreateReportStatic(
|
||
reporterId,
|
||
reportedUserId,
|
||
reportType,
|
||
reason,
|
||
description: null,
|
||
evidenceUrls: null);
|
||
|
||
// Assert - 验证所有必要字段都存在
|
||
var hasRequiredFields = ReportService.HasRequiredFields(report);
|
||
|
||
// 验证具体字段
|
||
var hasReporterId = report.ReporterId == reporterId;
|
||
var hasReportedUserId = report.ReportedUserId == reportedUserId;
|
||
var hasReportType = report.ReportType == reportType;
|
||
var hasReason = report.Reason == reason;
|
||
var hasCreateTime = report.CreateTime != default;
|
||
var hasStatus = report.Status == (int)ReportStatus.Pending;
|
||
|
||
return hasRequiredFields
|
||
&& hasReporterId
|
||
&& hasReportedUserId
|
||
&& hasReportType
|
||
&& hasReason
|
||
&& hasCreateTime
|
||
&& hasStatus;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 举报记录 - 举报人和被举报人不能相同
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_ReporterAndReportedUser_ShouldBeDifferent()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
var userId = positiveInt.Get;
|
||
var reportType = ValidReportTypes[userId % ValidReportTypes.Length];
|
||
var reason = ValidReasons[userId % ValidReasons.Length];
|
||
|
||
// 当举报人和被举报人相同时,验证应该失败
|
||
var isValid = ReportService.ValidateReportCompleteness(
|
||
userId,
|
||
userId, // 相同的用户ID
|
||
reportType,
|
||
reason,
|
||
DateTime.Now);
|
||
|
||
// 应该返回false,因为不能举报自己
|
||
return !isValid;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 举报记录 - 举报原因不能为空
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_Reason_ShouldNotBeEmpty()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
var seed = positiveInt.Get;
|
||
var reporterId = (seed % 500) + 1;
|
||
var reportedUserId = ((seed % 500) + 501);
|
||
var reportType = ValidReportTypes[seed % ValidReportTypes.Length];
|
||
|
||
// 测试空字符串
|
||
var emptyReasons = new[] { "", " ", " " };
|
||
var emptyReason = emptyReasons[seed % emptyReasons.Length];
|
||
|
||
// 当举报原因为空时,验证应该失败
|
||
var isValid = ReportService.ValidateReportCompleteness(
|
||
reporterId,
|
||
reportedUserId,
|
||
reportType,
|
||
emptyReason,
|
||
DateTime.Now);
|
||
|
||
// 应该返回false,因为举报原因不能为空
|
||
return !isValid;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 举报记录 - 举报类型必须有效
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_Type_ShouldBeValid()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
var seed = positiveInt.Get;
|
||
var reporterId = (seed % 500) + 1;
|
||
var reportedUserId = ((seed % 500) + 501);
|
||
var reportType = ValidReportTypes[seed % ValidReportTypes.Length];
|
||
var reason = ValidReasons[seed % ValidReasons.Length];
|
||
|
||
// 有效的举报类型应该通过验证
|
||
var isValid = ReportService.ValidateReportCompleteness(
|
||
reporterId,
|
||
reportedUserId,
|
||
reportType,
|
||
reason,
|
||
DateTime.Now);
|
||
|
||
return isValid;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 举报记录 - 无效的举报类型应该被拒绝
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_InvalidType_ShouldBeRejected()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
var seed = positiveInt.Get;
|
||
var reporterId = (seed % 500) + 1;
|
||
var reportedUserId = ((seed % 500) + 501);
|
||
// 生成无效的举报类型(不在枚举范围内)
|
||
var invalidReportTypes = new[] { 0, -1, 4, 5, 100 };
|
||
var invalidReportType = invalidReportTypes[seed % invalidReportTypes.Length];
|
||
var reason = ValidReasons[seed % ValidReasons.Length];
|
||
|
||
// 无效的举报类型应该验证失败
|
||
var isValid = ReportService.ValidateReportCompleteness(
|
||
reporterId,
|
||
reportedUserId,
|
||
invalidReportType,
|
||
reason,
|
||
DateTime.Now);
|
||
|
||
// 应该返回false
|
||
return !isValid;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 举报记录 - 证据保存正确性
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_Evidence_ShouldBePreserved()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
var seed = positiveInt.Get;
|
||
var reporterId = (seed % 500) + 1;
|
||
var reportedUserId = ((seed % 500) + 501);
|
||
var reportType = ValidReportTypes[seed % ValidReportTypes.Length];
|
||
var reason = ValidReasons[seed % ValidReasons.Length];
|
||
var evidenceCount = (seed % 5) + 1; // 1-5个证据
|
||
|
||
// 生成证据URL列表
|
||
var evidenceUrls = Enumerable.Range(1, evidenceCount)
|
||
.Select(i => $"https://example.com/evidence_{i}.jpg")
|
||
.ToList();
|
||
|
||
// Act - 创建带证据的举报记录
|
||
var report = ReportService.CreateReportStatic(
|
||
reporterId,
|
||
reportedUserId,
|
||
reportType,
|
||
reason,
|
||
description: "详细描述",
|
||
evidenceUrls: evidenceUrls);
|
||
|
||
// Assert - 验证证据被正确保存
|
||
var hasEvidence = !string.IsNullOrEmpty(report.Evidence);
|
||
var evidenceContainsUrls = evidenceUrls.All(url => report.Evidence!.Contains(url));
|
||
|
||
return hasEvidence && evidenceContainsUrls;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 举报记录 - 创建时间应该是当前时间附近
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_CreateTime_ShouldBeRecent()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
var seed = positiveInt.Get;
|
||
var reporterId = (seed % 500) + 1;
|
||
var reportedUserId = ((seed % 500) + 501);
|
||
var reportType = ValidReportTypes[seed % ValidReportTypes.Length];
|
||
var reason = ValidReasons[seed % ValidReasons.Length];
|
||
|
||
var beforeCreate = DateTime.Now;
|
||
|
||
// Act - 创建举报记录
|
||
var report = ReportService.CreateReportStatic(
|
||
reporterId,
|
||
reportedUserId,
|
||
reportType,
|
||
reason,
|
||
description: null,
|
||
evidenceUrls: null);
|
||
|
||
var afterCreate = DateTime.Now;
|
||
|
||
// Assert - 创建时间应该在beforeCreate和afterCreate之间
|
||
return report.CreateTime >= beforeCreate && report.CreateTime <= afterCreate;
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 举报记录 - 初始状态应该是待处理
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public Property Report_InitialStatus_ShouldBePending()
|
||
{
|
||
return Prop.ForAll(
|
||
Arb.Default.PositiveInt(),
|
||
positiveInt =>
|
||
{
|
||
var seed = positiveInt.Get;
|
||
var reporterId = (seed % 500) + 1;
|
||
var reportedUserId = ((seed % 500) + 501);
|
||
var reportType = ValidReportTypes[seed % ValidReportTypes.Length];
|
||
var reason = ValidReasons[seed % ValidReasons.Length];
|
||
|
||
// Act - 创建举报记录
|
||
var report = ReportService.CreateReportStatic(
|
||
reporterId,
|
||
reportedUserId,
|
||
reportType,
|
||
reason,
|
||
description: null,
|
||
evidenceUrls: null);
|
||
|
||
// Assert - 初始状态应该是待处理
|
||
return report.Status == (int)ReportStatus.Pending;
|
||
});
|
||
}
|
||
}
|