data-structure-typed 2.2.7 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +9 -0
- package/CHANGELOG.md +1 -1
- package/README.md +14 -3
- package/README_CN.md +119 -275
- package/benchmark/report.html +1 -1
- package/benchmark/report.json +20 -324
- package/dist/cjs/index.cjs +689 -182
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +693 -185
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +689 -182
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +693 -185
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/leetcode/avl-tree-counter.mjs +2957 -0
- package/dist/leetcode/avl-tree-multi-map.mjs +2889 -0
- package/dist/leetcode/avl-tree.mjs +2720 -0
- package/dist/leetcode/binary-tree.mjs +1594 -0
- package/dist/leetcode/bst.mjs +2398 -0
- package/dist/leetcode/deque.mjs +683 -0
- package/dist/leetcode/directed-graph.mjs +1733 -0
- package/dist/leetcode/doubly-linked-list.mjs +709 -0
- package/dist/leetcode/hash-map.mjs +493 -0
- package/dist/leetcode/heap.mjs +542 -0
- package/dist/leetcode/max-heap.mjs +375 -0
- package/dist/leetcode/max-priority-queue.mjs +383 -0
- package/dist/leetcode/min-heap.mjs +363 -0
- package/dist/leetcode/min-priority-queue.mjs +371 -0
- package/dist/leetcode/priority-queue.mjs +363 -0
- package/dist/leetcode/queue.mjs +943 -0
- package/dist/leetcode/red-black-tree.mjs +2765 -0
- package/dist/leetcode/singly-linked-list.mjs +754 -0
- package/dist/leetcode/stack.mjs +217 -0
- package/dist/leetcode/tree-counter.mjs +3039 -0
- package/dist/leetcode/tree-multi-map.mjs +2913 -0
- package/dist/leetcode/trie.mjs +413 -0
- package/dist/leetcode/undirected-graph.mjs +1650 -0
- package/dist/types/data-structures/base/linear-base.d.ts +6 -6
- package/dist/types/data-structures/binary-tree/avl-tree-counter.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree-multi-map.d.ts +2 -2
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +10 -10
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +25 -27
- package/dist/types/data-structures/binary-tree/bst.d.ts +13 -12
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +151 -21
- package/dist/types/data-structures/binary-tree/tree-counter.d.ts +4 -4
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +2 -2
- package/dist/types/interfaces/binary-tree.d.ts +1 -1
- package/dist/umd/data-structure-typed.js +689 -181
- package/dist/umd/data-structure-typed.js.map +1 -1
- package/dist/umd/data-structure-typed.min.js +3 -3
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +50 -172
- package/src/data-structures/base/linear-base.ts +2 -12
- package/src/data-structures/binary-tree/avl-tree-counter.ts +6 -6
- package/src/data-structures/binary-tree/avl-tree-multi-map.ts +13 -13
- package/src/data-structures/binary-tree/avl-tree.ts +15 -15
- package/src/data-structures/binary-tree/binary-tree.ts +57 -60
- package/src/data-structures/binary-tree/bst.ts +100 -26
- package/src/data-structures/binary-tree/red-black-tree.ts +586 -76
- package/src/data-structures/binary-tree/tree-counter.ts +25 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +13 -13
- package/src/data-structures/queue/deque.ts +10 -0
- package/src/interfaces/binary-tree.ts +1 -1
- package/test/performance/data-structures/binary-tree/red-black-tree.test.ts +1 -2
- package/test/unit/data-structures/base/iterable-element-base.coverage.test.ts +106 -0
- package/test/unit/data-structures/base/iterable-element-base.more-branches.coverage.test.ts +61 -0
- package/test/unit/data-structures/base/linear-base.array.coverage.test.ts +168 -0
- package/test/unit/data-structures/base/linear-base.concat-else.coverage.test.ts +82 -0
- package/test/unit/data-structures/base/linear-base.coverage.test.ts +72 -0
- package/test/unit/data-structures/base/linear-base.more-branches.coverage.test.ts +417 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches-3.coverage.test.ts +146 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.more-branches.coverage.test.ts +93 -0
- package/test/unit/data-structures/binary-tree/avl-tree-counter.test.ts +30 -30
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.coverage.test.ts +108 -0
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.more-branches-2.coverage.test.ts +85 -0
- package/test/unit/data-structures/binary-tree/avl-tree-multi-map.test.ts +46 -46
- package/test/unit/data-structures/binary-tree/avl-tree-node.familyPosition-root-left.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/avl-tree.more-branches-2.coverage.test.ts +99 -0
- package/test/unit/data-structures/binary-tree/avl-tree.test.ts +43 -43
- package/test/unit/data-structures/binary-tree/binary-indexed-tree.more-branches.coverage.test.ts +18 -0
- package/test/unit/data-structures/binary-tree/binary-tree.more-branches.coverage.test.ts +56 -0
- package/test/unit/data-structures/binary-tree/binary-tree.remaining-branches.coverage.test.ts +229 -0
- package/test/unit/data-structures/binary-tree/binary-tree.test.ts +151 -151
- package/test/unit/data-structures/binary-tree/bst.bound-by-predicate.coverage.test.ts +33 -0
- package/test/unit/data-structures/binary-tree/bst.coverage.test.ts +94 -0
- package/test/unit/data-structures/binary-tree/bst.deletebykey.coverage.test.ts +70 -0
- package/test/unit/data-structures/binary-tree/bst.deletewhere.coverage.test.ts +37 -0
- package/test/unit/data-structures/binary-tree/bst.floor-lower-predicate.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/bst.floor-setmany.coverage.test.ts +72 -0
- package/test/unit/data-structures/binary-tree/bst.getnode.range-ensure.coverage.test.ts +22 -0
- package/test/unit/data-structures/binary-tree/bst.misc-branches.coverage.test.ts +100 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-2.coverage.test.ts +133 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-3.coverage.test.ts +45 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-4.coverage.test.ts +36 -0
- package/test/unit/data-structures/binary-tree/bst.more-branches-5.coverage.test.ts +40 -0
- package/test/unit/data-structures/binary-tree/bst.more.coverage.test.ts +39 -0
- package/test/unit/data-structures/binary-tree/bst.node-family.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/bst.range-pruning.coverage.test.ts +43 -0
- package/test/unit/data-structures/binary-tree/bst.search-fastpath.coverage.test.ts +30 -0
- package/test/unit/data-structures/binary-tree/bst.test.ts +124 -154
- package/test/unit/data-structures/binary-tree/overall.test.ts +20 -20
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-corruption-repair.coverage.test.ts +66 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-max-update.coverage.test.ts +18 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-null.coverage.test.ts +53 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-stale-cache.coverage.test.ts +25 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.boundary-update.coverage.test.ts +23 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-delete.coverage.test.ts +49 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-edge.coverage.test.ts +37 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.cache-stale-insert.coverage.test.ts +39 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.coverage.test.ts +334 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.delete-fixup.coverage.test.ts +68 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.delete-successor.coverage.test.ts +75 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.factories.coverage.test.ts +26 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-compare-update.coverage.test.ts +74 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-no-update.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-cache-nullish.coverage.test.ts +61 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-defined.coverage.test.ts +35 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-mapmode-undefined.coverage.test.ts +43 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint-more.coverage.test.ts +99 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.hint.coverage.test.ts +60 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.insert-cache-nullish.coverage.test.ts +29 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.insert-header-parent-nullish.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.internal-walk.coverage.test.ts +57 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.minmax-cache.test.ts +65 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.misc-inputs.coverage.test.ts +17 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-2.coverage.test.ts +121 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-3.coverage.test.ts +55 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.more-branches-4.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.predsucc.coverage.test.ts +40 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.remaining-branches.coverage.test.ts +123 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.set-inputs.coverage.test.ts +64 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-parent-cache.coverage.test.ts +79 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-remaining.coverage.test.ts +44 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.setkvnode-uncovered.coverage.test.ts +74 -0
- package/test/unit/data-structures/binary-tree/red-black-tree.test.ts +141 -141
- package/test/unit/data-structures/binary-tree/red-black-tree.update-branches.coverage.test.ts +30 -0
- package/test/unit/data-structures/binary-tree/segment-tree.more-branches.coverage.test.ts +31 -0
- package/test/unit/data-structures/binary-tree/tree-counter.coverage.test.ts +115 -0
- package/test/unit/data-structures/binary-tree/tree-counter.more-branches.coverage.test.ts +244 -0
- package/test/unit/data-structures/binary-tree/tree-counter.test.ts +41 -39
- package/test/unit/data-structures/binary-tree/tree-multi-map.coverage.test.ts +104 -0
- package/test/unit/data-structures/binary-tree/tree-multi-map.more-branches-2.coverage.test.ts +59 -0
- package/test/unit/data-structures/binary-tree/tree-multi-map.test.ts +145 -145
- package/test/unit/data-structures/graph/abstract-graph.more-branches-2.coverage.test.ts +40 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-3.coverage.test.ts +65 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-4.coverage.test.ts +98 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches-5.coverage.test.ts +51 -0
- package/test/unit/data-structures/graph/abstract-graph.more-branches.coverage.test.ts +62 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches-2.coverage.test.ts +38 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches-3.coverage.test.ts +25 -0
- package/test/unit/data-structures/graph/directed-graph.more-branches.coverage.test.ts +82 -0
- package/test/unit/data-structures/graph/map-graph.more-branches.coverage.test.ts +22 -0
- package/test/unit/data-structures/graph/undirected-graph.more-branches-2.coverage.test.ts +35 -0
- package/test/unit/data-structures/graph/undirected-graph.more-branches.coverage.test.ts +87 -0
- package/test/unit/data-structures/hash/hash-map.more-branches.coverage.test.ts +64 -0
- package/test/unit/data-structures/hash/hash-map.toEntryFn-branch.coverage.test.ts +9 -0
- package/test/unit/data-structures/heap/heap.misc-branches.coverage.test.ts +110 -0
- package/test/unit/data-structures/heap/heap.remaining-branches.coverage.test.ts +22 -0
- package/test/unit/data-structures/heap/max-heap.coverage.test.ts +29 -0
- package/test/unit/data-structures/linked-list/doubly-linked-list.more-branches.coverage.test.ts +72 -0
- package/test/unit/data-structures/linked-list/linked-list.unshiftMany-else.coverage.test.ts +15 -0
- package/test/unit/data-structures/linked-list/singly-linked-list.coverage.test.ts +221 -0
- package/test/unit/data-structures/linked-list/singly-linked-list.more-branches.coverage.test.ts +86 -0
- package/test/unit/data-structures/linked-list/skip-linked-list.more-branches.coverage.test.ts +31 -0
- package/test/unit/data-structures/matrix/matrix.more-branches.coverage.test.ts +81 -0
- package/test/unit/data-structures/matrix/matrix.pivotElement-nullish.coverage.test.ts +28 -0
- package/test/unit/data-structures/priority-queue/max-priority-queue.more-branches.coverage.test.ts +10 -0
- package/test/unit/data-structures/priority-queue/priority-queue.coverage.test.ts +21 -0
- package/test/unit/data-structures/queue/deque.coverage.test.ts +173 -0
- package/test/unit/data-structures/queue/deque.more-branches-2.coverage.test.ts +39 -0
- package/test/unit/data-structures/queue/deque.more-branches-3.coverage.test.ts +9 -0
- package/test/unit/data-structures/queue/deque.more-branches.coverage.test.ts +95 -0
- package/test/unit/data-structures/queue/queue.coverage.test.ts +138 -0
- package/test/unit/data-structures/queue/queue.more-branches-2.coverage.test.ts +27 -0
- package/test/unit/data-structures/stack/stack.coverage.test.ts +112 -0
- package/test/unit/data-structures/tree/tree.more-branches.coverage.test.ts +9 -0
- package/test/unit/data-structures/trie/trie.more-branches-2.coverage.test.ts +51 -0
- package/test/utils/patch.ts +33 -0
- package/tsup.config.js +50 -21
- package/tsup.umd.config.js +29 -0
- package/tsup.node.config.js +0 -83
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Heap, FibonacciHeap } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('Heap / FibonacciHeap misc branch coverage', () => {
|
|
4
|
+
it('Heap.deleteBy covers not-found, idx=0 poll, idx=last pop, idx=middle splice paths', () => {
|
|
5
|
+
const h = new Heap<number>();
|
|
6
|
+
h.add(3);
|
|
7
|
+
h.add(1);
|
|
8
|
+
h.add(2);
|
|
9
|
+
|
|
10
|
+
expect(h.deleteBy(() => false)).toBe(false); // idx stays -1
|
|
11
|
+
|
|
12
|
+
// idx === 0
|
|
13
|
+
expect(h.deleteBy(x => x === h.peek())).toBe(true);
|
|
14
|
+
|
|
15
|
+
// ensure at least 2 elems again
|
|
16
|
+
h.add(4);
|
|
17
|
+
h.add(5);
|
|
18
|
+
|
|
19
|
+
// idx === last
|
|
20
|
+
const last = (h as any).elements[(h as any).elements.length - 1];
|
|
21
|
+
expect(h.deleteBy(x => x === last)).toBe(true);
|
|
22
|
+
|
|
23
|
+
// idx in middle
|
|
24
|
+
const mid = (h as any).elements[1];
|
|
25
|
+
expect(h.deleteBy(x => x === mid)).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('Heap.filter covers thisArg branch and else(i++) branch', () => {
|
|
29
|
+
const h = new Heap<number>();
|
|
30
|
+
h.add(1);
|
|
31
|
+
h.add(2);
|
|
32
|
+
h.add(3);
|
|
33
|
+
|
|
34
|
+
const ctx = { ok: true };
|
|
35
|
+
const out = h.filter(function (this: any, x: number) {
|
|
36
|
+
// keep only one element so the else branch runs too
|
|
37
|
+
return this.ok && x === 2;
|
|
38
|
+
}, ctx);
|
|
39
|
+
|
|
40
|
+
expect(out.toArray()).toEqual([2]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('Heap.map throws when comparator missing, and uses thisArg branch when provided', () => {
|
|
44
|
+
const h = new Heap<number>();
|
|
45
|
+
h.add(1);
|
|
46
|
+
h.add(2);
|
|
47
|
+
|
|
48
|
+
expect(() => h.map(x => ({ x }), {} as any)).toThrow(/requires options\.comparator/i);
|
|
49
|
+
|
|
50
|
+
const ctx = { mul: 10 };
|
|
51
|
+
const mapped = h.map(
|
|
52
|
+
function (this: any, x: number) {
|
|
53
|
+
return x * this.mul;
|
|
54
|
+
},
|
|
55
|
+
{ comparator: (a: number, b: number) => a - b },
|
|
56
|
+
ctx
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(mapped.peek()).toBe(10);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('Heap.mapSame covers thisArg branch', () => {
|
|
63
|
+
const h = new Heap<number>();
|
|
64
|
+
h.add(1);
|
|
65
|
+
h.add(3);
|
|
66
|
+
|
|
67
|
+
const ctx = { add: 7 };
|
|
68
|
+
const out = h.mapSame(function (this: any, x: number) {
|
|
69
|
+
return x + this.add;
|
|
70
|
+
}, ctx);
|
|
71
|
+
|
|
72
|
+
expect(out.peek()).toBe(8);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('Heap._createLike default-arg path can be called via (heap as any)._createLike()', () => {
|
|
76
|
+
const h = new Heap<number>();
|
|
77
|
+
const like = (h as any)._createLike();
|
|
78
|
+
expect(like.size).toBe(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('FibonacciHeap constructor throws when comparator is not a function', () => {
|
|
82
|
+
expect(() => new FibonacciHeap<number>(123 as any)).toThrow(/comparator must be a function/i);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('FibonacciHeap.consumeLinkedList(undefined) returns [] (covers !head guard)', () => {
|
|
86
|
+
const fh = new FibonacciHeap<number>();
|
|
87
|
+
expect(fh.consumeLinkedList(undefined)).toEqual([]);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('FibonacciHeap.merge covers empty-merge early return, empty-this adopt-root, and non-empty root-merge', () => {
|
|
91
|
+
const a = new FibonacciHeap<number>();
|
|
92
|
+
const b = new FibonacciHeap<number>();
|
|
93
|
+
|
|
94
|
+
// empty merge early return
|
|
95
|
+
a.merge(b);
|
|
96
|
+
expect(a.size).toBe(0);
|
|
97
|
+
|
|
98
|
+
// empty-this adopt-root
|
|
99
|
+
b.add(5);
|
|
100
|
+
a.merge(b);
|
|
101
|
+
expect(a.size).toBe(1);
|
|
102
|
+
|
|
103
|
+
// non-empty root-merge + min update paths
|
|
104
|
+
const c = new FibonacciHeap<number>();
|
|
105
|
+
c.add(1);
|
|
106
|
+
c.add(10);
|
|
107
|
+
a.merge(c);
|
|
108
|
+
expect(a.peek()).toBe(1);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Heap } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('Heap remaining branch coverage', () => {
|
|
4
|
+
it('Heap.map with options undefined hits (options ?? {}) path and throws for missing comparator', () => {
|
|
5
|
+
const h = new Heap<number>();
|
|
6
|
+
h.add(1);
|
|
7
|
+
expect(() => (h as any).map((x: number) => x, undefined)).toThrow(/requires options\.comparator/i);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('Heap.mapSame without thisArg hits thisArg===undefined branch', () => {
|
|
11
|
+
const h = new Heap<number>();
|
|
12
|
+
h.add(1);
|
|
13
|
+
h.add(2);
|
|
14
|
+
const out = h.mapSame(x => x * 2);
|
|
15
|
+
expect(out.toArray().sort((a, b) => a - b)).toEqual([2, 4]);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('Heap default comparator throws when comparing object types', () => {
|
|
19
|
+
const h = new Heap<any>();
|
|
20
|
+
expect(() => (h as any)._DEFAULT_COMPARATOR({}, 1)).toThrow(TypeError);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MaxHeap } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Coverage-focused test for MaxHeap comparator branches.
|
|
5
|
+
* Keep existing @example tests intact.
|
|
6
|
+
*/
|
|
7
|
+
describe('MaxHeap coverage', () => {
|
|
8
|
+
it('orders numbers as a max-heap (a<b / a>b / equal branches)', () => {
|
|
9
|
+
const h = new MaxHeap<number>();
|
|
10
|
+
|
|
11
|
+
h.add(2);
|
|
12
|
+
h.add(1);
|
|
13
|
+
h.add(3);
|
|
14
|
+
h.add(3); // equal branch exercised during comparisons
|
|
15
|
+
|
|
16
|
+
expect(h.peek()).toBe(3);
|
|
17
|
+
expect(h.poll()).toBe(3);
|
|
18
|
+
expect(h.poll()).toBe(3);
|
|
19
|
+
expect(h.poll()).toBe(2);
|
|
20
|
+
expect(h.poll()).toBe(1);
|
|
21
|
+
expect(h.poll()).toBe(undefined);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('throws when comparing object types without custom comparator', () => {
|
|
25
|
+
const h = new MaxHeap<any>();
|
|
26
|
+
h.add({ k: 1 });
|
|
27
|
+
expect(() => h.add({ k: 2 })).toThrow(TypeError);
|
|
28
|
+
});
|
|
29
|
+
});
|
package/test/unit/data-structures/linked-list/doubly-linked-list.more-branches.coverage.test.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { DoublyLinkedList, DoublyLinkedListNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('DoublyLinkedList additional branch coverage', () => {
|
|
4
|
+
it('unshiftMany uses toElementFn branch when provided', () => {
|
|
5
|
+
const l = new DoublyLinkedList<number, { v: number }>([], {
|
|
6
|
+
toElementFn: r => r.v
|
|
7
|
+
});
|
|
8
|
+
expect(l.unshiftMany([{ v: 1 }, { v: 2 }])).toEqual([true, true]);
|
|
9
|
+
expect(l.toArray()).toEqual([2, 1]);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('getNode(undefined) returns undefined (covers early return)', () => {
|
|
13
|
+
const l = new DoublyLinkedList<number>();
|
|
14
|
+
l.pushMany([1, 2]);
|
|
15
|
+
expect(l.getNode(undefined)).toBeUndefined();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('setAt returns false when node does not exist', () => {
|
|
19
|
+
const l = new DoublyLinkedList<number>();
|
|
20
|
+
expect(l.setAt(0, 1)).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('search returns value when predicate matches (covers predicate(current) true branch)', () => {
|
|
24
|
+
const l = new DoublyLinkedList<number>();
|
|
25
|
+
l.pushMany([1, 2, 3]);
|
|
26
|
+
expect(l.search(n => n.value === 2)).toBe(2);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('mapSame covers both thisArg branches', () => {
|
|
30
|
+
const l = new DoublyLinkedList<number>();
|
|
31
|
+
l.pushMany([1, 2]);
|
|
32
|
+
|
|
33
|
+
// thisArg === undefined arm
|
|
34
|
+
expect(l.mapSame(v => v + 1).toArray()).toEqual([2, 3]);
|
|
35
|
+
|
|
36
|
+
// thisArg provided arm
|
|
37
|
+
const ctx = { add: 10 };
|
|
38
|
+
expect(
|
|
39
|
+
l
|
|
40
|
+
.mapSame(function (this: any, v: number) {
|
|
41
|
+
return v + this.add;
|
|
42
|
+
}, ctx)
|
|
43
|
+
.toArray()
|
|
44
|
+
).toEqual([11, 12]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('_ensureNode returns the same node when input is a node (covers isNode true branch)', () => {
|
|
48
|
+
const l = new DoublyLinkedList<number>();
|
|
49
|
+
l.pushMany([1, 3]);
|
|
50
|
+
|
|
51
|
+
const existing = l.getNodeAt(0)!;
|
|
52
|
+
const newNode = new DoublyLinkedListNode(2);
|
|
53
|
+
|
|
54
|
+
// addAfter calls _ensureNode(newElementOrNode)
|
|
55
|
+
expect(l.addAfter(existing, newNode)).toBe(true);
|
|
56
|
+
expect(l.toArray()).toEqual([1, 2, 3]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('_ensurePredicate covers isNode(target) branch via search(node)', () => {
|
|
60
|
+
const l = new DoublyLinkedList<number>();
|
|
61
|
+
l.pushMany([1, 2, 3]);
|
|
62
|
+
|
|
63
|
+
const target = l.getNodeAt(1)!;
|
|
64
|
+
expect(l.search(target)).toBe(2);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('_createLike default-arg path can be called with no args', () => {
|
|
68
|
+
const l = new DoublyLinkedList<number>();
|
|
69
|
+
const like = (l as any)._createLike();
|
|
70
|
+
expect(like.length).toBe(0);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DoublyLinkedList, SinglyLinkedList } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('LinkedList unshiftMany else-branch coverage', () => {
|
|
4
|
+
it('DoublyLinkedList.unshiftMany uses else-branch when toElementFn is not provided', () => {
|
|
5
|
+
const l = new DoublyLinkedList<number>();
|
|
6
|
+
expect(l.unshiftMany([1, 2])).toEqual([true, true]);
|
|
7
|
+
expect(l.toArray()).toEqual([2, 1]);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('SinglyLinkedList.unshiftMany uses else-branch when toElementFn is not provided', () => {
|
|
11
|
+
const l = new SinglyLinkedList<number>();
|
|
12
|
+
expect(l.unshiftMany([1, 2])).toEqual([true, true]);
|
|
13
|
+
expect(l.toArray()).toEqual([2, 1]);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { SinglyLinkedList, SinglyLinkedListNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('SinglyLinkedList coverage', () => {
|
|
4
|
+
it('push respects maxLen by shifting when over capacity', () => {
|
|
5
|
+
const list = new SinglyLinkedList<number>([], { maxLen: 2 });
|
|
6
|
+
list.push(1);
|
|
7
|
+
list.push(2);
|
|
8
|
+
list.push(3); // should shift 1
|
|
9
|
+
expect([...list]).toEqual([2, 3]);
|
|
10
|
+
expect(list.length).toBe(2);
|
|
11
|
+
expect(list.first).toBe(2);
|
|
12
|
+
expect(list.last).toBe(3);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('pop covers empty, single-node, and multi-node cases', () => {
|
|
16
|
+
const empty = new SinglyLinkedList<number>();
|
|
17
|
+
expect(empty.pop()).toBeUndefined();
|
|
18
|
+
|
|
19
|
+
const single = new SinglyLinkedList<number>([1]);
|
|
20
|
+
expect(single.pop()).toBe(1);
|
|
21
|
+
expect(single.length).toBe(0);
|
|
22
|
+
expect(single.head).toBeUndefined();
|
|
23
|
+
expect(single.tail).toBeUndefined();
|
|
24
|
+
|
|
25
|
+
const multi = new SinglyLinkedList<number>([1, 2, 3]);
|
|
26
|
+
expect(multi.pop()).toBe(3);
|
|
27
|
+
expect([...multi]).toEqual([1, 2]);
|
|
28
|
+
expect(multi.tail?.value).toBe(2);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('shift/unshift handle empty and update tail when last removed', () => {
|
|
32
|
+
const list = new SinglyLinkedList<number>();
|
|
33
|
+
expect(list.shift()).toBeUndefined();
|
|
34
|
+
|
|
35
|
+
list.unshift(1);
|
|
36
|
+
expect(list.shift()).toBe(1);
|
|
37
|
+
expect(list.head).toBeUndefined();
|
|
38
|
+
expect(list.tail).toBeUndefined();
|
|
39
|
+
expect(list.length).toBe(0);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('pushMany/unshiftMany exercise toElementFn conversion branch', () => {
|
|
43
|
+
const list = new SinglyLinkedList<number, { v: number }>([], { toElementFn: r => r.v });
|
|
44
|
+
|
|
45
|
+
expect(list.pushMany([{ v: 1 }, { v: 2 }])).toEqual([true, true]);
|
|
46
|
+
expect([...list]).toEqual([1, 2]);
|
|
47
|
+
|
|
48
|
+
expect(list.unshiftMany([{ v: 3 }, { v: 4 }])).toEqual([true, true]);
|
|
49
|
+
expect([...list]).toEqual([4, 3, 1, 2]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('at/getNodeAt/setAt cover bounds and success cases', () => {
|
|
53
|
+
const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
54
|
+
|
|
55
|
+
expect(list.at(-1)).toBeUndefined();
|
|
56
|
+
expect(list.at(999)).toBeUndefined();
|
|
57
|
+
expect(list.at(1)).toBe(2);
|
|
58
|
+
|
|
59
|
+
expect(list.getNodeAt(-1)).toBeUndefined();
|
|
60
|
+
expect(list.getNodeAt(999)).toBeUndefined();
|
|
61
|
+
|
|
62
|
+
expect(list.setAt(999, 0)).toBe(false);
|
|
63
|
+
expect(list.setAt(1, 20)).toBe(true);
|
|
64
|
+
expect([...list]).toEqual([1, 20, 3]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('deleteAt covers head delete, tail delete, and middle delete', () => {
|
|
68
|
+
const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
69
|
+
|
|
70
|
+
expect(list.deleteAt(-1)).toBeUndefined();
|
|
71
|
+
expect(list.deleteAt(999)).toBeUndefined();
|
|
72
|
+
|
|
73
|
+
// head
|
|
74
|
+
expect(list.deleteAt(0)).toBe(1);
|
|
75
|
+
expect([...list]).toEqual([2, 3]);
|
|
76
|
+
|
|
77
|
+
// tail
|
|
78
|
+
expect(list.deleteAt(1)).toBe(3);
|
|
79
|
+
expect([...list]).toEqual([2]);
|
|
80
|
+
expect(list.tail?.value).toBe(2);
|
|
81
|
+
|
|
82
|
+
// middle (rebuild)
|
|
83
|
+
list.pushMany([3, 4]); // [2,3,4]
|
|
84
|
+
expect(list.deleteAt(1)).toBe(3);
|
|
85
|
+
expect([...list]).toEqual([2, 4]);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('delete covers undefined input, missing node, and deleting head/tail', () => {
|
|
89
|
+
const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
90
|
+
|
|
91
|
+
expect(list.delete(undefined)).toBe(false);
|
|
92
|
+
expect(list.delete(999)).toBe(false);
|
|
93
|
+
|
|
94
|
+
// delete head
|
|
95
|
+
expect(list.delete(1)).toBe(true);
|
|
96
|
+
expect([...list]).toEqual([2, 3]);
|
|
97
|
+
|
|
98
|
+
// delete tail
|
|
99
|
+
expect(list.delete(3)).toBe(true);
|
|
100
|
+
expect([...list]).toEqual([2]);
|
|
101
|
+
expect(list.tail?.value).toBe(2);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('reverse early-return and full reverse path', () => {
|
|
105
|
+
const empty = new SinglyLinkedList<number>();
|
|
106
|
+
expect(empty.reverse()).toBe(empty);
|
|
107
|
+
|
|
108
|
+
const single = new SinglyLinkedList<number>([1]);
|
|
109
|
+
expect([...single.reverse()]).toEqual([1]);
|
|
110
|
+
|
|
111
|
+
const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
112
|
+
list.reverse();
|
|
113
|
+
expect([...list]).toEqual([3, 2, 1]);
|
|
114
|
+
expect(list.first).toBe(3);
|
|
115
|
+
expect(list.last).toBe(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('getNode/search handle undefined, node pass-through, and predicate branches', () => {
|
|
119
|
+
const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
120
|
+
expect(list.getNode(undefined)).toBeUndefined();
|
|
121
|
+
|
|
122
|
+
const n2 = list.getNodeAt(1)!;
|
|
123
|
+
expect(list.getNode(n2)).toBe(n2);
|
|
124
|
+
|
|
125
|
+
expect(list.getNode(node => node.value === 3)?.value).toBe(3);
|
|
126
|
+
expect(list.search(node => node.value === 2)).toBe(2);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('addAt/addBefore/addAfter cover boundary and missing-node cases', () => {
|
|
130
|
+
const list = new SinglyLinkedList<number>([2, 4]);
|
|
131
|
+
|
|
132
|
+
expect(list.addAt(-1, 0)).toBe(false);
|
|
133
|
+
expect(list.addAt(999, 0)).toBe(false);
|
|
134
|
+
|
|
135
|
+
// addAt head/tail/middle
|
|
136
|
+
expect(list.addAt(0, 1)).toBe(true);
|
|
137
|
+
expect(list.addAt(list.length, 5)).toBe(true);
|
|
138
|
+
expect(list.addAt(2, 3)).toBe(true);
|
|
139
|
+
expect([...list]).toEqual([1, 2, 3, 4, 5]);
|
|
140
|
+
|
|
141
|
+
// addBefore/After missing
|
|
142
|
+
expect(list.addBefore(999, 0)).toBe(false);
|
|
143
|
+
expect(list.addAfter(999, 0)).toBe(false);
|
|
144
|
+
|
|
145
|
+
// addBefore head
|
|
146
|
+
expect(list.addBefore(1, 0)).toBe(true);
|
|
147
|
+
// addAfter tail
|
|
148
|
+
expect(list.addAfter(5, 6)).toBe(true);
|
|
149
|
+
expect([...list]).toEqual([0, 1, 2, 3, 4, 5, 6]);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('splice covers remove-only, insert-only, remove+insert, and empty-result reset', () => {
|
|
153
|
+
const list = new SinglyLinkedList<number>([1, 2, 3, 4]);
|
|
154
|
+
|
|
155
|
+
// remove middle
|
|
156
|
+
const removed = list.splice(1, 2);
|
|
157
|
+
expect([...removed]).toEqual([2, 3]);
|
|
158
|
+
expect([...list]).toEqual([1, 4]);
|
|
159
|
+
|
|
160
|
+
// insert at head without deletion
|
|
161
|
+
const removed2 = list.splice(0, 0, 9, 8);
|
|
162
|
+
expect([...removed2]).toEqual([]);
|
|
163
|
+
expect([...list]).toEqual([9, 8, 1, 4]);
|
|
164
|
+
|
|
165
|
+
// remove tail and insert
|
|
166
|
+
const removed3 = list.splice(3, 10, 7);
|
|
167
|
+
expect([...removed3]).toEqual([4]);
|
|
168
|
+
expect([...list]).toEqual([9, 8, 1, 7]);
|
|
169
|
+
|
|
170
|
+
// remove everything, expect head/tail reset
|
|
171
|
+
const removedAll = list.splice(0, 999);
|
|
172
|
+
expect([...removedAll]).toEqual([9, 8, 1, 7]);
|
|
173
|
+
expect(list.length).toBe(0);
|
|
174
|
+
expect(list.head).toBeUndefined();
|
|
175
|
+
expect(list.tail).toBeUndefined();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('countOccurrences covers element/node/predicate branches and setEquality', () => {
|
|
179
|
+
type Obj = { id: number };
|
|
180
|
+
const a: Obj = { id: 1 };
|
|
181
|
+
const b: Obj = { id: 1 };
|
|
182
|
+
const c: Obj = { id: 2 };
|
|
183
|
+
|
|
184
|
+
const list = new SinglyLinkedList<Obj>([a, c]);
|
|
185
|
+
|
|
186
|
+
// default Object.is: b is not the same ref as a
|
|
187
|
+
expect(list.countOccurrences(b)).toBe(0);
|
|
188
|
+
|
|
189
|
+
list.setEquality((x, y) => x.id === y.id);
|
|
190
|
+
expect(list.countOccurrences(b)).toBe(1);
|
|
191
|
+
|
|
192
|
+
const nodeA = list.getNodeAt(0)!;
|
|
193
|
+
expect(list.countOccurrences(nodeA)).toBe(1);
|
|
194
|
+
|
|
195
|
+
expect(list.countOccurrences(node => node.value.id === 2)).toBe(1);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('deleteWhere covers deleting head and tail branches + no-match', () => {
|
|
199
|
+
const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
200
|
+
|
|
201
|
+
// delete head branch
|
|
202
|
+
expect(list.deleteWhere(v => v === 1)).toBe(true);
|
|
203
|
+
expect([...list]).toEqual([2, 3]);
|
|
204
|
+
|
|
205
|
+
// delete tail branch
|
|
206
|
+
expect(list.deleteWhere(v => v === 3)).toBe(true);
|
|
207
|
+
expect([...list]).toEqual([2]);
|
|
208
|
+
expect(list.tail?.value).toBe(2);
|
|
209
|
+
|
|
210
|
+
// no match
|
|
211
|
+
expect(list.deleteWhere(v => v === 999)).toBe(false);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('_getPrevNode not-found branch via foreign node', () => {
|
|
215
|
+
const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
216
|
+
const foreign = new SinglyLinkedListNode(2);
|
|
217
|
+
|
|
218
|
+
// Access protected for branch coverage.
|
|
219
|
+
expect((list as any)._getPrevNode(foreign)).toBeUndefined();
|
|
220
|
+
});
|
|
221
|
+
});
|
package/test/unit/data-structures/linked-list/singly-linked-list.more-branches.coverage.test.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { SinglyLinkedList, SinglyLinkedListNode } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('SinglyLinkedList additional branch coverage', () => {
|
|
4
|
+
it('unshiftMany uses toElementFn branch when provided', () => {
|
|
5
|
+
const l = new SinglyLinkedList<number, { v: number }>([], {
|
|
6
|
+
toElementFn: r => r.v
|
|
7
|
+
});
|
|
8
|
+
expect(l.unshiftMany([{ v: 1 }, { v: 2 }])).toEqual([true, true]);
|
|
9
|
+
expect(l.toArray()).toEqual([2, 1]);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('addBefore sets tail when prevNode is undefined and internal tail is missing (covers if(!this._tail))', () => {
|
|
13
|
+
const l = new SinglyLinkedList<number>();
|
|
14
|
+
l.push(1);
|
|
15
|
+
|
|
16
|
+
// Corrupt internal tail so the recovery branch runs.
|
|
17
|
+
(l as any)._tail = undefined;
|
|
18
|
+
|
|
19
|
+
expect(l.addBefore(1, 0)).toBe(true);
|
|
20
|
+
expect(l.toArray()).toEqual([0, 1]);
|
|
21
|
+
// and tail should be restored (best-effort invariant)
|
|
22
|
+
expect((l as any)._tail).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('splice uses default deleteCount=0 when omitted', () => {
|
|
26
|
+
const l = new SinglyLinkedList<number>();
|
|
27
|
+
l.pushMany([1, 2, 3]);
|
|
28
|
+
|
|
29
|
+
const removed = l.splice(1); // deleteCount omitted
|
|
30
|
+
expect(removed.toArray()).toEqual([]);
|
|
31
|
+
expect(l.toArray()).toEqual([1, 2, 3]);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('deleteWhere sets tail to undefined when removing the only element (covers current===_tail branch)', () => {
|
|
35
|
+
const l = new SinglyLinkedList<number>();
|
|
36
|
+
l.push(1);
|
|
37
|
+
|
|
38
|
+
expect(l.deleteWhere(v => v === 1)).toBe(true);
|
|
39
|
+
expect(l.length).toBe(0);
|
|
40
|
+
expect((l as any)._tail).toBeUndefined();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('mapSame covers both ternary arms (thisArg undefined vs defined)', () => {
|
|
44
|
+
const l = new SinglyLinkedList<number>();
|
|
45
|
+
l.pushMany([1, 2]);
|
|
46
|
+
|
|
47
|
+
// thisArg === undefined branch
|
|
48
|
+
expect(l.mapSame(v => v + 1).toArray()).toEqual([2, 3]);
|
|
49
|
+
|
|
50
|
+
// thisArg provided branch
|
|
51
|
+
const ctx = { add: 10 };
|
|
52
|
+
expect(
|
|
53
|
+
l
|
|
54
|
+
.mapSame(function (this: any, v: number) {
|
|
55
|
+
return v + this.add;
|
|
56
|
+
}, ctx)
|
|
57
|
+
.toArray()
|
|
58
|
+
).toEqual([11, 12]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('_ensureNode returns the same node when input is a node (covers isNode true branch)', () => {
|
|
62
|
+
const l = new SinglyLinkedList<number>();
|
|
63
|
+
l.pushMany([1, 3]);
|
|
64
|
+
|
|
65
|
+
const existing = l.getNodeAt(0)!;
|
|
66
|
+
const newNode = new SinglyLinkedListNode(2);
|
|
67
|
+
|
|
68
|
+
// addAfter calls _ensureNode(newElementOrNode)
|
|
69
|
+
expect(l.addAfter(existing, newNode)).toBe(true);
|
|
70
|
+
expect(l.toArray()).toEqual([1, 2, 3]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('_ensurePredicate covers isNode(target) branch via search(node)', () => {
|
|
74
|
+
const l = new SinglyLinkedList<number>();
|
|
75
|
+
l.pushMany([1, 2, 3]);
|
|
76
|
+
|
|
77
|
+
const target = l.getNodeAt(1)!;
|
|
78
|
+
expect(l.search(target)).toBe(2);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('_createLike default-arg path can be called with no args', () => {
|
|
82
|
+
const l = new SinglyLinkedList<number>();
|
|
83
|
+
const like = (l as any)._createLike();
|
|
84
|
+
expect(like.length).toBe(0);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SkipList } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('SkipList additional branch coverage', () => {
|
|
4
|
+
it('constructor applies options branches (maxLevel/probability) and first() returns undefined when empty', () => {
|
|
5
|
+
const s = new SkipList<number, number>([], { maxLevel: 8, probability: 0.25 });
|
|
6
|
+
expect(s.maxLevel).toBe(8);
|
|
7
|
+
expect(s.probability).toBe(0.25);
|
|
8
|
+
|
|
9
|
+
// covers `firstNode ? ... : undefined` false arm
|
|
10
|
+
expect(s.first).toBeUndefined();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('delete() covers the break branch when deleted node has smaller level than list level', () => {
|
|
14
|
+
const s = new SkipList<number, string>();
|
|
15
|
+
|
|
16
|
+
// Force deterministic node levels: first node makes list level high, second is low-level.
|
|
17
|
+
const origRandomLevel = (s as any)._randomLevel;
|
|
18
|
+
const levels = [4, 1];
|
|
19
|
+
(s as any)._randomLevel = () => levels.shift() ?? 1;
|
|
20
|
+
try {
|
|
21
|
+
s.add(1, 'hi'); // level 4, end -> raises list level
|
|
22
|
+
s.add(2, 'lo'); // level 1, end, list level stays 4
|
|
23
|
+
|
|
24
|
+
expect(s.level).toBeGreaterThan(1);
|
|
25
|
+
expect(s.delete(2)).toBe(true);
|
|
26
|
+
expect(s.get(2)).toBeUndefined();
|
|
27
|
+
} finally {
|
|
28
|
+
(s as any)._randomLevel = origRandomLevel;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Matrix } from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('Matrix additional branch coverage', () => {
|
|
4
|
+
it('inverse throws when matrix is singular (pivotRow reaches rows)', () => {
|
|
5
|
+
const m = new Matrix([[0]], { rows: 1, cols: 1 });
|
|
6
|
+
expect(() => m.inverse()).toThrow(/singular/i);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('inverse hits division-by-zero guard (pivotElement===0) via get() monkeypatch', () => {
|
|
10
|
+
const m = new Matrix(
|
|
11
|
+
[
|
|
12
|
+
[1, 0],
|
|
13
|
+
[0, 1]
|
|
14
|
+
],
|
|
15
|
+
{ rows: 2, cols: 2 }
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const origGet = (Matrix as any).prototype.get;
|
|
19
|
+
try {
|
|
20
|
+
(Matrix as any).prototype.get = function (row: number, col: number) {
|
|
21
|
+
// Make pivot search succeed (non-zero) but pivot element read as 0.
|
|
22
|
+
if (row === col) return 0;
|
|
23
|
+
return 1;
|
|
24
|
+
};
|
|
25
|
+
expect(() => m.inverse()).toThrow(/division by zero/i);
|
|
26
|
+
} finally {
|
|
27
|
+
(Matrix as any).prototype.get = origGet;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('inverse treats undefined elimination factor as 0 (factor===undefined branch)', () => {
|
|
32
|
+
const m = new Matrix(
|
|
33
|
+
[
|
|
34
|
+
[1, 0],
|
|
35
|
+
[0, 1]
|
|
36
|
+
],
|
|
37
|
+
{ rows: 2, cols: 2 }
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const origGet = (Matrix as any).prototype.get;
|
|
41
|
+
try {
|
|
42
|
+
(Matrix as any).prototype.get = function (row: number, col: number) {
|
|
43
|
+
// Provide real diagonal for pivoting
|
|
44
|
+
if (row === col) return 1;
|
|
45
|
+
// For elimination factor reads (j,i) when j!=i, return undefined
|
|
46
|
+
return undefined;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Should still return something (we only care about branch execution)
|
|
50
|
+
const inv = m.inverse();
|
|
51
|
+
expect(inv?.rows).toBe(2);
|
|
52
|
+
expect(inv?.cols).toBe(2);
|
|
53
|
+
} finally {
|
|
54
|
+
(Matrix as any).prototype.get = origGet;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('_scaleRow and _addScaledRow coerce undefined multiply/add results to 0', () => {
|
|
59
|
+
const m = new Matrix(
|
|
60
|
+
[
|
|
61
|
+
[1, 2],
|
|
62
|
+
[3, 4]
|
|
63
|
+
],
|
|
64
|
+
{
|
|
65
|
+
rows: 2,
|
|
66
|
+
cols: 2,
|
|
67
|
+
multiplyFn: () => undefined as any,
|
|
68
|
+
addFn: () => undefined as any
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// call protected helpers via any
|
|
73
|
+
(m as any)._scaleRow(0, 2);
|
|
74
|
+
expect(m.data[0][0]).toBe(0);
|
|
75
|
+
expect(m.data[0][1]).toBe(0);
|
|
76
|
+
|
|
77
|
+
(m as any)._addScaledRow(1, 0, 3);
|
|
78
|
+
expect(m.data[1][0]).toBe(0);
|
|
79
|
+
expect(m.data[1][1]).toBe(0);
|
|
80
|
+
});
|
|
81
|
+
});
|