164 lines
8.3 KiB
C#
164 lines
8.3 KiB
C#
using FsCheck;
|
|
using FsCheck.Xunit;
|
|
using Infrastructure;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Xunit;
|
|
using ZR.Common;
|
|
using ZR.Model.Business.Dto;
|
|
|
|
namespace ZR.Tests
|
|
{
|
|
/// <summary>
|
|
/// CosService 属性测试
|
|
/// **Feature: work-camera-2.0, Property 1: Pre-signed URL Generation Completeness**
|
|
/// **Validates: Requirements 1.1, 1.2, 1.4, 1.5**
|
|
/// </summary>
|
|
public class CosServicePropertyTests : IClassFixture<TestFixture>
|
|
{
|
|
public CosServicePropertyTests(TestFixture fixture)
|
|
{
|
|
// 确保配置已初始化
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 1: Pre-signed URL Generation Completeness
|
|
///
|
|
/// *For any* valid upload request with N images and M workers, the API SHALL return exactly N image entries, each containing:
|
|
/// - 1 daily photo URL
|
|
/// - M worker directory URLs (one per worker)
|
|
/// - 1 content directory URL
|
|
/// - 1 department directory URL
|
|
/// - All URLs following the pattern `/workfiles/{yyyyMM}/{yyyyMMdd}/{category}/{subcategory}/{timestamp}_{random}.{ext}`
|
|
///
|
|
/// **Validates: Requirements 1.1, 1.2, 1.4, 1.5**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public Property UrlGenerationCompleteness_ReturnsCorrectStructure()
|
|
{
|
|
// Generate valid inputs using a combined generator
|
|
var requestGen = from imageCount in Gen.Choose(1, 15)
|
|
from workerCount in Gen.Choose(1, 10)
|
|
from deptName in Gen.Elements("技术部", "市场部", "财务部", "人事部", "运营部")
|
|
from content in Gen.Elements("设备检修", "日常巡检", "故障处理", "安装调试", "维护保养")
|
|
from fileExt in Gen.Elements(".jpg", ".png", ".jpeg")
|
|
from year in Gen.Choose(2020, 2030)
|
|
from month in Gen.Choose(1, 12)
|
|
from day in Gen.Choose(1, 28)
|
|
select new { imageCount, workerCount, deptName, content, fileExt, year, month, day };
|
|
|
|
return Prop.ForAll(
|
|
requestGen.ToArbitrary(),
|
|
req =>
|
|
{
|
|
// Generate unique worker names
|
|
var allWorkers = new[] { "张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", "郑一", "冯二" };
|
|
var workers = allWorkers.Take(req.workerCount).ToList();
|
|
|
|
var recordTime = new DateTime(req.year, req.month, req.day, 10, 30, 0);
|
|
var request = new CosUploadUrlsRequest
|
|
{
|
|
RecordTime = recordTime,
|
|
DeptName = req.deptName,
|
|
Content = req.content,
|
|
Workers = workers,
|
|
FileExt = req.fileExt,
|
|
ImageCount = req.imageCount
|
|
};
|
|
|
|
// Act
|
|
var response = CosService.GetUploadUrls(request);
|
|
|
|
// Assert: Response should not be null
|
|
if (response == null || response.Images == null)
|
|
return false.Label("Response or Images is null");
|
|
|
|
// Assert: Should return exactly N images
|
|
if (response.Images.Count != req.imageCount)
|
|
return false.Label($"Expected {req.imageCount} images, got {response.Images.Count}");
|
|
|
|
// Expected date path format
|
|
var expectedDatePath = $"/workfiles/{recordTime:yyyyMM}/{recordTime:yyyyMMdd}/";
|
|
|
|
foreach (var image in response.Images)
|
|
{
|
|
// Assert: Each image should have ImageId
|
|
if (string.IsNullOrEmpty(image.ImageId))
|
|
return false.Label("ImageId is null or empty");
|
|
|
|
// Assert: Each image should have FileName with correct extension
|
|
if (string.IsNullOrEmpty(image.FileName) || !image.FileName.EndsWith(req.fileExt))
|
|
return false.Label($"FileName is invalid or doesn't end with {req.fileExt}");
|
|
|
|
// Assert: FileName should follow timestamp_random format
|
|
if (!image.FileName.Contains("_"))
|
|
return false.Label("FileName doesn't follow timestamp_random format");
|
|
|
|
// Assert: Each image should have AccessUrl
|
|
if (string.IsNullOrEmpty(image.AccessUrl))
|
|
return false.Label("AccessUrl is null or empty");
|
|
|
|
// Assert: AccessUrl should contain correct date path
|
|
if (!image.AccessUrl.Contains(expectedDatePath))
|
|
return false.Label($"AccessUrl doesn't contain expected date path: {expectedDatePath}");
|
|
|
|
// Assert: AccessUrl should contain 当日照片 category
|
|
if (!image.AccessUrl.Contains("/当日照片/"))
|
|
return false.Label("AccessUrl doesn't contain /当日照片/");
|
|
|
|
// Assert: UploadUrls should not be null
|
|
if (image.UploadUrls == null)
|
|
return false.Label("UploadUrls is null");
|
|
|
|
// Assert: Should have 1 daily photo URL
|
|
if (string.IsNullOrEmpty(image.UploadUrls.Daily))
|
|
return false.Label("Daily URL is null or empty");
|
|
|
|
// Assert: Daily URL should contain correct path
|
|
if (!image.UploadUrls.Daily.Contains(expectedDatePath) || !image.UploadUrls.Daily.Contains("当日照片"))
|
|
return false.Label("Daily URL doesn't contain expected path");
|
|
|
|
// Assert: Should have 1 content directory URL
|
|
if (string.IsNullOrEmpty(image.UploadUrls.Content))
|
|
return false.Label("Content URL is null or empty");
|
|
|
|
// Assert: Content URL should contain correct path
|
|
if (!image.UploadUrls.Content.Contains(expectedDatePath) || !image.UploadUrls.Content.Contains("工作内容"))
|
|
return false.Label("Content URL doesn't contain expected path");
|
|
|
|
// Assert: Should have 1 department directory URL
|
|
if (string.IsNullOrEmpty(image.UploadUrls.Dept))
|
|
return false.Label("Dept URL is null or empty");
|
|
|
|
// Assert: Dept URL should contain correct path
|
|
if (!image.UploadUrls.Dept.Contains(expectedDatePath) || !image.UploadUrls.Dept.Contains("部门"))
|
|
return false.Label("Dept URL doesn't contain expected path");
|
|
|
|
// Assert: Should have M worker directory URLs
|
|
if (image.UploadUrls.Workers == null)
|
|
return false.Label("Workers URLs dictionary is null");
|
|
|
|
if (image.UploadUrls.Workers.Count != req.workerCount)
|
|
return false.Label($"Expected {req.workerCount} worker URLs, got {image.UploadUrls.Workers.Count}");
|
|
|
|
// Assert: Each worker should have a URL
|
|
foreach (var worker in workers)
|
|
{
|
|
if (!image.UploadUrls.Workers.ContainsKey(worker))
|
|
return false.Label($"Missing URL for worker: {worker}");
|
|
|
|
var workerUrl = image.UploadUrls.Workers[worker];
|
|
if (string.IsNullOrEmpty(workerUrl))
|
|
return false.Label($"Worker URL is null or empty for: {worker}");
|
|
|
|
// Assert: Worker URL should contain correct path
|
|
if (!workerUrl.Contains(expectedDatePath) || !workerUrl.Contains("参与人员"))
|
|
return false.Label($"Worker URL doesn't contain expected path for: {worker}");
|
|
}
|
|
}
|
|
|
|
return true.Label("All assertions passed");
|
|
});
|
|
}
|
|
}
|
|
}
|