import { tap, expect } from '@git.zone/tstest/tapbundle'; import { BinaryHeap } from '../../../ts/core/utils/binary-heap.js'; interface TestItem { id: string; priority: number; value: string; } tap.test('should create empty heap', async () => { const heap = new BinaryHeap((a, b) => a - b); expect(heap.size).toEqual(0); expect(heap.isEmpty()).toBeTrue(); expect(heap.peek()).toBeUndefined(); }); tap.test('should insert and extract in correct order', async () => { const heap = new BinaryHeap((a, b) => a - b); heap.insert(5); heap.insert(3); heap.insert(7); heap.insert(1); heap.insert(9); heap.insert(4); expect(heap.size).toEqual(6); // Extract in ascending order expect(heap.extract()).toEqual(1); expect(heap.extract()).toEqual(3); expect(heap.extract()).toEqual(4); expect(heap.extract()).toEqual(5); expect(heap.extract()).toEqual(7); expect(heap.extract()).toEqual(9); expect(heap.extract()).toBeUndefined(); }); tap.test('should work with custom objects and comparator', async () => { const heap = new BinaryHeap( (a, b) => a.priority - b.priority, (item) => item.id ); heap.insert({ id: 'a', priority: 5, value: 'five' }); heap.insert({ id: 'b', priority: 2, value: 'two' }); heap.insert({ id: 'c', priority: 8, value: 'eight' }); heap.insert({ id: 'd', priority: 1, value: 'one' }); const first = heap.extract(); expect(first?.priority).toEqual(1); expect(first?.value).toEqual('one'); const second = heap.extract(); expect(second?.priority).toEqual(2); expect(second?.value).toEqual('two'); }); tap.test('should support reverse order (max heap)', async () => { const heap = new BinaryHeap((a, b) => b - a); heap.insert(5); heap.insert(3); heap.insert(7); heap.insert(1); heap.insert(9); // Extract in descending order expect(heap.extract()).toEqual(9); expect(heap.extract()).toEqual(7); expect(heap.extract()).toEqual(5); }); tap.test('should extract by predicate', async () => { const heap = new BinaryHeap((a, b) => a.priority - b.priority); heap.insert({ id: 'a', priority: 5, value: 'five' }); heap.insert({ id: 'b', priority: 2, value: 'two' }); heap.insert({ id: 'c', priority: 8, value: 'eight' }); const extracted = heap.extractIf(item => item.id === 'b'); expect(extracted?.id).toEqual('b'); expect(heap.size).toEqual(2); // Should not find it again const notFound = heap.extractIf(item => item.id === 'b'); expect(notFound).toBeUndefined(); }); tap.test('should extract by key', async () => { const heap = new BinaryHeap( (a, b) => a.priority - b.priority, (item) => item.id ); heap.insert({ id: 'a', priority: 5, value: 'five' }); heap.insert({ id: 'b', priority: 2, value: 'two' }); heap.insert({ id: 'c', priority: 8, value: 'eight' }); expect(heap.hasKey('b')).toBeTrue(); const extracted = heap.extractByKey('b'); expect(extracted?.id).toEqual('b'); expect(heap.size).toEqual(2); expect(heap.hasKey('b')).toBeFalse(); // Should not find it again const notFound = heap.extractByKey('b'); expect(notFound).toBeUndefined(); }); tap.test('should throw when using key operations without extractKey', async () => { const heap = new BinaryHeap((a, b) => a.priority - b.priority); heap.insert({ id: 'a', priority: 5, value: 'five' }); let error: Error | null = null; try { heap.extractByKey('a'); } catch (e: any) { error = e; } expect(error).not.toBeNull(); expect(error?.message).toContain('extractKey function must be provided'); }); tap.test('should handle duplicates correctly', async () => { const heap = new BinaryHeap((a, b) => a - b); heap.insert(5); heap.insert(5); heap.insert(5); heap.insert(3); heap.insert(7); expect(heap.size).toEqual(5); expect(heap.extract()).toEqual(3); expect(heap.extract()).toEqual(5); expect(heap.extract()).toEqual(5); expect(heap.extract()).toEqual(5); expect(heap.extract()).toEqual(7); }); tap.test('should convert to array without modifying heap', async () => { const heap = new BinaryHeap((a, b) => a - b); heap.insert(5); heap.insert(3); heap.insert(7); const array = heap.toArray(); expect(array).toContain(3); expect(array).toContain(5); expect(array).toContain(7); expect(array.length).toEqual(3); // Heap should still be intact expect(heap.size).toEqual(3); expect(heap.extract()).toEqual(3); }); tap.test('should clear the heap', async () => { const heap = new BinaryHeap( (a, b) => a.priority - b.priority, (item) => item.id ); heap.insert({ id: 'a', priority: 5, value: 'five' }); heap.insert({ id: 'b', priority: 2, value: 'two' }); expect(heap.size).toEqual(2); expect(heap.hasKey('a')).toBeTrue(); heap.clear(); expect(heap.size).toEqual(0); expect(heap.isEmpty()).toBeTrue(); expect(heap.hasKey('a')).toBeFalse(); }); tap.test('should handle complex extraction patterns', async () => { const heap = new BinaryHeap((a, b) => a - b); // Insert numbers 1-10 in random order [8, 3, 5, 9, 1, 7, 4, 10, 2, 6].forEach(n => heap.insert(n)); // Extract some in order expect(heap.extract()).toEqual(1); expect(heap.extract()).toEqual(2); // Insert more heap.insert(0); heap.insert(1.5); // Continue extracting expect(heap.extract()).toEqual(0); expect(heap.extract()).toEqual(1.5); expect(heap.extract()).toEqual(3); // Verify remaining size (10 - 2 extracted + 2 inserted - 3 extracted = 7) expect(heap.size).toEqual(7); }); tap.start();