A:增加工具类
This commit is contained in:
1 parent
1c97bfb181
commit
6decd94b1c
42 files changed
+1544
-4787
No files matched your search
@@ -13,7 +13,7 @@ type ExifData map[string]interface{}
|
||||
|
||||
// GetExifData 获取 EXIF 数据
|
||||
func GetExifData(ctx context.Context, input string) (ExifData, error) {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func GetExifData(ctx context.Context, input string) (ExifData, error) {
|
||||
|
||||
// GetExifField 获取特定的 EXIF 字段
|
||||
func GetExifField(ctx context.Context, input string, fields ...string) (map[string]string, error) {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func GetExifField(ctx context.Context, input string, fields ...string) (map[stri
|
||||
|
||||
// RemoveExifData 移除 EXIF 数据
|
||||
func RemoveExifData(ctx context.Context, input string, backup bool) error {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func RemoveExifData(ctx context.Context, input string, backup bool) error {
|
||||
|
||||
// CopyExifData 复制 EXIF 数据从一个文件到另一个文件
|
||||
func CopyExifData(ctx context.Context, source, target string) error {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func CopyExifData(ctx context.Context, source, target string) error {
|
||||
|
||||
// SetExifField 设置 EXIF 字段
|
||||
func SetExifField(ctx context.Context, input string, fields map[string]string) error {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ func SetExifField(ctx context.Context, input string, fields map[string]string) e
|
||||
|
||||
// IsExifToolAvailable 检查 ExifTool 是否可用
|
||||
func IsExifToolAvailable() bool {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return false
|
||||
}
|
||||
return utils.ExifToolPath != ""
|
||||
@@ -141,6 +141,6 @@ func IsExifToolAvailable() bool {
|
||||
|
||||
// GetToolPaths 获取工具路径(用于调试)
|
||||
func GetToolPaths() (imageMagick, exifTool string) {
|
||||
utils.EnsureInitialized()
|
||||
utils.EnsureInitialized(nil, nil)
|
||||
return utils.ImageMagickPath, utils.ExifToolPath
|
||||
}
|
||||
@@ -0,0 +1,623 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 测试用的图片文件路径
|
||||
var testImages = []string{
|
||||
"../../img/cyberpunk2077_world_third@3x.webp",
|
||||
"../../img/image-1.JPG",
|
||||
"../../img/image-1-1.JPG",
|
||||
"../../img/image-2.JPG",
|
||||
"../../img/image-3.JPG",
|
||||
"../../img/image-4.JPG",
|
||||
"../../img/Snipaste_2022-12-17_20-13-15.png",
|
||||
}
|
||||
|
||||
// TestIsExifToolAvailable 测试ExifTool是否可用
|
||||
func TestIsExifToolAvailable(t *testing.T) {
|
||||
available := IsExifToolAvailable()
|
||||
if !available {
|
||||
t.Skip("ExifTool not available, skipping EXIF tests")
|
||||
}
|
||||
t.Logf("ExifTool is available")
|
||||
}
|
||||
|
||||
// TestGetToolPaths 测试获取工具路径
|
||||
func TestGetToolPaths(t *testing.T) {
|
||||
imageMagick, exifTool := GetToolPaths()
|
||||
t.Logf("ImageMagick path: %s", imageMagick)
|
||||
t.Logf("ExifTool path: %s", exifTool)
|
||||
|
||||
if exifTool == "" {
|
||||
t.Skip("ExifTool path is empty, skipping remaining tests")
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetExifData 测试获取EXIF数据
|
||||
func TestGetExifData(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
for _, imgPath := range testImages {
|
||||
t.Run(filepath.Base(imgPath), func(t *testing.T) {
|
||||
// 检查文件是否存在
|
||||
if _, err := os.Stat(imgPath); os.IsNotExist(err) {
|
||||
t.Skipf("Test image %s does not exist", imgPath)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := GetExifData(ctx, imgPath)
|
||||
if err != nil {
|
||||
t.Logf("Warning: Failed to get EXIF data for %s: %v", imgPath, err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
t.Logf("No EXIF data found for %s", imgPath)
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("EXIF data for %s:", imgPath)
|
||||
for key, value := range data {
|
||||
t.Logf(" %s: %v", key, value)
|
||||
}
|
||||
|
||||
// 验证常见的EXIF字段
|
||||
commonFields := []string{"FileName", "FileSize", "ImageWidth", "ImageHeight"}
|
||||
for _, field := range commonFields {
|
||||
if _, exists := data[field]; exists {
|
||||
t.Logf("Found expected field: %s", field)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetExifDataWithInvalidFile 测试无效文件的情况
|
||||
func TestGetExifDataWithInvalidFile(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 测试不存在的文件
|
||||
_, err := GetExifData(ctx, "nonexistent.jpg")
|
||||
if err == nil {
|
||||
t.Error("Expected error for nonexistent file, but got nil")
|
||||
}
|
||||
t.Logf("Expected error for nonexistent file: %v", err)
|
||||
|
||||
// 测试空路径
|
||||
_, err = GetExifData(ctx, "")
|
||||
if err == nil {
|
||||
t.Error("Expected error for empty path, but got nil")
|
||||
}
|
||||
t.Logf("Expected error for empty path: %v", err)
|
||||
}
|
||||
|
||||
// TestGetExifField 测试获取特定EXIF字段
|
||||
func TestGetExifField(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 找一个存在的图片文件进行测试
|
||||
var testImg string
|
||||
for _, imgPath := range testImages {
|
||||
if _, err := os.Stat(imgPath); err == nil {
|
||||
testImg = imgPath
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if testImg == "" {
|
||||
t.Skip("No test images available")
|
||||
}
|
||||
|
||||
t.Run("SingleField", func(t *testing.T) {
|
||||
fields, err := GetExifField(ctx, testImg, "ImageWidth")
|
||||
if err != nil {
|
||||
t.Logf("Failed to get single field: %v", err)
|
||||
return
|
||||
}
|
||||
t.Logf("Single field result: %+v", fields)
|
||||
})
|
||||
|
||||
t.Run("MultipleFields", func(t *testing.T) {
|
||||
fields, err := GetExifField(ctx, testImg, "ImageWidth", "ImageHeight", "FileSize")
|
||||
if err != nil {
|
||||
t.Logf("Failed to get multiple fields: %v", err)
|
||||
return
|
||||
}
|
||||
t.Logf("Multiple fields result: %+v", fields)
|
||||
})
|
||||
|
||||
t.Run("NonexistentField", func(t *testing.T) {
|
||||
fields, err := GetExifField(ctx, testImg, "NonexistentField")
|
||||
if err != nil {
|
||||
t.Logf("Error getting nonexistent field (expected): %v", err)
|
||||
} else {
|
||||
t.Logf("Nonexistent field result: %+v", fields)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestRemoveExifData 测试移除EXIF数据
|
||||
func TestRemoveExifData(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 找一个JPEG文件作为测试目标(因为JPEG通常有EXIF数据)
|
||||
var testImg string
|
||||
for _, imgPath := range testImages {
|
||||
if _, err := os.Stat(imgPath); err == nil && filepath.Ext(imgPath) == ".JPG" {
|
||||
testImg = imgPath
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if testImg == "" {
|
||||
t.Skip("No JPEG test images available")
|
||||
}
|
||||
|
||||
// 创建测试文件的副本
|
||||
tempFile := filepath.Join(os.TempDir(), "test_remove_exif.jpg")
|
||||
defer os.Remove(tempFile)
|
||||
|
||||
// 复制原文件
|
||||
if err := copyFile(testImg, tempFile); err != nil {
|
||||
t.Fatalf("Failed to create test file copy: %v", err)
|
||||
}
|
||||
|
||||
t.Run("RemoveWithBackup", func(t *testing.T) {
|
||||
// 获取移除前的EXIF数据
|
||||
beforeData, err := GetExifData(ctx, tempFile)
|
||||
if err != nil {
|
||||
t.Logf("No EXIF data before removal: %v", err)
|
||||
} else {
|
||||
t.Logf("EXIF data before removal: %d fields", len(beforeData))
|
||||
}
|
||||
|
||||
// 移除EXIF数据(保留备份)
|
||||
err = RemoveExifData(ctx, tempFile, true)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to remove EXIF data with backup: %v", err)
|
||||
}
|
||||
|
||||
// 检查备份文件是否存在
|
||||
backupFile := tempFile + "_original"
|
||||
if _, err := os.Stat(backupFile); err == nil {
|
||||
defer os.Remove(backupFile)
|
||||
t.Logf("Backup file created successfully")
|
||||
}
|
||||
|
||||
// 获取移除后的EXIF数据
|
||||
afterData, err := GetExifData(ctx, tempFile)
|
||||
if err != nil {
|
||||
t.Logf("No EXIF data after removal (expected): %v", err)
|
||||
} else {
|
||||
t.Logf("EXIF data after removal: %d fields", len(afterData))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RemoveWithoutBackup", func(t *testing.T) {
|
||||
// 重新创建测试文件
|
||||
if err := copyFile(testImg, tempFile); err != nil {
|
||||
t.Fatalf("Failed to recreate test file: %v", err)
|
||||
}
|
||||
|
||||
// 移除EXIF数据(不保留备份)
|
||||
err := RemoveExifData(ctx, tempFile, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to remove EXIF data without backup: %v", err)
|
||||
}
|
||||
|
||||
// 检查备份文件不存在
|
||||
backupFile := tempFile + "_original"
|
||||
if _, err := os.Stat(backupFile); err == nil {
|
||||
t.Error("Backup file should not exist when backup=false")
|
||||
os.Remove(backupFile)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("RemoveFromNonexistentFile", func(t *testing.T) {
|
||||
err := RemoveExifData(ctx, "nonexistent.jpg", false)
|
||||
if err == nil {
|
||||
t.Error("Expected error for nonexistent file, but got nil")
|
||||
}
|
||||
t.Logf("Expected error for nonexistent file: %v", err)
|
||||
})
|
||||
}
|
||||
|
||||
// TestCopyExifData 测试复制EXIF数据
|
||||
func TestCopyExifData(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 找两个不同的图片文件
|
||||
var sourceImg, targetImg string
|
||||
jpegCount := 0
|
||||
for _, imgPath := range testImages {
|
||||
if _, err := os.Stat(imgPath); err == nil {
|
||||
if filepath.Ext(imgPath) == ".JPG" {
|
||||
jpegCount++
|
||||
if sourceImg == "" {
|
||||
sourceImg = imgPath
|
||||
} else if targetImg == "" && imgPath != sourceImg {
|
||||
targetImg = imgPath
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sourceImg == "" || targetImg == "" {
|
||||
t.Skip("Need at least 2 JPEG test images")
|
||||
}
|
||||
|
||||
// 创建目标文件的副本
|
||||
tempTarget := filepath.Join(os.TempDir(), "test_copy_target.jpg")
|
||||
defer os.Remove(tempTarget)
|
||||
|
||||
if err := copyFile(targetImg, tempTarget); err != nil {
|
||||
t.Fatalf("Failed to create target file copy: %v", err)
|
||||
}
|
||||
|
||||
t.Run("CopyValidFiles", func(t *testing.T) {
|
||||
// 获取源文件的EXIF数据
|
||||
sourceData, err := GetExifData(ctx, sourceImg)
|
||||
if err != nil {
|
||||
t.Logf("No EXIF data in source file: %v", err)
|
||||
}
|
||||
|
||||
// 复制EXIF数据
|
||||
err = CopyExifData(ctx, sourceImg, tempTarget)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to copy EXIF data: %v", err)
|
||||
}
|
||||
|
||||
// 获取目标文件的EXIF数据
|
||||
targetData, err := GetExifData(ctx, tempTarget)
|
||||
if err != nil {
|
||||
t.Logf("No EXIF data in target file after copy: %v", err)
|
||||
} else {
|
||||
t.Logf("Successfully copied EXIF data, target now has %d fields", len(targetData))
|
||||
|
||||
// 比较一些关键字段
|
||||
if sourceData != nil {
|
||||
for _, field := range []string{"Make", "Model", "DateTime"} {
|
||||
if sourceVal, exists := sourceData[field]; exists {
|
||||
if targetVal, exists := targetData[field]; exists {
|
||||
if reflect.DeepEqual(sourceVal, targetVal) {
|
||||
t.Logf("Field %s copied correctly: %v", field, sourceVal)
|
||||
} else {
|
||||
t.Logf("Field %s differs: source=%v, target=%v", field, sourceVal, targetVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CopyFromNonexistentSource", func(t *testing.T) {
|
||||
err := CopyExifData(ctx, "nonexistent.jpg", tempTarget)
|
||||
if err == nil {
|
||||
t.Error("Expected error for nonexistent source file, but got nil")
|
||||
}
|
||||
t.Logf("Expected error for nonexistent source: %v", err)
|
||||
})
|
||||
|
||||
t.Run("CopyToNonexistentTarget", func(t *testing.T) {
|
||||
err := CopyExifData(ctx, sourceImg, "nonexistent.jpg")
|
||||
if err == nil {
|
||||
t.Error("Expected error for nonexistent target file, but got nil")
|
||||
}
|
||||
t.Logf("Expected error for nonexistent target: %v", err)
|
||||
})
|
||||
}
|
||||
|
||||
// TestSetExifField 测试设置EXIF字段
|
||||
func TestSetExifField(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// 找一个JPEG文件作为测试目标
|
||||
var testImg string
|
||||
for _, imgPath := range testImages {
|
||||
if _, err := os.Stat(imgPath); err == nil && filepath.Ext(imgPath) == ".JPG" {
|
||||
testImg = imgPath
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if testImg == "" {
|
||||
t.Skip("No JPEG test images available")
|
||||
}
|
||||
|
||||
// 创建测试文件的副本
|
||||
tempFile := filepath.Join(os.TempDir(), "test_set_exif.jpg")
|
||||
defer os.Remove(tempFile)
|
||||
|
||||
if err := copyFile(testImg, tempFile); err != nil {
|
||||
t.Fatalf("Failed to create test file copy: %v", err)
|
||||
}
|
||||
|
||||
t.Run("SetSingleField", func(t *testing.T) {
|
||||
fields := map[string]string{
|
||||
"Artist": "Test Artist",
|
||||
}
|
||||
|
||||
err := SetExifField(ctx, tempFile, fields)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set single field: %v", err)
|
||||
}
|
||||
|
||||
// 验证字段是否设置成功
|
||||
data, err := GetExifData(ctx, tempFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get EXIF data after setting: %v", err)
|
||||
}
|
||||
|
||||
if artist, exists := data["Artist"]; exists {
|
||||
t.Logf("Artist field set successfully: %v", artist)
|
||||
} else {
|
||||
t.Error("Artist field not found after setting")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SetMultipleFields", func(t *testing.T) {
|
||||
currentTime := time.Now().Format("2006:01:02 15:04:05")
|
||||
fields := map[string]string{
|
||||
"Artist": "Test Artist Updated",
|
||||
"Comment": "Test Comment",
|
||||
"DateTime": currentTime,
|
||||
}
|
||||
|
||||
err := SetExifField(ctx, tempFile, fields)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set multiple fields: %v", err)
|
||||
}
|
||||
|
||||
// 验证字段是否设置成功
|
||||
data, err := GetExifData(ctx, tempFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get EXIF data after setting: %v", err)
|
||||
}
|
||||
|
||||
for key, _ := range fields {
|
||||
if actualValue, exists := data[key]; exists {
|
||||
t.Logf("Field %s set successfully: %v", key, actualValue)
|
||||
} else {
|
||||
t.Errorf("Field %s not found after setting", key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SetFieldWithSpecialCharacters", func(t *testing.T) {
|
||||
fields := map[string]string{
|
||||
"Comment": "测试中文注释 & Special chars: !@#$%",
|
||||
}
|
||||
|
||||
err := SetExifField(ctx, tempFile, fields)
|
||||
if err != nil {
|
||||
t.Logf("Failed to set field with special characters (may be expected): %v", err)
|
||||
} else {
|
||||
t.Logf("Successfully set field with special characters")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("SetFieldOnNonexistentFile", func(t *testing.T) {
|
||||
fields := map[string]string{
|
||||
"Artist": "Test Artist",
|
||||
}
|
||||
|
||||
err := SetExifField(ctx, "nonexistent.jpg", fields)
|
||||
if err == nil {
|
||||
t.Error("Expected error for nonexistent file, but got nil")
|
||||
}
|
||||
t.Logf("Expected error for nonexistent file: %v", err)
|
||||
})
|
||||
}
|
||||
|
||||
// TestContextCancellation 测试上下文取消
|
||||
func TestContextCancellation(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
// 找一个存在的图片文件
|
||||
var testImg string
|
||||
for _, imgPath := range testImages {
|
||||
if _, err := os.Stat(imgPath); err == nil {
|
||||
testImg = imgPath
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if testImg == "" {
|
||||
t.Skip("No test images available")
|
||||
}
|
||||
|
||||
t.Run("CancelledContext", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel() // 立即取消上下文
|
||||
|
||||
_, err := GetExifData(ctx, testImg)
|
||||
if err != nil {
|
||||
t.Logf("Operation correctly failed with cancelled context: %v", err)
|
||||
} else {
|
||||
t.Log("Operation completed despite cancelled context")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("TimeoutContext", func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
_, err := GetExifData(ctx, testImg)
|
||||
if err != nil {
|
||||
t.Logf("Operation correctly failed with timeout context: %v", err)
|
||||
} else {
|
||||
t.Log("Operation completed within timeout")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TestDifferentImageFormats 测试不同图片格式
|
||||
func TestDifferentImageFormats(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
formatTests := map[string][]string{
|
||||
"JPEG": {".JPG", ".jpg", ".jpeg"},
|
||||
"PNG": {".PNG", ".png"},
|
||||
"WEBP": {".webp"},
|
||||
}
|
||||
|
||||
for format, extensions := range formatTests {
|
||||
t.Run(format, func(t *testing.T) {
|
||||
found := false
|
||||
for _, imgPath := range testImages {
|
||||
ext := filepath.Ext(imgPath)
|
||||
for _, validExt := range extensions {
|
||||
if ext == validExt {
|
||||
if _, err := os.Stat(imgPath); err == nil {
|
||||
found = true
|
||||
data, err := GetExifData(ctx, imgPath)
|
||||
if err != nil {
|
||||
t.Logf("No EXIF data for %s format (%s): %v", format, imgPath, err)
|
||||
} else {
|
||||
t.Logf("%s format (%s) has %d EXIF fields", format, imgPath, len(data))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if found {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Logf("No %s format images found for testing", format)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数:复制文件
|
||||
func copyFile(src, dst string) error {
|
||||
input, err := os.ReadFile(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(dst, input, 0644)
|
||||
}
|
||||
|
||||
// BenchmarkGetExifData 性能测试
|
||||
func BenchmarkGetExifData(b *testing.B) {
|
||||
if !IsExifToolAvailable() {
|
||||
b.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
// 找一个存在的图片文件
|
||||
var testImg string
|
||||
for _, imgPath := range testImages {
|
||||
if _, err := os.Stat(imgPath); err == nil {
|
||||
testImg = imgPath
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if testImg == "" {
|
||||
b.Skip("No test images available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := GetExifData(ctx, testImg)
|
||||
if err != nil {
|
||||
b.Fatalf("Benchmark failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestConcurrentAccess 并发访问测试
|
||||
func TestConcurrentAccess(t *testing.T) {
|
||||
if !IsExifToolAvailable() {
|
||||
t.Skip("ExifTool not available")
|
||||
}
|
||||
|
||||
// 找一个存在的图片文件
|
||||
var testImg string
|
||||
for _, imgPath := range testImages {
|
||||
if _, err := os.Stat(imgPath); err == nil {
|
||||
testImg = imgPath
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if testImg == "" {
|
||||
t.Skip("No test images available")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
const numGoroutines = 5
|
||||
|
||||
done := make(chan bool, numGoroutines)
|
||||
errors := make(chan error, numGoroutines)
|
||||
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func(id int) {
|
||||
defer func() { done <- true }()
|
||||
|
||||
_, err := GetExifData(ctx, testImg)
|
||||
if err != nil {
|
||||
errors <- err
|
||||
return
|
||||
}
|
||||
|
||||
t.Logf("Goroutine %d completed successfully", id)
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 等待所有goroutine完成
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
select {
|
||||
case <-done:
|
||||
// 成功完成
|
||||
case err := <-errors:
|
||||
t.Errorf("Concurrent access error: %v", err)
|
||||
case <-time.After(30 * time.Second):
|
||||
t.Error("Concurrent access test timed out")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ type ImageInfo struct {
|
||||
// ConvertImage 使用 ImageMagick 转换图片
|
||||
// 示例: ConvertImage(ctx, "input.jpg", "output.png", "-quality", "90")
|
||||
func ConvertImage(ctx context.Context, input, output string, options ...string) error {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -35,12 +35,20 @@ func ConvertImage(ctx context.Context, input, output string, options ...string)
|
||||
|
||||
// ResizeImage 调整图片大小
|
||||
func ResizeImage(ctx context.Context, input, output string, width, height int) error {
|
||||
// 添加参数验证
|
||||
if width <= 0 || height <= 0 {
|
||||
return fmt.Errorf("invalid dimensions: width and height must be positive, got width=%d, height=%d", width, height)
|
||||
}
|
||||
size := fmt.Sprintf("%dx%d", width, height)
|
||||
return ConvertImage(ctx, input, output, "-resize", size)
|
||||
}
|
||||
|
||||
// ResizeImageKeepAspect 按比例调整图片大小(保持宽高比)
|
||||
func ResizeImageKeepAspect(ctx context.Context, input, output string, maxWidth, maxHeight int) error {
|
||||
// 添加参数验证
|
||||
if maxWidth <= 0 || maxHeight <= 0 {
|
||||
return fmt.Errorf("invalid dimensions: maxWidth and maxHeight must be positive, got maxWidth=%d, maxHeight=%d", maxWidth, maxHeight)
|
||||
}
|
||||
size := fmt.Sprintf("%dx%d>", maxWidth, maxHeight)
|
||||
return ConvertImage(ctx, input, output, "-resize", size)
|
||||
}
|
||||
@@ -58,7 +66,7 @@ func RotateImage(ctx context.Context, input, output string, degrees float64) err
|
||||
|
||||
// IsImageMagickAvailable 检查 ImageMagick 是否可用
|
||||
func IsImageMagickAvailable() bool {
|
||||
if err := utils.EnsureInitialized(); err != nil {
|
||||
if err := utils.EnsureInitialized(nil, nil); err != nil {
|
||||
return false
|
||||
}
|
||||
return utils.ImageMagickPath != ""
|
||||
|
||||
@@ -0,0 +1,612 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"rear/internal/utils"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// 测试图片基础路径
|
||||
testImageBasePath = "D:\\go-argus\\rear\\internal\\img"
|
||||
|
||||
// 测试输出目录
|
||||
testOutputDir = "test_output"
|
||||
)
|
||||
|
||||
// 测试用的图片文件
|
||||
var testImages1 = []string{
|
||||
"cyberpunk2077_world_third@3x.webp",
|
||||
"image-1.JPG",
|
||||
"image-1-1.JPG",
|
||||
"image-2.JPG",
|
||||
"image-3.JPG",
|
||||
"image-4.JPG",
|
||||
"img_1.jpg",
|
||||
"img_2.jpg",
|
||||
"Snipaste_2022-12-17_20-13-15.png",
|
||||
}
|
||||
|
||||
// setupTest 设置测试环境
|
||||
func setupTest(t *testing.T) (string, func()) {
|
||||
// 创建测试输出目录
|
||||
outputDir := filepath.Join(".", testOutputDir)
|
||||
err := os.MkdirAll(outputDir, 0755)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test output directory: %v", err)
|
||||
}
|
||||
|
||||
// 返回清理函数
|
||||
cleanup := func() {
|
||||
os.RemoveAll(outputDir)
|
||||
}
|
||||
|
||||
return outputDir, cleanup
|
||||
}
|
||||
|
||||
// getTestImagePath 获取测试图片的完整路径
|
||||
func getTestImagePath(imageName string) string {
|
||||
return filepath.Join(testImageBasePath, imageName)
|
||||
}
|
||||
|
||||
// fileExists 检查文件是否存在
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// TestIsImageMagickAvailable 测试 ImageMagick 是否可用
|
||||
func TestIsImageMagickAvailable(t *testing.T) {
|
||||
available := IsImageMagickAvailable()
|
||||
if !available {
|
||||
t.Skip("ImageMagick is not available, skipping ImageMagick tests")
|
||||
}
|
||||
t.Log("ImageMagick is available")
|
||||
}
|
||||
|
||||
// TestConvertImage 测试基础图片转换功能
|
||||
func TestConvertImage(t *testing.T) {
|
||||
dir := "D:\\go-argus\\rear\\output\\tools"
|
||||
err := utils.Initialize(nil, &dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !IsImageMagickAvailable() {
|
||||
t.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
output string
|
||||
options []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Convert JPG to PNG",
|
||||
input: getTestImagePath("image-1.JPG"),
|
||||
output: filepath.Join(outputDir, "converted_jpg_to_png.png"),
|
||||
options: []string{"-quality", "90"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Convert WebP to JPG",
|
||||
input: getTestImagePath("cyberpunk2077_world_third@3x.webp"),
|
||||
output: filepath.Join(outputDir, "converted_webp_to_jpg.jpg"),
|
||||
options: []string{"-quality", "85"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Convert PNG to WebP",
|
||||
input: getTestImagePath("Snipaste_2022-12-17_20-13-15.png"),
|
||||
output: filepath.Join(outputDir, "converted_png_to_webp.webp"),
|
||||
options: []string{"-quality", "80"},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid input file",
|
||||
input: "nonexistent.jpg",
|
||||
output: filepath.Join(outputDir, "should_not_exist.png"),
|
||||
options: []string{},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// 检查输入文件是否存在(除了测试错误情况)
|
||||
if !tt.wantErr && !fileExists(tt.input) {
|
||||
t.Skipf("Input file %s does not exist", tt.input)
|
||||
}
|
||||
|
||||
err := ConvertImage(ctx, tt.input, tt.output, tt.options...)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("ConvertImage() expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("ConvertImage() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查输出文件是否存在
|
||||
if !fileExists(tt.output) {
|
||||
t.Errorf("Output file %s was not created", tt.output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestResizeImage 测试调整图片大小功能
|
||||
func TestResizeImage(t *testing.T) {
|
||||
dir := "D:\\go-argus\\rear\\output\\tools"
|
||||
err := utils.Initialize(nil, &dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !IsImageMagickAvailable() {
|
||||
t.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
width int
|
||||
height int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Resize to 800x600",
|
||||
input: getTestImagePath("image-1.JPG"),
|
||||
width: 800,
|
||||
height: 600,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Resize to 1920x1080",
|
||||
input: getTestImagePath("img_1.jpg"),
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Resize to small size 100x100",
|
||||
input: getTestImagePath("Snipaste_2022-12-17_20-13-15.png"),
|
||||
width: 100,
|
||||
height: 100,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid dimensions",
|
||||
input: getTestImagePath("image-1.JPG"),
|
||||
width: -100,
|
||||
height: -100,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !fileExists(tt.input) {
|
||||
t.Skipf("Input file %s does not exist", tt.input)
|
||||
}
|
||||
|
||||
output := filepath.Join(outputDir, fmt.Sprintf("resized_%dx%d_%s", tt.width, tt.height, filepath.Base(tt.input)))
|
||||
|
||||
err := ResizeImage(ctx, tt.input, output, tt.width, tt.height)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("ResizeImage() expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("ResizeImage() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !fileExists(output) {
|
||||
t.Errorf("Output file %s was not created", output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestResizeImageKeepAspect 测试按比例调整图片大小功能
|
||||
func TestResizeImageKeepAspect(t *testing.T) {
|
||||
dir := "D:\\go-argus\\rear\\output\\tools"
|
||||
err := utils.Initialize(nil, &dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !IsImageMagickAvailable() {
|
||||
t.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
maxWidth int
|
||||
maxHeight int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Keep aspect ratio 1920x1080",
|
||||
input: getTestImagePath("image-2.JPG"),
|
||||
maxWidth: 1920,
|
||||
maxHeight: 1080,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Keep aspect ratio 800x600",
|
||||
input: getTestImagePath("cyberpunk2077_world_third@3x.webp"),
|
||||
maxWidth: 800,
|
||||
maxHeight: 600,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Keep aspect ratio thumbnail 200x200",
|
||||
input: getTestImagePath("img_2.jpg"),
|
||||
maxWidth: 200,
|
||||
maxHeight: 200,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !fileExists(tt.input) {
|
||||
t.Skipf("Input file %s does not exist", tt.input)
|
||||
}
|
||||
|
||||
output := filepath.Join(outputDir, fmt.Sprintf("resized_aspect_%dx%d_%s", tt.maxWidth, tt.maxHeight, filepath.Base(tt.input)))
|
||||
|
||||
err := ResizeImageKeepAspect(ctx, tt.input, output, tt.maxWidth, tt.maxHeight)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("ResizeImageKeepAspect() expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("ResizeImageKeepAspect() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !fileExists(output) {
|
||||
t.Errorf("Output file %s was not created", output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCropImage 测试裁剪图片功能
|
||||
func TestCropImage(t *testing.T) {
|
||||
dir := "D:\\go-argus\\rear\\output\\tools"
|
||||
err := utils.Initialize(nil, &dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !IsImageMagickAvailable() {
|
||||
t.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
width int
|
||||
height int
|
||||
x int
|
||||
y int
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Crop center 400x300",
|
||||
input: getTestImagePath("image-3.JPG"),
|
||||
width: 400,
|
||||
height: 300,
|
||||
x: 100,
|
||||
y: 100,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Crop square 500x500",
|
||||
input: getTestImagePath("image-4.JPG"),
|
||||
width: 500,
|
||||
height: 500,
|
||||
x: 50,
|
||||
y: 50,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Crop from origin",
|
||||
input: getTestImagePath("Snipaste_2022-12-17_20-13-15.png"),
|
||||
width: 200,
|
||||
height: 200,
|
||||
x: 0,
|
||||
y: 0,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !fileExists(tt.input) {
|
||||
t.Skipf("Input file %s does not exist", tt.input)
|
||||
}
|
||||
|
||||
output := filepath.Join(outputDir, fmt.Sprintf("cropped_%dx%d_%s", tt.width, tt.height, filepath.Base(tt.input)))
|
||||
|
||||
err := CropImage(ctx, tt.input, output, tt.width, tt.height, tt.x, tt.y)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("CropImage() expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("CropImage() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !fileExists(output) {
|
||||
t.Errorf("Output file %s was not created", output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestRotateImage 测试旋转图片功能
|
||||
func TestRotateImage(t *testing.T) {
|
||||
dir := "D:\\go-argus\\rear\\output\\tools"
|
||||
err := utils.Initialize(nil, &dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !IsImageMagickAvailable() {
|
||||
t.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
degrees float64
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Rotate 90 degrees",
|
||||
input: getTestImagePath("image-1-1.JPG"),
|
||||
degrees: 90.0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Rotate 180 degrees",
|
||||
input: getTestImagePath("img_1.jpg"),
|
||||
degrees: 180.0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Rotate 270 degrees",
|
||||
input: getTestImagePath("img_2.jpg"),
|
||||
degrees: 270.0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Rotate 45 degrees",
|
||||
input: getTestImagePath("Snipaste_2022-12-17_20-13-15.png"),
|
||||
degrees: 45.0,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "Rotate negative degrees",
|
||||
input: getTestImagePath("image-2.JPG"),
|
||||
degrees: -90.0,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if !fileExists(tt.input) {
|
||||
t.Skipf("Input file %s does not exist", tt.input)
|
||||
}
|
||||
|
||||
output := filepath.Join(outputDir, fmt.Sprintf("rotated_%.0f_%s", tt.degrees, filepath.Base(tt.input)))
|
||||
|
||||
err := RotateImage(ctx, tt.input, output, tt.degrees)
|
||||
|
||||
if tt.wantErr {
|
||||
if err == nil {
|
||||
t.Errorf("RotateImage() expected error, got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("RotateImage() error = %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !fileExists(output) {
|
||||
t.Errorf("Output file %s was not created", output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestContextCancellation1 测试上下文取消功能
|
||||
func TestContextCancellation1(t *testing.T) {
|
||||
if !IsImageMagickAvailable() {
|
||||
t.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
// 创建一个会立即取消的上下文
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel() // 立即取消
|
||||
|
||||
input := getTestImagePath("image-1.JPG")
|
||||
if !fileExists(input) {
|
||||
t.Skip("Test image does not exist")
|
||||
}
|
||||
|
||||
output := filepath.Join(outputDir, "should_not_be_created.png")
|
||||
|
||||
err := ConvertImage(ctx, input, output, "-quality", "90")
|
||||
if err == nil {
|
||||
t.Error("Expected error due to context cancellation, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBatchOperations 测试批量操作
|
||||
func TestBatchOperations(t *testing.T) {
|
||||
if !IsImageMagickAvailable() {
|
||||
t.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(t)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// 获取所有存在的测试图片
|
||||
var existingImages []string
|
||||
for _, imgName := range testImages1 {
|
||||
imgPath := getTestImagePath(imgName)
|
||||
if fileExists(imgPath) {
|
||||
existingImages = append(existingImages, imgPath)
|
||||
}
|
||||
}
|
||||
|
||||
if len(existingImages) == 0 {
|
||||
t.Skip("No test images found")
|
||||
}
|
||||
|
||||
t.Logf("Processing %d images", len(existingImages))
|
||||
|
||||
// 批量转换为不同格式
|
||||
for i, imgPath := range existingImages {
|
||||
t.Run(fmt.Sprintf("BatchConvert_%d", i), func(t *testing.T) {
|
||||
baseName := filepath.Base(imgPath)
|
||||
ext := filepath.Ext(baseName)
|
||||
nameWithoutExt := baseName[:len(baseName)-len(ext)]
|
||||
|
||||
// 转换为WebP
|
||||
webpOutput := filepath.Join(outputDir, fmt.Sprintf("batch_%s.webp", nameWithoutExt))
|
||||
err := ConvertImage(ctx, imgPath, webpOutput, "-quality", "80")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to convert %s to WebP: %v", baseName, err)
|
||||
}
|
||||
|
||||
// 创建缩略图
|
||||
thumbnailOutput := filepath.Join(outputDir, fmt.Sprintf("thumbnail_%s.jpg", nameWithoutExt))
|
||||
err = ResizeImageKeepAspect(ctx, imgPath, thumbnailOutput, 200, 200)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create thumbnail for %s: %v", baseName, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkConvertImage 性能测试
|
||||
func BenchmarkConvertImage(b *testing.B) {
|
||||
if !IsImageMagickAvailable() {
|
||||
b.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(&testing.T{})
|
||||
defer cleanup()
|
||||
|
||||
input := getTestImagePath("image-1.JPG")
|
||||
if !fileExists(input) {
|
||||
b.Skip("Test image does not exist")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
output := filepath.Join(outputDir, fmt.Sprintf("bench_%d.png", i))
|
||||
err := ConvertImage(ctx, input, output, "-quality", "90")
|
||||
if err != nil {
|
||||
b.Fatalf("ConvertImage failed: %v", err)
|
||||
}
|
||||
// 清理输出文件
|
||||
os.Remove(output)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkResizeImage 性能测试
|
||||
func BenchmarkResizeImage(b *testing.B) {
|
||||
if !IsImageMagickAvailable() {
|
||||
b.Skip("ImageMagick is not available")
|
||||
}
|
||||
|
||||
outputDir, cleanup := setupTest(&testing.T{})
|
||||
defer cleanup()
|
||||
|
||||
input := getTestImagePath("image-1.JPG")
|
||||
if !fileExists(input) {
|
||||
b.Skip("Test image does not exist")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
output := filepath.Join(outputDir, fmt.Sprintf("bench_resize_%d.jpg", i))
|
||||
err := ResizeImage(ctx, input, output, 800, 600)
|
||||
if err != nil {
|
||||
b.Fatalf("ResizeImage failed: %v", err)
|
||||
}
|
||||
// 清理输出文件
|
||||
os.Remove(output)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user