using FsCheck;
using FsCheck.Xunit;
using OfficeOpenXml;
using WorkCameraExport.Models;
using WorkCameraExport.Services;
using Xunit;
namespace WorkCameraExport.Tests
{
///
/// ExportService 属性测试
/// Feature: work-camera-2.0.1
///
public class ExportServicePropertyTests : IDisposable
{
private readonly string _testOutputDir;
public ExportServicePropertyTests()
{
_testOutputDir = Path.Combine(Path.GetTempPath(), $"ExportService_Test_{Guid.NewGuid():N}");
Directory.CreateDirectory(_testOutputDir);
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
}
public void Dispose()
{
try
{
if (Directory.Exists(_testOutputDir))
{
Directory.Delete(_testOutputDir, true);
}
}
catch
{
// 忽略清理错误
}
}
#region Property 6: 分页数据获取
///
/// Property 6: 分页数据获取
/// For any 分页查询,每页返回的数据量应不超过 pageSize(50),且所有页的数据合并后应等于总记录数。
/// Validates: Requirements 6.3
///
[Property(MaxTest = 100)]
public Property PaginatedData_PageSize_ShouldNotExceedLimit()
{
return Prop.ForAll(
Arb.From(),
Arb.From(),
(totalCountGen, pageSizeGen) =>
{
var totalCount = (totalCountGen.Get % 200) + 1; // 1-200 条记录
var pageSize = (pageSizeGen.Get % 50) + 1; // 1-50 每页
// 模拟分页
var pages = SimulatePagination(totalCount, pageSize);
// 验证每页数据量不超过 pageSize
var allPagesValid = pages.All(p => p.Count <= pageSize);
// 验证总数据量等于 totalCount
var totalFromPages = pages.Sum(p => p.Count);
return (allPagesValid && totalFromPages == totalCount)
.Label($"All pages should have <= {pageSize} items and total should be {totalCount}, got {totalFromPages}");
});
}
///
/// Property 6 扩展: 分页后的数据应保持顺序
///
[Property(MaxTest = 100)]
public Property PaginatedData_Order_ShouldBePreserved()
{
return Prop.ForAll(
Arb.From(),
(totalCountGen) =>
{
var totalCount = (totalCountGen.Get % 100) + 1;
var pageSize = 50;
// 生成有序数据
var allData = Enumerable.Range(1, totalCount).ToList();
// 模拟分页获取
var pages = SimulatePaginationWithData(allData, pageSize);
// 合并所有页
var merged = pages.SelectMany(p => p).ToList();
// 验证顺序
var orderPreserved = merged.SequenceEqual(allData);
return orderPreserved.Label("Data order should be preserved after pagination");
});
}
#endregion
#region 辅助方法
///
/// 模拟分页
///
private List> SimulatePagination(int totalCount, int pageSize)
{
var pages = new List>();
var remaining = totalCount;
var pageNum = 0;
while (remaining > 0)
{
var count = Math.Min(remaining, pageSize);
pages.Add(Enumerable.Range(pageNum * pageSize + 1, count).ToList());
remaining -= count;
pageNum++;
}
return pages;
}
///
/// 模拟分页(带数据)
///
private List> SimulatePaginationWithData(List data, int pageSize)
{
var pages = new List>();
for (int i = 0; i < data.Count; i += pageSize)
{
pages.Add(data.Skip(i).Take(pageSize).ToList());
}
return pages;
}
#endregion
}
}