Files
aida_front/src/component/Canvas/CanvasEditor/tests/liquifyIntegrationTests.js
2025-07-14 01:00:23 +08:00

451 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 液化功能集成测试
* 用于在浏览器环境中测试完整的液化工作流程
*/
import { LiquifyCPUManager } from "../managers/liquify/LiquifyCPUManager.js";
import { LiquifyWebGLManager } from "../managers/liquify/LiquifyWebGLManager.js";
import { LiquifyRealTimeUpdater } from "../managers/liquify/LiquifyRealTimeUpdater.js";
import { EnhancedLiquifyManager } from "../managers/liquify/EnhancedLiquifyManager.js";
// 集成测试结果
let testResults = {
totalTests: 0,
passedTests: 0,
failedTests: 0,
errors: [],
};
/**
* 创建测试图像数据
*/
function createTestImageData(width = 100, height = 100) {
const imageData = new ImageData(width, height);
const data = imageData.data;
// 创建一个简单的渐变图案用于测试
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const index = (y * width + x) * 4;
data[index] = (x / width) * 255; // Red
data[index + 1] = (y / height) * 255; // Green
data[index + 2] = 128; // Blue
data[index + 3] = 255; // Alpha
}
}
return imageData;
}
/**
* 创建测试Canvas
*/
function createTestCanvas(width = 200, height = 200) {
const canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
return canvas;
}
/**
* 创建模拟Fabric对象
*/
function createMockFabricObject(imageData) {
return {
left: 50,
top: 50,
width: imageData.width,
height: imageData.height,
scaleX: 1,
scaleY: 1,
angle: 0,
flipX: false,
flipY: false,
_element: null,
calcTransformMatrix: function () {
return [this.scaleX, 0, 0, this.scaleY, this.left, this.top];
},
set: function (props) {
Object.assign(this, props);
},
};
}
/**
* 运行单个测试
*/
async function runTest(testName, testFunction) {
testResults.totalTests++;
try {
console.log(`🧪 运行测试: ${testName}`);
await testFunction();
testResults.passedTests++;
console.log(`✅ 测试通过: ${testName}`);
} catch (error) {
testResults.failedTests++;
testResults.errors.push({ testName, error: error.message });
console.error(`❌ 测试失败: ${testName}`, error);
}
}
/**
* 测试CPU管理器基本功能
*/
async function testCPUManagerBasics() {
const manager = new LiquifyCPUManager();
const testImageData = createTestImageData();
// 初始化
manager.initialize(testImageData);
// 设置参数
manager.setParams({
size: 50,
pressure: 0.5,
distortion: 0.3,
power: 0.8,
});
// 设置模式
manager.setMode("push");
// 应用变形
const result = manager.applyDeformation(50, 50);
if (!result || result.width !== testImageData.width || result.height !== testImageData.height) {
throw new Error("CPU管理器变形结果无效");
}
// 测试不同模式
const modes = ["push", "clockwise", "counterclockwise", "pinch", "expand", "reconstruct"];
for (const mode of modes) {
manager.setMode(mode);
const modeResult = manager.applyDeformation(25, 25);
if (!modeResult) {
throw new Error(`模式 ${mode} 变形失败`);
}
}
}
/**
* 测试WebGL管理器基本功能
*/
async function testWebGLManagerBasics() {
const manager = new LiquifyWebGLManager();
const testImageData = createTestImageData();
try {
// 初始化
manager.initialize(testImageData);
// 检查WebGL是否可用
if (!manager.initialized) {
console.warn("WebGL不可用跳过WebGL测试");
return;
}
// 设置参数
manager.setParams({
size: 50,
pressure: 0.5,
distortion: 0.3,
power: 0.8,
});
// 设置模式
manager.setMode("push");
// 应用变形
const result = manager.applyDeformation(50, 50);
if (!result || result.width !== testImageData.width || result.height !== testImageData.height) {
throw new Error("WebGL管理器变形结果无效");
}
} catch (error) {
if (error.message.includes("WebGL")) {
console.warn("WebGL不支持跳过WebGL测试");
return;
}
throw error;
}
}
/**
* 测试实时更新器功能
*/
async function testRealTimeUpdater() {
const canvas = createTestCanvas();
const testImageData = createTestImageData();
const mockFabricObject = createMockFabricObject(testImageData);
// 模拟fabric Canvas
const fabricCanvas = {
getObjects: () => [mockFabricObject],
remove: () => {},
insertAt: () => {},
renderAll: () => {},
};
const updater = new LiquifyRealTimeUpdater(fabricCanvas);
// 设置目标对象
updater.setTargetObject(mockFabricObject);
// 测试快速更新
await updater.updateImage(testImageData, true);
// 测试完整更新
await updater.updateImage(testImageData, false);
// 测试待处理更新
updater.pendingImageData = testImageData;
await updater.processPendingUpdates();
// 清理
updater.dispose();
}
/**
* 测试增强液化管理器
*/
async function testEnhancedLiquifyManager() {
const manager = new EnhancedLiquifyManager();
const testImageData = createTestImageData();
const mockFabricObject = createMockFabricObject(testImageData);
// 初始化
const result = await manager.prepareForLiquify(mockFabricObject);
if (!result || !result.originalImageData) {
throw new Error("增强液化管理器初始化失败");
}
// 设置参数
manager.setParams({
size: 50,
pressure: 0.5,
distortion: 0.3,
power: 0.8,
});
// 应用液化
const liquifyResult = await manager.applyLiquify(
mockFabricObject,
"push",
{ size: 50, pressure: 0.5, distortion: 0.3, power: 0.8 },
50,
50
);
if (!liquifyResult) {
throw new Error("液化应用失败");
}
}
/**
* 测试坐标转换准确性
*/
async function testCoordinateConversion() {
const testImageData = createTestImageData(200, 200);
const mockFabricObject = createMockFabricObject(testImageData);
// 测试不同的缩放情况
const testCases = [
{ scaleX: 1, scaleY: 1, flipX: false, flipY: false },
{ scaleX: 2, scaleY: 2, flipX: false, flipY: false },
{ scaleX: 0.5, scaleY: 0.5, flipX: false, flipY: false },
{ scaleX: 1, scaleY: 1, flipX: true, flipY: false },
{ scaleX: 1, scaleY: 1, flipX: false, flipY: true },
];
for (const testCase of testCases) {
Object.assign(mockFabricObject, testCase);
// 模拟坐标转换函数(简化版)
const fabricX = 100,
fabricY = 100;
// 创建变换矩阵模拟
const transform = mockFabricObject.calcTransformMatrix();
// 基本的坐标边界检查
const localX = (fabricX - mockFabricObject.left) / mockFabricObject.scaleX;
const localY = (fabricY - mockFabricObject.top) / mockFabricObject.scaleY;
if (
localX < -mockFabricObject.width / 2 ||
localX > mockFabricObject.width / 2 ||
localY < -mockFabricObject.height / 2 ||
localY > mockFabricObject.height / 2
) {
// 坐标在对象外部,这是正常情况
continue;
}
// 转换到图像坐标
let imageX =
(localX + mockFabricObject.width / 2) * (testImageData.width / mockFabricObject.width);
let imageY =
(localY + mockFabricObject.height / 2) * (testImageData.height / mockFabricObject.height);
// 处理翻转
if (mockFabricObject.flipX) {
imageX = testImageData.width - imageX;
}
if (mockFabricObject.flipY) {
imageY = testImageData.height - imageY;
}
// 验证结果在合理范围内
if (
imageX < 0 ||
imageX >= testImageData.width ||
imageY < 0 ||
imageY >= testImageData.height
) {
throw new Error(`坐标转换结果超出图像范围: (${imageX}, ${imageY})`);
}
}
}
/**
* 测试性能表现
*/
async function testPerformance() {
const manager = new LiquifyCPUManager();
const testImageData = createTestImageData(400, 400); // 更大的图像
manager.initialize(testImageData);
manager.setParams({
size: 50,
pressure: 0.5,
distortion: 0.3,
power: 0.8,
});
manager.setMode("push");
// 测试多次操作的性能
const startTime = performance.now();
const operationCount = 100;
for (let i = 0; i < operationCount; i++) {
const x = Math.random() * testImageData.width;
const y = Math.random() * testImageData.height;
manager.applyDeformation(x, y);
}
const endTime = performance.now();
const totalTime = endTime - startTime;
const avgTime = totalTime / operationCount;
console.log(
`性能测试结果: ${operationCount} 次操作,总耗时 ${totalTime.toFixed(
2
)}ms平均 ${avgTime.toFixed(2)}ms/次`
);
// 验证性能阈值每次操作不应超过50ms
if (avgTime > 50) {
throw new Error(`性能不达标:平均操作时间 ${avgTime.toFixed(2)}ms 超过阈值 50ms`);
}
}
/**
* 测试内存管理
*/
async function testMemoryManagement() {
const initialMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
// 创建多个管理器实例
const managers = [];
for (let i = 0; i < 10; i++) {
const manager = new LiquifyCPUManager();
const testImageData = createTestImageData(200, 200);
manager.initialize(testImageData);
managers.push(manager);
}
// 销毁所有管理器
for (const manager of managers) {
if (manager.destroy) {
manager.destroy();
}
}
// 强制垃圾回收(如果可用)
if (window.gc) {
window.gc();
}
const finalMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
const memoryIncrease = finalMemory - initialMemory;
console.log(
`内存测试: 初始 ${(initialMemory / 1024 / 1024).toFixed(2)}MB, 最终 ${(
finalMemory /
1024 /
1024
).toFixed(2)}MB, 增长 ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`
);
// 验证内存增长不超过10MB基本的内存泄漏检查
if (memoryIncrease > 10 * 1024 * 1024) {
console.warn(`潜在内存泄漏: 内存增长 ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`);
}
}
/**
* 运行所有集成测试
*/
export async function runLiquifyIntegrationTests() {
console.log("🚀 开始液化功能集成测试...");
// 重置测试结果
testResults = {
totalTests: 0,
passedTests: 0,
failedTests: 0,
errors: [],
};
try {
// 基础功能测试
await runTest("CPU管理器基本功能", testCPUManagerBasics);
await runTest("WebGL管理器基本功能", testWebGLManagerBasics);
await runTest("实时更新器功能", testRealTimeUpdater);
await runTest("增强液化管理器", testEnhancedLiquifyManager);
// 高级功能测试
await runTest("坐标转换准确性", testCoordinateConversion);
await runTest("性能表现", testPerformance);
await runTest("内存管理", testMemoryManagement);
} catch (error) {
console.error("集成测试出现严重错误:", error);
}
// 输出测试结果
console.log("\n📊 液化功能集成测试结果:");
console.log(`总测试数: ${testResults.totalTests}`);
console.log(`通过: ${testResults.passedTests}`);
console.log(`失败: ${testResults.failedTests}`);
console.log(`成功率: ${((testResults.passedTests / testResults.totalTests) * 100).toFixed(1)}%`);
if (testResults.errors.length > 0) {
console.log("\n❌ 失败的测试:");
testResults.errors.forEach(({ testName, error }) => {
console.log(` - ${testName}: ${error}`);
});
}
return testResults;
}
/**
* 在浏览器控制台中运行测试
*/
if (typeof window !== "undefined") {
window.runLiquifyIntegrationTests = runLiquifyIntegrationTests;
console.log("💡 使用 window.runLiquifyIntegrationTests() 运行液化集成测试");
}