254 lines
11 KiB
C#
254 lines
11 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>
|
|
/// V3 记录保存属性测试
|
|
/// **Feature: work-camera-2.0, Property 3: V3 Record Save Integrity**
|
|
/// **Validates: Requirements 3.1, 3.4**
|
|
/// </summary>
|
|
public class V3RecordSavePropertyTests : IClassFixture<TestFixture>
|
|
{
|
|
private const string ValidCosDomain = "https://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com";
|
|
private const string ValidPrefix = "workfiles";
|
|
|
|
public V3RecordSavePropertyTests(TestFixture fixture)
|
|
{
|
|
// 确保配置已初始化
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成有效的COS URL
|
|
/// </summary>
|
|
private static string GenerateValidCosUrl(int year, int month, int day, string category, int timestampPart, int random, string ext)
|
|
{
|
|
return $"{ValidCosDomain}/{ValidPrefix}/{year:D4}{month:D2}/{year:D4}{month:D2}{day:D2}/{category}/{timestampPart}_{random}{ext}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: V3 Record Save Integrity - Input Validation
|
|
///
|
|
/// *For any* valid V3 save request with N image URLs (1-15), the system SHALL:
|
|
/// - Accept the request when all URLs are valid COS URLs
|
|
/// - The image count in the request equals N
|
|
///
|
|
/// **Validates: Requirements 3.1, 3.4**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public Property ValidV3Request_HasCorrectImageCount()
|
|
{
|
|
// Generate valid V3 requests
|
|
var requestGen = from imageCount in Gen.Choose(1, 15)
|
|
from workerCount in Gen.Choose(1, 5)
|
|
from deptName in Gen.Elements("技术部", "市场部", "财务部", "人事部", "运营部")
|
|
from content in Gen.Elements("设备检修", "日常巡检", "故障处理", "安装调试", "维护保养")
|
|
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, year, month, day };
|
|
|
|
return Prop.ForAll(
|
|
requestGen.ToArbitrary(),
|
|
req =>
|
|
{
|
|
// Generate unique worker names
|
|
var allWorkers = new[] { "张三", "李四", "王五", "赵六", "钱七" };
|
|
var workers = allWorkers.Take(req.workerCount).ToList();
|
|
|
|
// Generate valid COS URLs
|
|
var imageUrls = new List<string>();
|
|
for (int i = 0; i < req.imageCount; i++)
|
|
{
|
|
var url = GenerateValidCosUrl(req.year, req.month, req.day, "当日照片", 100000 + i, 1000 + i, ".jpg");
|
|
imageUrls.Add(url);
|
|
}
|
|
|
|
var dto = new CamRecordWorkV3Dto
|
|
{
|
|
DeptName = req.deptName,
|
|
Content = req.content,
|
|
RecordTime = new DateTime(req.year, req.month, req.day, 10, 30, 0),
|
|
Workers = workers,
|
|
ImageUrls = imageUrls,
|
|
Longitude = "121.4737",
|
|
Latitude = "31.2304",
|
|
Address = "上海市浦东新区",
|
|
StatusName = "正常"
|
|
};
|
|
|
|
// Verify: Image count matches
|
|
if (dto.ImageUrls.Count != req.imageCount)
|
|
return false.Label($"Expected {req.imageCount} images, got {dto.ImageUrls.Count}");
|
|
|
|
// Verify: All URLs are valid COS URLs
|
|
foreach (var url in dto.ImageUrls)
|
|
{
|
|
if (!CosService.IsValidCosUrl(url))
|
|
return false.Label($"Invalid COS URL: {url}");
|
|
}
|
|
|
|
// Verify: Workers count matches
|
|
if (dto.Workers.Count != req.workerCount)
|
|
return false.Label($"Expected {req.workerCount} workers, got {dto.Workers.Count}");
|
|
|
|
return true.Label("All assertions passed");
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: V3 Record Save Integrity - URL Validation Consistency
|
|
///
|
|
/// *For any* V3 save request, all image URLs must pass COS validation.
|
|
/// If any URL is invalid, the entire request should be rejected.
|
|
///
|
|
/// **Validates: Requirements 3.1, 3.4**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public Property AllImageUrls_MustBeValidCosUrls()
|
|
{
|
|
// Generate requests with valid COS URLs
|
|
var requestGen = from imageCount in Gen.Choose(1, 15)
|
|
from year in Gen.Choose(2020, 2030)
|
|
from month in Gen.Choose(1, 12)
|
|
from day in Gen.Choose(1, 28)
|
|
from category in Gen.Elements("当日照片", "参与人员/张三", "工作内容/设备检修", "部门/技术部")
|
|
select new { imageCount, year, month, day, category };
|
|
|
|
return Prop.ForAll(
|
|
requestGen.ToArbitrary(),
|
|
req =>
|
|
{
|
|
// Generate valid COS URLs
|
|
var imageUrls = new List<string>();
|
|
for (int i = 0; i < req.imageCount; i++)
|
|
{
|
|
var url = GenerateValidCosUrl(req.year, req.month, req.day, req.category, 100000 + i, 1000 + i, ".jpg");
|
|
imageUrls.Add(url);
|
|
}
|
|
|
|
// Verify: All URLs pass validation
|
|
var allValid = imageUrls.All(url => CosService.IsValidCosUrl(url));
|
|
|
|
return allValid.Label($"All {req.imageCount} URLs should be valid COS URLs");
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: V3 Record Save Integrity - Image Count Limit
|
|
///
|
|
/// *For any* V3 save request, the image count must be between 1 and 15.
|
|
///
|
|
/// **Validates: Requirements 3.1, 3.4**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public Property ImageCount_MustBeWithinLimit()
|
|
{
|
|
// Generate image counts within valid range
|
|
var countGen = Gen.Choose(1, 15);
|
|
|
|
return Prop.ForAll(
|
|
countGen.ToArbitrary(),
|
|
imageCount =>
|
|
{
|
|
// Verify: Count is within valid range
|
|
var isValid = imageCount >= 1 && imageCount <= 15;
|
|
|
|
return isValid.Label($"Image count {imageCount} should be within 1-15 range");
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: V3 Record Save Integrity - Request with Invalid URLs Rejected
|
|
///
|
|
/// *For any* V3 save request containing at least one invalid URL,
|
|
/// the validation should fail.
|
|
///
|
|
/// **Validates: Requirements 3.1, 3.4**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public Property RequestWithInvalidUrl_ShouldFailValidation()
|
|
{
|
|
// Generate requests with one invalid URL mixed in
|
|
var requestGen = from validCount in Gen.Choose(1, 10)
|
|
from invalidDomain in Gen.Elements(
|
|
"https://other-bucket.cos.ap-shanghai.myqcloud.com",
|
|
"https://example.com",
|
|
"http://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com")
|
|
from year in Gen.Choose(2020, 2030)
|
|
from month in Gen.Choose(1, 12)
|
|
from day in Gen.Choose(1, 28)
|
|
select new { validCount, invalidDomain, year, month, day };
|
|
|
|
return Prop.ForAll(
|
|
requestGen.ToArbitrary(),
|
|
req =>
|
|
{
|
|
// Generate valid COS URLs
|
|
var imageUrls = new List<string>();
|
|
for (int i = 0; i < req.validCount; i++)
|
|
{
|
|
var url = GenerateValidCosUrl(req.year, req.month, req.day, "当日照片", 100000 + i, 1000 + i, ".jpg");
|
|
imageUrls.Add(url);
|
|
}
|
|
|
|
// Add one invalid URL
|
|
var invalidUrl = $"{req.invalidDomain}/workfiles/{req.year:D4}{req.month:D2}/{req.year:D4}{req.month:D2}{req.day:D2}/当日照片/test.jpg";
|
|
imageUrls.Add(invalidUrl);
|
|
|
|
// Verify: At least one URL fails validation
|
|
var hasInvalidUrl = imageUrls.Any(url => !CosService.IsValidCosUrl(url));
|
|
|
|
return hasInvalidUrl.Label("Request with invalid URL should fail validation");
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property 3: V3 Record Save Integrity - First Image as Cover
|
|
///
|
|
/// *For any* valid V3 save request with N images, the first image URL
|
|
/// should be used as the cover image (ImageUrl field in work record).
|
|
///
|
|
/// **Validates: Requirements 3.1, 3.4**
|
|
/// </summary>
|
|
[Property(MaxTest = 100)]
|
|
public Property FirstImage_ShouldBeCoverImage()
|
|
{
|
|
// Generate requests with multiple images
|
|
var requestGen = from imageCount in Gen.Choose(1, 15)
|
|
from year in Gen.Choose(2020, 2030)
|
|
from month in Gen.Choose(1, 12)
|
|
from day in Gen.Choose(1, 28)
|
|
select new { imageCount, year, month, day };
|
|
|
|
return Prop.ForAll(
|
|
requestGen.ToArbitrary(),
|
|
req =>
|
|
{
|
|
// Generate valid COS URLs
|
|
var imageUrls = new List<string>();
|
|
for (int i = 0; i < req.imageCount; i++)
|
|
{
|
|
var url = GenerateValidCosUrl(req.year, req.month, req.day, "当日照片", 100000 + i, 1000 + i, ".jpg");
|
|
imageUrls.Add(url);
|
|
}
|
|
|
|
// Verify: First URL exists and is valid
|
|
var firstUrl = imageUrls.FirstOrDefault();
|
|
if (string.IsNullOrEmpty(firstUrl))
|
|
return false.Label("First URL should not be empty");
|
|
|
|
if (!CosService.IsValidCosUrl(firstUrl))
|
|
return false.Label("First URL should be a valid COS URL");
|
|
|
|
return true.Label("First image can be used as cover image");
|
|
});
|
|
}
|
|
}
|
|
}
|