总测试项
0
涵盖 5 大功能模块
通过数
0
实时更新
压缩率
0%
LZ-String 算法

🔍 Task 3: 表单特殊字符处理测试
XSS 防护

边界测试用例

💾 Task 4: 本地存储压缩算法优化
LZ-String

原始数据大小

0 KB

测试数据:音乐工程 JSON

压缩后大小

0 KB

LZ-String 压缩

压缩率

0%

空间节省

⚡ Task 5: 分片上传并发数测试
动态并发

1 3 10
已上传: 0 / 0
速度: 0 MB/s
预计剩余: --

📈 Task 7: 图表导出格式选项扩展
多格式支持

分辨率:
质量: 90%

🖨️ Task 6: 水印字体大小调整
自适应

-30°
30%

当前字体大小:--px

画布尺寸:800 x 600

测试 😊 中文 \' OR 1=1 -- &', unicode: '\u0000\u0001\u0002 特殊\u007F 字符\uFFFF', xss: '' }; document.getElementById('form-input').value = inputs[type]; runFormTest(); } function escapeHtmlChars(str) { return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } // ==================== 存储压缩测试 ==================== function runCompressionTest() { const compressor = new StorageCompressor(); // 生成模拟音乐工程数据 const musicProject = generateMockMusicProject(); const originalSize = JSON.stringify(musicProject).length; // 压缩 const compressed = compressor.compress(musicProject); const compressedSize = compressed.length; // 解压验证 const decompressed = compressor.decompress(compressed); const isValid = JSON.stringify(decompressed) === JSON.stringify(musicProject); // 更新显示 document.getElementById('original-size').textContent = formatBytes(originalSize); document.getElementById('compressed-size').textContent = formatBytes(compressedSize); const ratio = ((1 - compressedSize / originalSize) * 100).toFixed(1); document.getElementById('compression-ratio').textContent = ratio + '%'; document.getElementById('compression-rate').textContent = ratio + '%'; // 显示结果 const resultDiv = document.getElementById('storage-result'); resultDiv.innerHTML = `
✅ 压缩测试${isValid ? '成功' : '失败'}
原始大小:${formatBytes(originalSize)}
压缩后:${formatBytes(compressedSize)}
节省空间:${ratio}%
压缩时间:${compressor.lastCompressionTime}ms
解压时间:${compressor.lastDecompressionTime}ms
`; updateStats(isValid ? 1 : 0, 1); } function runBenchmark() { const compressor = new StorageCompressor(); const benchmark = new CompressionBenchmark(); const sizes = [1024, 10240, 102400, 1024000]; // 1KB, 10KB, 100KB, 1MB const results = []; sizes.forEach(size => { const data = generateRandomData(size); const result = benchmark.run(data); results.push(result); }); const resultDiv = document.getElementById('storage-result'); resultDiv.innerHTML = `
📊 性能基准测试
${results.map(r => ` `).join('')}
数据大小 压缩率 压缩时间 解压时间
${formatBytes(r.originalSize)} ${r.compressionRatio.toFixed(1)}% ${r.compressionTime.toFixed(2)}ms ${r.decompressionTime.toFixed(2)}ms
`; } function testWebWorker() { const resultDiv = document.getElementById('storage-result'); resultDiv.innerHTML = '
正在启动 Web Worker 进行异步压缩测试...
'; const compressor = new StorageCompressor(); const largeData = generateMockMusicProject(); const startTime = performance.now(); compressor.compressAsync(largeData).then(result => { const endTime = performance.now(); const duration = (endTime - startTime).toFixed(2); resultDiv.innerHTML += `
✅ Web Worker 异步压缩完成
耗时:${duration}ms
主线程未被阻塞 ✓
`; }).catch(err => { resultDiv.innerHTML += `
❌ 错误:${err.message}
`; }); } // ==================== 上传测试 ==================== async function runUploadTest() { const concurrency = parseInt(document.getElementById('concurrency-slider').value); const fileSizeMB = parseInt(document.getElementById('file-size-select').value); const networkCondition = document.getElementById('network-condition').value; const manager = new UploadManager({ maxConcurrency: concurrency, retryAttempts: 3, chunkSize: 1024 * 1024 // 1MB per chunk }); const resultDiv = document.getElementById('upload-result'); const progressBar = document.getElementById('upload-progress'); resultDiv.innerHTML = '
初始化上传测试...
'; // 模拟上传 const totalChunks = fileSizeMB; let uploadedChunks = 0; const startTime = performance.now(); try { await manager.simulateUpload(totalChunks, { networkCondition, onProgress: (progress) => { uploadedChunks = Math.floor(progress * totalChunks); progressBar.value = progress * 100; document.getElementById('uploaded-chunks').textContent = `${uploadedChunks} / ${totalChunks}`; const elapsed = (performance.now() - startTime) / 1000; const speed = (uploadedChunks / elapsed).toFixed(2); document.getElementById('upload-speed').textContent = `${speed} MB/s`; const remaining = totalChunks - uploadedChunks; const eta = remaining / speed; document.getElementById('eta').textContent = eta < 60 ? `${eta.toFixed(0)}秒` : `${(eta / 60).toFixed(1)}分钟`; }, onComplete: (stats) => { const duration = ((performance.now() - startTime) / 1000).toFixed(2); resultDiv.innerHTML = `
✅ 上传测试完成
总耗时:${duration}s
平均速度:${stats.avgSpeed.toFixed(2)} MB/s
成功分片:${stats.successfulChunks}
失败分片:${stats.failedChunks}
重试次数:${stats.totalRetries}
并发峰值:${stats.peakConcurrency}
`; updateStats(1, 1); } }); } catch (err) { resultDiv.innerHTML = `
❌ 上传失败:${err.message}
`; updateStats(0, 1); } } // ==================== 图表导出测试 ==================== function exportChart(format) { const canvas = document.getElementById('test-chart'); const dpi = parseInt(document.getElementById('export-dpi').value); const quality = parseFloat(document.getElementById('export-quality').value); const includeData = document.getElementById('include-data').checked; const resultDiv = document.getElementById('export-result'); resultDiv.className = 'mt-4 test-result test-info'; switch (format.toLowerCase()) { case 'png': case 'jpg': const dataUrl = canvas.toDataURL(`image/${format}`, quality); resultDiv.innerHTML = `✅ ${format.toUpperCase()} 导出成功
数据 URL 长度:${dataUrl.length} 字符`; break; case 'svg': const svgExporter = new SVGExporter(); const svg = svgExporter.export(canvas); resultDiv.innerHTML = `✅ SVG 导出成功
SVG 内容长度:${svg.length} 字符`; break; case 'pdf': resultDiv.innerHTML = `⏳ PDF 导出需要 jsPDF 库,请确保已加载...`; break; case 'xlsx': case 'excel': const excelExporter = new ExcelExporter(); const chartData = { labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], values: [65, 45, 80, 55, 90, 70, 85] }; resultDiv.innerHTML = `✅ Excel 数据准备就绪
可调用 download() 方法下载`; break; default: resultDiv.innerHTML = `❌ 不支持的格式:${format}`; } updateStats(1, 1); } async function batchExport() { const batchExporter = new BatchExporter(); const canvas = document.getElementById('test-chart'); const formats = ['png', 'jpg', 'svg', 'csv', 'json']; formats.forEach(format => { batchExporter.addTask({ canvas, format, filename: `chart.${format}`, options: { quality: 0.9 } }); }); const resultDiv = document.getElementById('export-result'); resultDiv.innerHTML = '⏳ 正在批量导出...'; const report = await batchExporter.executeAll(); resultDiv.innerHTML = `
批量导出完成
总计:${report.total} 个文件
成功:${report.success}
失败:${report.failed}
总大小:${report.totalSize}
`; } // ==================== 水印测试 ==================== function setWatermarkPosition(position) { if (watermarkRenderer) { watermarkRenderer.config.position = position; renderWatermark(); } } function renderWatermark() { const text = document.getElementById('watermark-text').value; const rotation = parseInt(document.getElementById('watermark-rotation').value); const opacity = parseFloat(document.getElementById('watermark-opacity').value); if (!watermarkRenderer) return; const result = watermarkRenderer.render(text, { rotation, color: `rgba(139, 92, 246, ${opacity})` }); document.getElementById('current-font-size').textContent = result.fontSize; updateStats(1, 1); } function clearWatermark() { if (watermarkRenderer) { watermarkRenderer.clear(); initWatermarkCanvas(); } } function downloadWatermark() { if (watermarkRenderer) { watermarkRenderer.download('watermark.png'); } } // ==================== 工具函数 ==================== function updateStats(passed = 0, total = 0) { testStats.passed += passed; testStats.total += total; document.getElementById('passed-tests').textContent = testStats.passed; document.getElementById('total-tests').textContent = testStats.total; } function formatBytes(bytes) { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB'; return (bytes / (1024 * 1024)).toFixed(2) + ' MB'; } function generateMockMusicProject() { return { name: 'Demo Song', bpm: 120, key: 'C', tracks: Array.from({ length: 8 }, (_, i) => ({ name: `Track ${i + 1}`, instrument: ['piano', 'guitar', 'drums', 'bass'][i % 4], notes: Array.from({ length: 100 }, () => ({ pitch: Math.floor(Math.random() * 88) + 1, velocity: Math.floor(Math.random() * 127), duration: Math.random() * 2, startTime: Math.random() * 100 })) })), metadata: { created: Date.now(), modified: Date.now(), author: 'AI Composer' } }; } function generateRandomData(size) { const obj = {}; for (let i = 0; i < size / 10; i++) { obj[`key_${i}`] = Math.random().toString(36).substring(2, 15); } return obj; }