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 } }