88 lines
3.3 KiB
TypeScript
88 lines
3.3 KiB
TypeScript
/// <reference types="jest" />
|
|
import { DataProcessor, AggregateResult } from '../src/core/dataProcessor';
|
|
|
|
describe('DataProcessor Algorithm & Performance Validation', () => {
|
|
|
|
// 1. 정합성 테스트 (Correctness)
|
|
test('Should correctly aggregate data by key path', () => {
|
|
const testData = [
|
|
{ category: 'A', value: 10 },
|
|
{ category: 'B', value: 20 },
|
|
{ category: 'A', value: 30 },
|
|
{ category: 'C', value: 40 },
|
|
];
|
|
|
|
const result = DataProcessor.aggregate(testData, 'category');
|
|
|
|
expect(result.length).toBe(3);
|
|
expect(result.find((r: AggregateResult) => r.key === 'A')?.count).toBe(2);
|
|
expect(result.find((r: AggregateResult) => r.key === 'B')?.count).toBe(1);
|
|
});
|
|
|
|
// 2. 예외 처리 테스트 (Robustness)
|
|
test('Should handle invalid or missing key paths gracefully', () => {
|
|
const testData = [
|
|
{ id: 1, info: { type: 'X' } },
|
|
{ id: 2 }, // info.type 없음
|
|
{ id: 3, info: null }, // info.type 접근 불가
|
|
];
|
|
|
|
const result = DataProcessor.aggregate(testData, 'info.type');
|
|
|
|
expect(result.length).toBe(1);
|
|
expect(result[0].key).toBe('X');
|
|
});
|
|
|
|
test('Should reject unsafe or malformed key paths', () => {
|
|
expect(() => DataProcessor.aggregate([{ a: 1 }], '')).toThrow(TypeError);
|
|
expect(() => DataProcessor.aggregate([{ a: 1 }], 'a..b')).toThrow(TypeError);
|
|
expect(() => DataProcessor.aggregate([{ a: 1 }], '__proto__.polluted')).toThrow(TypeError);
|
|
});
|
|
|
|
test('Should support aggregation without retaining source values', () => {
|
|
const result = DataProcessor.aggregate([
|
|
{ category: 'A', value: 10 },
|
|
{ category: 'A', value: 20 },
|
|
], 'category', { collectValues: false });
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0].count).toBe(2);
|
|
expect(result[0].values).toEqual([]);
|
|
});
|
|
|
|
// 3. 성능 벤치마크 (O(N) vs O(N^2) 검증)
|
|
test('O(N) Efficiency Benchmark', () => {
|
|
const generateData = (n: number) => {
|
|
return Array.from({ length: n }, (_, i) => ({
|
|
id: i,
|
|
group: `group_${i % 100}`
|
|
}));
|
|
};
|
|
|
|
const smallN = 1000;
|
|
const largeN = 100000; // 100배 증가
|
|
|
|
// Small dataset test
|
|
const smallData = generateData(smallN);
|
|
const startSmall = performance.now();
|
|
DataProcessor.aggregate(smallData, 'group');
|
|
const endSmall = performance.now();
|
|
const durationSmall = endSmall - startSmall;
|
|
|
|
// Large dataset test
|
|
const largeData = generateData(largeN);
|
|
const startLarge = performance.now();
|
|
DataProcessor.aggregate(largeData, 'group');
|
|
const endLarge = performance.now();
|
|
const durationLarge = endLarge - startLarge;
|
|
|
|
console.log(`[Benchmark] N=${smallN}: ${durationSmall.toFixed(4)}ms`);
|
|
console.log(`[Benchmark] N=${largeN}: ${durationLarge.toFixed(4)}ms`);
|
|
console.log(`[Benchmark] Scale Factor (N x 100): ${(durationLarge / durationSmall).toFixed(2)}x time`);
|
|
|
|
// O(N^2)이었다면 10,000배 이상의 시간이 걸려야 하지만,
|
|
// O(N)인 경우 약 100배 내외의 증가폭을 보여야 합니다.
|
|
expect(durationLarge / durationSmall).toBeLessThan(500);
|
|
});
|
|
});
|