/** * AriaEngine Bloom Filter + MemTable 单元测试 */ import { BloomFilter } from '../../src/engine/aria/index/bloom'; import { MemTable } from '../../src/engine/aria/index/memtable'; // =================================================================== // BloomFilter // =================================================================== describe('AriaEngine — BloomFilter', () => { it('插入后 mayContain 返回 true', () => { const bf = new BloomFilter(100); bf.insert('hello'); expect(bf.mayContain('hello')).toBe(true); }); it('未插入的 key mayContain 返回 false', () => { const bf = new BloomFilter(100); bf.insert('hello'); expect(bf.mayContain('world')).toBe(false); }); it('批量插入后所有 key 都判定存在', () => { const bf = new BloomFilter(500); const keys: string[] = []; for (let i = 0; i < 200; i++) { const k = `key-${i}`; keys.push(k); bf.insert(k); } for (const k of keys) { expect(bf.mayContain(k)).toBe(true); } }); it('False positive 率可控', () => { const n = 500; const bf = new BloomFilter(n, 10); for (let i = 0; i < n; i++) { bf.insert(`present-${i}`); } let fp = 0; for (let i = 0; i < 500; i++) { if (bf.mayContain(`absent-${i}`)) fp++; } expect(fp).toBeLessThan(25); }); it('getHashCount 返回哈希函数数量', () => { const bf = new BloomFilter(1000, 10); expect(bf.getHashCount()).toBeGreaterThan(0); }); it('serialize + fromData 往返', () => { const bf1 = new BloomFilter(100); bf1.insert('a'); bf1.insert('b'); const data = bf1.serialize(); const bf2 = BloomFilter.fromData(data, bf1.getHashCount()); expect(bf2.mayContain('a')).toBe(true); expect(bf2.mayContain('b')).toBe(true); expect(bf2.mayContain('c')).toBe(false); }); it('空过滤器 mayContain 返回 false', () => { const bf = new BloomFilter(100); expect(bf.mayContain('anything')).toBe(false); }); it('最少 1 个哈希函数', () => { const bf = new BloomFilter(10, 1); expect(bf.getHashCount()).toBeGreaterThanOrEqual(1); }); }); // =================================================================== // MemTable // =================================================================== describe('AriaEngine — MemTable', () => { let mt: MemTable; beforeEach(() => { mt = new MemTable(4 * 1024 * 1024); }); it('put + get 往返', () => { mt.put('key1', { name: 'Alice', age: 30 }); const val = mt.get('key1'); expect(val).not.toBeNull(); expect(val!.name).toBe('Alice'); }); it('get — 不存在的 key 返回 null', () => { expect(mt.get('nonexistent')).toBeNull(); }); it('put 更新已存在的 key', () => { mt.put('k', { v: 1 }); mt.put('k', { v: 2 }); expect(mt.get('k')!.v).toBe(2); }); it('delete 删除成功', () => { mt.put('k', { v: 1 }); expect(mt.delete('k')).toBe(true); expect(mt.get('k')).toBeNull(); }); it('delete — 不存在的 key 返回 false', () => { expect(mt.delete('ghost')).toBe(false); }); it('getAllEntries 返回所有条目(有序)', () => { mt.put('c', { v: 3 }); mt.put('a', { v: 1 }); mt.put('b', { v: 2 }); const entries = mt.getAllEntries(); expect(entries).toHaveLength(3); expect(entries[0][0]).toBe('a'); expect(entries[1][0]).toBe('b'); expect(entries[2][0]).toBe('c'); }); it('rangeScan — 范围查询', () => { mt.put('a', { v: 1 }); mt.put('b', { v: 2 }); mt.put('c', { v: 3 }); mt.put('d', { v: 4 }); const results = mt.rangeScan('b', 'c'); expect(results).toHaveLength(2); expect(results[0][0]).toBe('b'); expect(results[1][0]).toBe('c'); }); it('rangeScan — 空结果', () => { mt.put('a', { v: 1 }); const results = mt.rangeScan('z', 'zz'); expect(results).toHaveLength(0); }); it('getEntryCount 正确计数', () => { expect(mt.getEntryCount()).toBe(0); mt.put('a', { v: 1 }); mt.put('b', { v: 2 }); expect(mt.getEntryCount()).toBe(2); mt.delete('a'); expect(mt.getEntryCount()).toBe(1); }); it('shouldFlush — 未达阈值返回 false', () => { expect(mt.shouldFlush()).toBe(false); }); it('clear 清空所有数据', () => { mt.put('a', { v: 1 }); mt.put('b', { v: 2 }); mt.clear(); expect(mt.getEntryCount()).toBe(0); expect(mt.get('a')).toBeNull(); }); it('getEstimatedSize 返回合理估计值', () => { expect(mt.getEstimatedSize()).toBe(0); mt.put('hello', { name: 'world', count: 42 }); expect(mt.getEstimatedSize()).toBeGreaterThan(0); }); it('大量数据插入保持有序', () => { const count = 100; for (let i = count - 1; i >= 0; i--) { mt.put(`key-${String(i).padStart(3, '0')}`, { idx: i }); } const entries = mt.getAllEntries(); expect(entries).toHaveLength(count); for (let i = 0; i < count; i++) { expect(entries[i][1].idx).toBe(i); } }); it('删除后重新插入', () => { mt.put('k', { v: 1 }); mt.delete('k'); mt.put('k', { v: 2 }); expect(mt.get('k')!.v).toBe(2); }); it('范围扫描包含边界', () => { mt.put('aa', { v: 1 }); mt.put('ab', { v: 2 }); mt.put('ac', { v: 3 }); const results = mt.rangeScan('aa', 'ab'); expect(results).toHaveLength(2); expect(results[0][0]).toBe('aa'); expect(results[1][0]).toBe('ab'); }); });