WorkCamera/server/Zr.Admin.NET/ZR.Tests/CosUrlValidationPropertyTests.cs
2026-01-05 21:20:55 +08:00

142 lines
5.8 KiB
C#

using FsCheck;
using FsCheck.Xunit;
using Infrastructure;
using Microsoft.Extensions.Configuration;
using Xunit;
using ZR.Common;
namespace ZR.Tests
{
/// <summary>
/// COS URL 验证属性测试
/// **Feature: work-camera-2.0, Property 2: COS URL Validation**
/// **Validates: Requirements 3.3**
/// </summary>
public class CosUrlValidationPropertyTests : IClassFixture<TestFixture>
{
private const string ValidCosDomain = "https://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com";
private const string ValidPrefix = "workfiles";
public CosUrlValidationPropertyTests(TestFixture fixture)
{
// 确保配置已初始化
}
/// <summary>
/// Property 2: COS URL Validation
///
/// *For any* URL submitted to the V3 interface, the system SHALL accept only URLs matching
/// the COS domain pattern `https://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com/workfiles/...`
/// and reject all other URLs.
///
/// **Validates: Requirements 3.3**
/// </summary>
[Property(MaxTest = 100)]
public Property ValidCosUrls_AreAccepted()
{
// Generate valid COS URLs
var validUrlGen = 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("当日照片", "参与人员/张三", "工作内容/设备检修", "部门/技术部")
from timestampPart in Gen.Choose(100000, 999999)
from random in Gen.Choose(1000, 9999)
from ext in Gen.Elements(".jpg", ".png", ".jpeg")
select $"{ValidCosDomain}/{ValidPrefix}/{year:D4}{month:D2}/{year:D4}{month:D2}{day:D2}/{category}/{timestampPart}_{random}{ext}";
return Prop.ForAll(
validUrlGen.ToArbitrary(),
url =>
{
var result = CosService.IsValidCosUrl(url);
return result.Label($"Valid COS URL should be accepted: {url}");
});
}
/// <summary>
/// Property 2: COS URL Validation - Invalid domain URLs are rejected
///
/// *For any* URL with a different domain, the system SHALL reject it.
///
/// **Validates: Requirements 3.3**
/// </summary>
[Property(MaxTest = 100)]
public Property InvalidDomainUrls_AreRejected()
{
// Generate URLs with invalid domains
var invalidDomainGen = from domain in Gen.Elements(
"https://other-bucket.cos.ap-shanghai.myqcloud.com",
"https://example.com",
"http://miaoyu-1308826010.cos.ap-shanghai.myqcloud.com", // http instead of https
"https://miaoyu.cos.ap-shanghai.myqcloud.com",
"https://localhost:8080",
"https://192.168.1.1")
from path in Gen.Elements(
"/workfiles/202501/20250105/当日照片/test.jpg",
"/files/image.png",
"/test.jpg")
select domain + path;
return Prop.ForAll(
invalidDomainGen.ToArbitrary(),
url =>
{
var result = CosService.IsValidCosUrl(url);
return (!result).Label($"Invalid domain URL should be rejected: {url}");
});
}
/// <summary>
/// Property 2: COS URL Validation - Invalid prefix URLs are rejected
///
/// *For any* URL with the correct domain but wrong prefix, the system SHALL reject it.
///
/// **Validates: Requirements 3.3**
/// </summary>
[Property(MaxTest = 100)]
public Property InvalidPrefixUrls_AreRejected()
{
// Generate URLs with invalid prefixes
var invalidPrefixGen = from prefix in Gen.Elements(
"files",
"images",
"uploads",
"data",
"work",
"workfile") // missing 's'
from path in Gen.Elements(
"/202501/20250105/当日照片/test.jpg",
"/test.jpg")
select $"{ValidCosDomain}/{prefix}{path}";
return Prop.ForAll(
invalidPrefixGen.ToArbitrary(),
url =>
{
var result = CosService.IsValidCosUrl(url);
return (!result).Label($"Invalid prefix URL should be rejected: {url}");
});
}
/// <summary>
/// Property 2: COS URL Validation - Empty and null URLs are rejected
///
/// **Validates: Requirements 3.3**
/// </summary>
[Property(MaxTest = 100)]
public Property EmptyOrWhitespaceUrls_AreRejected()
{
// Generate empty or whitespace strings
var emptyGen = Gen.Elements("", " ", " ", "\t", "\n", "\r\n", " ");
return Prop.ForAll(
emptyGen.ToArbitrary(),
url =>
{
var result = CosService.IsValidCosUrl(url);
return (!result).Label($"Empty/whitespace URL should be rejected");
});
}
}
}