209 lines
7.7 KiB
C#
209 lines
7.7 KiB
C#
using FsCheck;
|
||
using FsCheck.Xunit;
|
||
using HoneyBox.Admin.Business.Services;
|
||
using Xunit;
|
||
|
||
namespace HoneyBox.Tests.Services;
|
||
|
||
/// <summary>
|
||
/// UploadService 属性测试
|
||
/// **Validates: Requirements 1.2, 1.3, 1.4, 1.5**
|
||
/// </summary>
|
||
public class UploadServicePropertyTests
|
||
{
|
||
/// <summary>
|
||
/// 允许的图片扩展名
|
||
/// </summary>
|
||
private static readonly string[] AllowedExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".webp" };
|
||
|
||
/// <summary>
|
||
/// 不允许的扩展名示例
|
||
/// </summary>
|
||
private static readonly string[] DisallowedExtensions = { ".txt", ".pdf", ".exe", ".doc", ".html", ".js", ".css", ".zip", ".rar", ".mp4" };
|
||
|
||
#region Property 1: 文件格式验证
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 1: 文件格式验证**
|
||
/// *For any* 上传的文件,如果文件扩展名不在允许列表(jpg, jpeg, png, gif, webp)中,
|
||
/// THE Upload_Service SHALL 返回格式错误。
|
||
/// **Validates: Requirements 1.2, 1.4**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool InvalidExtension_ShouldBeRejected(PositiveInt seed)
|
||
{
|
||
// 从不允许的扩展名中选择一个
|
||
var extension = DisallowedExtensions[seed.Get % DisallowedExtensions.Length];
|
||
|
||
// 验证该扩展名被拒绝
|
||
return !UploadService.IsValidExtension(extension);
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 1: 文件格式验证**
|
||
/// *For any* 允许的图片扩展名,THE Upload_Service SHALL 接受该格式。
|
||
/// **Validates: Requirements 1.4**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool ValidExtension_ShouldBeAccepted(PositiveInt seed)
|
||
{
|
||
// 从允许的扩展名中选择一个
|
||
var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length];
|
||
|
||
// 验证该扩展名被接受
|
||
return UploadService.IsValidExtension(extension);
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 1: 文件格式验证**
|
||
/// *For any* 允许的图片扩展名(大写形式),THE Upload_Service SHALL 接受该格式(大小写不敏感)。
|
||
/// **Validates: Requirements 1.4**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool ValidExtension_CaseInsensitive_ShouldBeAccepted(PositiveInt seed)
|
||
{
|
||
// 从允许的扩展名中选择一个并转为大写
|
||
var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length].ToUpperInvariant();
|
||
|
||
// 验证大写扩展名也被接受
|
||
return UploadService.IsValidExtension(extension);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Property 2: 文件大小验证
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 2: 文件大小验证**
|
||
/// *For any* 上传的文件,如果文件大小超过10MB,THE Upload_Service SHALL 返回大小超限错误。
|
||
/// **Validates: Requirements 1.3**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool FileSizeExceeding10MB_ShouldBeRejected(PositiveInt extraBytes)
|
||
{
|
||
// 10MB + 额外字节
|
||
var maxSize = 10L * 1024 * 1024;
|
||
var fileSize = maxSize + extraBytes.Get;
|
||
|
||
// 验证超过10MB的文件被拒绝
|
||
return !UploadService.IsValidFileSize(fileSize);
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 2: 文件大小验证**
|
||
/// *For any* 文件大小在1字节到10MB之间,THE Upload_Service SHALL 接受该文件。
|
||
/// **Validates: Requirements 1.3**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool FileSizeWithin10MB_ShouldBeAccepted(PositiveInt seed)
|
||
{
|
||
// 生成1字节到10MB之间的文件大小
|
||
var maxSize = 10L * 1024 * 1024;
|
||
var fileSize = (seed.Get % maxSize) + 1; // 确保至少1字节
|
||
|
||
// 验证在范围内的文件被接受
|
||
return UploadService.IsValidFileSize(fileSize);
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 2: 文件大小验证**
|
||
/// *For any* 文件大小为0或负数,THE Upload_Service SHALL 拒绝该文件。
|
||
/// **Validates: Requirements 1.3**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool ZeroOrNegativeFileSize_ShouldBeRejected(NegativeInt negativeSize)
|
||
{
|
||
// 验证0和负数被拒绝
|
||
return !UploadService.IsValidFileSize(0) && !UploadService.IsValidFileSize(negativeSize.Get);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Property 3: 文件名唯一性
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 3: 文件名唯一性**
|
||
/// *For any* 两次上传操作,即使上传相同的文件,生成的文件名 SHALL 不同。
|
||
/// **Validates: Requirements 1.5**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool GeneratedFileNames_ShouldBeUnique(PositiveInt seed)
|
||
{
|
||
// 使用相同的原始文件名
|
||
var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length];
|
||
var originalFileName = $"test_file{extension}";
|
||
|
||
// 生成两个唯一文件名
|
||
var name1 = UploadService.GenerateUniqueFileName(originalFileName);
|
||
var name2 = UploadService.GenerateUniqueFileName(originalFileName);
|
||
|
||
// 验证两个文件名不同
|
||
return name1 != name2;
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 3: 文件名唯一性**
|
||
/// *For any* 原始文件名,生成的唯一文件名 SHALL 保留原始扩展名。
|
||
/// **Validates: Requirements 1.5**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool GeneratedFileName_ShouldPreserveExtension(PositiveInt seed)
|
||
{
|
||
// 选择一个扩展名
|
||
var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length];
|
||
var originalFileName = $"original_file_{seed.Get}{extension}";
|
||
|
||
// 生成唯一文件名
|
||
var uniqueName = UploadService.GenerateUniqueFileName(originalFileName);
|
||
|
||
// 验证扩展名被保留(转为小写)
|
||
return uniqueName.EndsWith(extension.ToLowerInvariant());
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 3: 文件名唯一性**
|
||
/// *For any* 大写扩展名的文件,生成的唯一文件名 SHALL 将扩展名转为小写。
|
||
/// **Validates: Requirements 1.5**
|
||
/// </summary>
|
||
[Property(MaxTest = 100)]
|
||
public bool GeneratedFileName_ShouldNormalizeExtensionToLowercase(PositiveInt seed)
|
||
{
|
||
// 选择一个扩展名并转为大写
|
||
var extension = AllowedExtensions[seed.Get % AllowedExtensions.Length].ToUpperInvariant();
|
||
var originalFileName = $"FILE_{seed.Get}{extension}";
|
||
|
||
// 生成唯一文件名
|
||
var uniqueName = UploadService.GenerateUniqueFileName(originalFileName);
|
||
|
||
// 验证扩展名被转为小写
|
||
return uniqueName.EndsWith(extension.ToLowerInvariant());
|
||
}
|
||
|
||
/// <summary>
|
||
/// **Feature: image-upload-feature, Property 3: 文件名唯一性**
|
||
/// *For any* 多次生成的文件名,所有文件名 SHALL 互不相同。
|
||
/// **Validates: Requirements 1.5**
|
||
/// </summary>
|
||
[Property(MaxTest = 50)]
|
||
public bool MultipleGeneratedFileNames_ShouldAllBeUnique(PositiveInt seed)
|
||
{
|
||
var originalFileName = "test.jpg";
|
||
var generatedNames = new HashSet<string>();
|
||
|
||
// 生成多个文件名
|
||
var count = (seed.Get % 10) + 5; // 5-14个文件名
|
||
for (var i = 0; i < count; i++)
|
||
{
|
||
var name = UploadService.GenerateUniqueFileName(originalFileName);
|
||
if (!generatedNames.Add(name))
|
||
{
|
||
return false; // 发现重复
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
#endregion
|
||
}
|