174 lines
5.5 KiB
TypeScript
174 lines
5.5 KiB
TypeScript
/**
|
||
* Stresstest – 50.000 Elemente: SpatialIndex Query-Performance,
|
||
* HistoryManager Memory, Undo/Redo Performance.
|
||
*/
|
||
import { describe, it, expect } from 'vitest';
|
||
import { SpatialIndex } from '../src/canvas/SpatialIndex';
|
||
import { HistoryManager } from '../src/history/HistoryManager';
|
||
import type { CADElement, CADLayer } from '../src/types/cad.types';
|
||
|
||
const N = 50_000;
|
||
|
||
function generateElements(count: number): CADElement[] {
|
||
const elements: CADElement[] = [];
|
||
for (let i = 0; i < count; i++) {
|
||
elements.push({
|
||
id: `elem-${i}`,
|
||
type: 'rect',
|
||
layerId: 'layer-1',
|
||
x: (i % 1000) * 1.5,
|
||
y: Math.floor(i / 1000) * 1.5,
|
||
width: 1,
|
||
height: 1,
|
||
properties: {},
|
||
});
|
||
}
|
||
return elements;
|
||
}
|
||
|
||
function makeLayer(): CADLayer {
|
||
return {
|
||
id: 'layer-1',
|
||
name: 'Layer 1',
|
||
visible: true,
|
||
locked: false,
|
||
color: '#ffffff',
|
||
lineType: 'solid',
|
||
transparency: 0,
|
||
sortOrder: 0,
|
||
parentId: null,
|
||
};
|
||
}
|
||
|
||
describe('Stresstest: 50.000 Elemente', () => {
|
||
it('should bulk-insert 50k elements into SpatialIndex in under 2s', () => {
|
||
const elements = generateElements(N);
|
||
const index = new SpatialIndex();
|
||
const start = performance.now();
|
||
index.bulkInsert(elements);
|
||
const elapsed = performance.now() - start;
|
||
console.log(`SpatialIndex bulkInsert: ${elapsed.toFixed(1)}ms for ${N} elements`);
|
||
expect(elapsed).toBeLessThan(2000);
|
||
});
|
||
|
||
it('should search SpatialIndex with 50k elements in under 10ms', () => {
|
||
const elements = generateElements(N);
|
||
const index = new SpatialIndex();
|
||
index.bulkInsert(elements);
|
||
// Search a region in the middle
|
||
const start = performance.now();
|
||
const results = index.search({ minX: 750, minY: 37.5, maxX: 1500, maxY: 75 });
|
||
const elapsed = performance.now() - start;
|
||
console.log(`SpatialIndex search: ${elapsed.toFixed(2)}ms, found ${results.length} elements`);
|
||
expect(elapsed).toBeLessThan(50);
|
||
expect(results.length).toBeGreaterThan(0);
|
||
});
|
||
|
||
it('should search a small point region with 50k elements in under 5ms', () => {
|
||
const elements = generateElements(N);
|
||
const index = new SpatialIndex();
|
||
index.bulkInsert(elements);
|
||
const start = performance.now();
|
||
const results = index.search({ minX: 750, minY: 37.5, maxX: 751, maxY: 38.5 });
|
||
const elapsed = performance.now() - start;
|
||
console.log(`SpatialIndex point search: ${elapsed.toFixed(3)}ms, found ${results.length} elements`);
|
||
expect(elapsed).toBeLessThan(10);
|
||
});
|
||
|
||
it('should clear and re-insert 50k elements in under 2s', () => {
|
||
const elements = generateElements(N);
|
||
const index = new SpatialIndex();
|
||
index.bulkInsert(elements);
|
||
// Modify 100 elements
|
||
for (let i = 0; i < 100; i++) {
|
||
elements[i].x += 5000;
|
||
}
|
||
const start = performance.now();
|
||
index.clear();
|
||
index.bulkInsert(elements);
|
||
const elapsed = performance.now() - start;
|
||
console.log(`SpatialIndex clear+reinsert: ${elapsed.toFixed(1)}ms after 100 modifications`);
|
||
expect(elapsed).toBeLessThan(2000);
|
||
});
|
||
|
||
it('should handle HistoryManager with 50k elements snapshot', () => {
|
||
const elements = generateElements(N);
|
||
const layers = [makeLayer()];
|
||
const history = new HistoryManager({ maxStackSize: 50 });
|
||
const start = performance.now();
|
||
history.initialize({
|
||
elements,
|
||
layers,
|
||
blocks: [],
|
||
groups: [],
|
||
bgConfig: null,
|
||
});
|
||
const elapsed = performance.now() - start;
|
||
console.log(`HistoryManager initialize: ${elapsed.toFixed(1)}ms for ${N} elements`);
|
||
expect(elapsed).toBeLessThan(1000);
|
||
});
|
||
|
||
it('should push 10 history snapshots with 50k elements each', () => {
|
||
const elements = generateElements(N);
|
||
const layers = [makeLayer()];
|
||
const history = new HistoryManager({ maxStackSize: 50 });
|
||
history.initialize({
|
||
elements,
|
||
layers,
|
||
blocks: [],
|
||
groups: [],
|
||
bgConfig: null,
|
||
});
|
||
const start = performance.now();
|
||
for (let i = 0; i < 10; i++) {
|
||
// Slightly modify elements each snapshot
|
||
elements[i * 100].x += 1;
|
||
history.pushSnapshot({
|
||
elements: [...elements],
|
||
layers,
|
||
blocks: [],
|
||
groups: [],
|
||
bgConfig: null,
|
||
label: `Step ${i + 1}`,
|
||
});
|
||
}
|
||
const elapsed = performance.now() - start;
|
||
console.log(`HistoryManager 10 snapshots: ${elapsed.toFixed(1)}ms for ${N} elements each`);
|
||
expect(elapsed).toBeLessThan(5000);
|
||
expect(history.getHistory().length).toBe(11); // initial + 10
|
||
});
|
||
|
||
it('should undo/redo with 50k elements in under 100ms', () => {
|
||
const elements = generateElements(N);
|
||
const layers = [makeLayer()];
|
||
const history = new HistoryManager({ maxStackSize: 50 });
|
||
history.initialize({
|
||
elements,
|
||
layers,
|
||
blocks: [],
|
||
groups: [],
|
||
bgConfig: null,
|
||
});
|
||
history.pushSnapshot({
|
||
elements: [...elements],
|
||
layers,
|
||
blocks: [],
|
||
groups: [],
|
||
bgConfig: null,
|
||
label: 'Step 1',
|
||
});
|
||
const undoStart = performance.now();
|
||
const undoSnap = history.undo();
|
||
const undoTime = performance.now() - undoStart;
|
||
console.log(`Undo: ${undoTime.toFixed(2)}ms for ${N} elements`);
|
||
expect(undoSnap).not.toBeNull();
|
||
expect(undoTime).toBeLessThan(100);
|
||
const redoStart = performance.now();
|
||
const redoSnap = history.redo();
|
||
const redoTime = performance.now() - redoStart;
|
||
console.log(`Redo: ${redoTime.toFixed(2)}ms for ${N} elements`);
|
||
expect(redoSnap).not.toBeNull();
|
||
expect(redoTime).toBeLessThan(100);
|
||
});
|
||
});
|