test: The test cases have been added, though slightly tricky. The overall test coverage is currently at 93.27%.

This commit is contained in:
Revone 2024-10-16 21:55:48 +13:00
parent e6acc0f8f1
commit 07dd75de70
28 changed files with 1024 additions and 352 deletions

View file

@ -163,8 +163,8 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
if (this.isEntry(rawEle)) {
key = rawEle[0];
value = rawEle[1];
} else if (this.toEntryFn) {
const item = this.toEntryFn(rawEle);
} else if (this._toEntryFn) {
const item = this._toEntryFn(rawEle);
key = item[0];
value = item[1];
}
@ -244,7 +244,7 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
* @return A new hashmap with the same values as this one
*/
clone(): HashMap<K, V, R> {
return new HashMap<K, V, R>(this, { hashFn: this.hashFn, toEntryFn: this.toEntryFn });
return new HashMap<K, V, R>(this, { hashFn: this._hashFn, toEntryFn: this._toEntryFn });
}
/**
@ -302,18 +302,6 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
return filteredMap;
}
/**
* The put function sets a value in a data structure using a specified key.
* @param {K} key - The key parameter is of type K, which represents the type of the key being passed
* to the function.
* @param {V} value - The value parameter represents the value that you want to associate with the
* specified key in the data structure.
* @returns The method is returning a boolean value.
*/
put(key: K, value: V): boolean {
return this.set(key, value);
}
/**
* The function returns an iterator that yields key-value pairs from both an object store and an
* object map.
@ -349,7 +337,7 @@ export class HashMap<K = any, V = any, R = [K, V]> extends IterableEntryBase<K,
let strKey: string;
if (keyType !== 'string' && keyType !== 'number' && keyType !== 'symbol') {
strKey = this.hashFn(key);
strKey = this._hashFn(key);
} else {
if (keyType === 'number') {
// TODO numeric key should has its own hash
@ -379,7 +367,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
* @param [options] - The `options` parameter is an optional object that can contain the following
* properties:
*/
constructor(entryOrRawElements: Iterable<R> = [], options?: LinkedHashMapOptions<K, V, R>) {
constructor(entryOrRawElements: Iterable<R | [K, V]> = [], options?: LinkedHashMapOptions<K, V, R>) {
super();
this._sentinel = <HashMapLinkedNode<K, V>>{};
this._sentinel.prev = this._sentinel.next = this._head = this._tail = this._sentinel;
@ -395,10 +383,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
}
if (entryOrRawElements) {
for (const el of entryOrRawElements) {
const [key, value] = this.toEntryFn(el);
this.set(key, value);
}
this.setMany(entryOrRawElements);
}
}
@ -465,7 +450,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
return this._tail;
}
protected _toEntryFn: (rawElement: R) => [K, V] = (rawElement: R) => {
protected _toEntryFn?: (rawElement: R) => [K, V] = (rawElement: R) => {
if (this.isEntry(rawElement)) {
// TODO, For performance optimization, it may be necessary to only inspect the first element traversed.
return rawElement;
@ -575,7 +560,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
const isNewKey = !this.has(key); // Check if the key is new
if (isWeakKey(key)) {
const hash = this.objHashFn(key);
const hash = this._objHashFn(key);
node = this.objMap.get(hash);
if (!node && isNewKey) {
@ -587,7 +572,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
node.value = value;
}
} else {
const hash = this.hashFn(key);
const hash = this._hashFn(key);
node = this.noObjMap[hash];
if (!node && isNewKey) {
@ -623,11 +608,20 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
* R.
* @returns The `setMany` function returns an array of booleans.
*/
setMany(entryOrRawElements: Iterable<R>): boolean[] {
setMany(entryOrRawElements: Iterable<R | [K, V]>): boolean[] {
const results: boolean[] = [];
for (const rawEle of entryOrRawElements) {
const [key, value] = this.toEntryFn(rawEle);
results.push(this.set(key, value));
let key: K | undefined, value: V | undefined;
if (this.isEntry(rawEle)) {
key = rawEle[0];
value = rawEle[1];
} else if (this._toEntryFn) {
const item = this._toEntryFn(rawEle);
key = item[0];
value = item[1];
}
if (key !== undefined && value !== undefined) results.push(this.set(key, value));
}
return results;
}
@ -640,10 +634,10 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
*/
override has(key: K): boolean {
if (isWeakKey(key)) {
const hash = this.objHashFn(key);
const hash = this._objHashFn(key);
return this.objMap.has(hash);
} else {
const hash = this.hashFn(key);
const hash = this._hashFn(key);
return hash in this.noObjMap;
}
}
@ -668,11 +662,11 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
*/
override get(key: K): V | undefined {
if (isWeakKey(key)) {
const hash = this.objHashFn(key);
const hash = this._objHashFn(key);
const node = this.objMap.get(hash);
return node ? node.value : undefined;
} else {
const hash = this.hashFn(key);
const hash = this._hashFn(key);
const node = this.noObjMap[hash];
return node ? node.value : undefined;
}
@ -722,7 +716,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
let node;
if (isWeakKey(key)) {
const hash = this.objHashFn(key);
const hash = this._objHashFn(key);
// Get nodes from WeakMap
node = this.objMap.get(hash);
@ -733,7 +727,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
// Remove nodes from WeakMap
this.objMap.delete(hash);
} else {
const hash = this.hashFn(key);
const hash = this._hashFn(key);
// Get nodes from noObjMap
node = this.noObjMap[hash];
@ -832,7 +826,7 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
* of the original `LinkedHashMap` object.
*/
clone(): LinkedHashMap<K, V> {
const cloned = new LinkedHashMap<K, V>([], { hashFn: this.hashFn, objHashFn: this.objHashFn });
const cloned = new LinkedHashMap<K, V>([], { hashFn: this._hashFn, objHashFn: this._objHashFn });
for (const entry of this) {
const [key, value] = entry;
cloned.set(key, value);
@ -905,26 +899,6 @@ export class LinkedHashMap<K = any, V = any, R = [K, V]> extends IterableEntryBa
return mappedMap;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The put function sets a value in a data structure using a specified key.
* @param {K} key - The key parameter is of type K, which represents the type of the key being passed
* to the function.
* @param {V} value - The value parameter represents the value that you want to associate with the
* specified key in the data structure.
* @returns The method is returning a boolean value.
*/
put(key: K, value: V): boolean {
return this.set(key, value);
}
/**
* Time Complexity: O(n)
* Space Complexity: O(1)

View file

@ -350,7 +350,7 @@ export class SinglyLinkedList<E = any, R = any> extends IterableElementBase<E, R
* successfully deleted from the linked list, and `false` if the value or node is not found in the linked list.
*/
delete(valueOrNode: E | SinglyLinkedListNode<E> | undefined): boolean {
if (!valueOrNode) return false;
if (valueOrNode === undefined) return false;
let value: E;
if (valueOrNode instanceof SinglyLinkedListNode) {
value = valueOrNode.value;

View file

@ -507,7 +507,6 @@ export class Deque<E = any, R = any> extends IterableElementBase<E, R, Deque<E,
cutRest(pos: number, isCutSelf = false): Deque<E> {
if (isCutSelf) {
if (pos < 0) {
this.clear();
return this;
}
const { bucketIndex, indexInBucket } = this._getBucketAndPosition(pos);
@ -517,7 +516,7 @@ export class Deque<E = any, R = any> extends IterableElementBase<E, R, Deque<E,
return this;
} else {
const newDeque = new Deque<E>([], { bucketSize: this._bucketSize });
if (pos < 0) pos = 0;
for (let i = pos; i < this.size; i++) {
newDeque.push(this.at(i));
}

View file

@ -95,7 +95,7 @@ export class Queue<E = any, R = any> extends IterableElementBase<E, R, Queue<E,
return this.size > 0 ? this.elements[this.elements.length - 1] : undefined;
}
_autoCompactRatio: number = 0.5;
protected _autoCompactRatio: number = 0.5;
/**
* This function returns the value of the autoCompactRatio property.

View file

@ -12,7 +12,6 @@ export class TreeNode<V = any> {
constructor(key: string, value?: V, children?: TreeNode<V>[]) {
this._key = key;
this._value = value || undefined;
this._children = children || [];
}
protected _key: string;

View file

@ -617,14 +617,14 @@ describe('AVLTreeMultiMap iterative methods test', () => {
treeMM.add([3, 'c'], undefined, 1);
});
test('The node obtained by get Node should match the node type', () => {
it('The node obtained by get Node should match the node type', () => {
const node3 = treeMM.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
expect(node3).toBeInstanceOf(AVLTreeNode);
});
test('forEach should iterate over all elements', () => {
it('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
treeMM.forEach((value, key) => {
mockCallback(value, key);
@ -636,7 +636,7 @@ describe('AVLTreeMultiMap iterative methods test', () => {
expect(mockCallback.mock.calls[2]).toEqual(['c', 3]);
});
test('filter should return a new tree with filtered elements', () => {
it('filter should return a new tree with filtered elements', () => {
const filteredTree = treeMM.filter((value, key) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
@ -645,7 +645,7 @@ describe('AVLTreeMultiMap iterative methods test', () => {
]);
});
test('map should return a new tree with modified elements', () => {
it('map should return a new tree with modified elements', () => {
const mappedTree = treeMM.map((value, key) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
@ -655,12 +655,12 @@ describe('AVLTreeMultiMap iterative methods test', () => {
]);
});
test('reduce should accumulate values', () => {
it('reduce should accumulate values', () => {
const sum = treeMM.reduce((acc, value, key) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
it('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of treeMM) {
entries.push(entry);
@ -674,19 +674,19 @@ describe('AVLTreeMultiMap iterative methods test', () => {
]);
});
test('should clone work well', () => {
it('should clone work well', () => {
expect(treeMM.count).toBe(21);
const cloned = treeMM.clone();
expect(cloned.root?.left?.key).toBe(1);
expect(cloned.root?.right?.value).toBe('c');
});
test('should keys', () => {
it('should keys', () => {
const keys = treeMM.keys();
expect([...keys]).toEqual([1, 2, 3]);
});
test('should values', () => {
it('should values', () => {
const values = treeMM.values();
expect([...values]).toEqual(['a', 'b', 'c']);
});

View file

@ -339,14 +339,14 @@ describe('AVLTree iterative methods test', () => {
avl.add([3, 'c']);
});
test('The node obtained by get Node should match the node type', () => {
it('The node obtained by get Node should match the node type', () => {
const node3 = avl.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
expect(node3).toBeInstanceOf(AVLTreeNode);
});
test('forEach should iterate over all elements', () => {
it('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
avl.forEach((value, key) => {
mockCallback(value, key);
@ -358,7 +358,7 @@ describe('AVLTree iterative methods test', () => {
expect(mockCallback.mock.calls[2]).toEqual(['c', 3]);
});
test('filter should return a new tree with filtered elements', () => {
it('filter should return a new tree with filtered elements', () => {
const filteredTree = avl.filter((value, key) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
@ -367,7 +367,7 @@ describe('AVLTree iterative methods test', () => {
]);
});
test('map should return a new tree with modified elements', () => {
it('map should return a new tree with modified elements', () => {
const mappedTree = avl.map((value, key) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
@ -377,12 +377,12 @@ describe('AVLTree iterative methods test', () => {
]);
});
test('reduce should accumulate values', () => {
it('reduce should accumulate values', () => {
const sum = avl.reduce((acc, value, key) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
it('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of avl) {
entries.push(entry);
@ -396,18 +396,18 @@ describe('AVLTree iterative methods test', () => {
]);
});
test('should clone work well', () => {
it('should clone work well', () => {
const cloned = avl.clone();
expect(cloned.root?.left?.key).toBe(1);
expect(cloned.root?.right?.value).toBe('c');
});
test('should keys', () => {
it('should keys', () => {
const keys = avl.keys();
expect([...keys]).toEqual([1, 2, 3]);
});
test('should values', () => {
it('should values', () => {
const values = avl.values();
expect([...values]).toEqual(['a', 'b', 'c']);
});

View file

@ -767,12 +767,12 @@ describe('BinaryTree iterative methods test', () => {
binaryTree.add([3, 'c']);
});
test('The node obtained by get Node should match the node type', () => {
it('The node obtained by get Node should match the node type', () => {
const node3 = binaryTree.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
});
test('forEach should iterate over all elements', () => {
it('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
binaryTree.forEach((value, key) => {
mockCallback(value, key);
@ -784,7 +784,7 @@ describe('BinaryTree iterative methods test', () => {
expect(mockCallback.mock.calls[2]).toEqual(['c', 3]);
});
test('filter should return a new tree with filtered elements', () => {
it('filter should return a new tree with filtered elements', () => {
const filteredTree = binaryTree.filter((value, key) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
@ -793,7 +793,7 @@ describe('BinaryTree iterative methods test', () => {
]);
});
test('map should return a new tree with modified elements', () => {
it('map should return a new tree with modified elements', () => {
const mappedTree = binaryTree.map((value, key) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
@ -803,12 +803,12 @@ describe('BinaryTree iterative methods test', () => {
]);
});
test('reduce should accumulate values', () => {
it('reduce should accumulate values', () => {
const sum = binaryTree.reduce((acc, currentValue, currentKey) => acc + currentKey, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
it('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of binaryTree) {
entries.push(entry);
@ -822,23 +822,23 @@ describe('BinaryTree iterative methods test', () => {
]);
});
test('should clone work well', () => {
it('should clone work well', () => {
const cloned = binaryTree.clone();
expect(cloned.root?.left?.key).toBe(2);
expect(cloned.root?.right?.value).toBe('c');
});
test('should keys', () => {
it('should keys', () => {
const keys = binaryTree.keys();
expect([...keys]).toEqual([2, 1, 3]);
});
test('should values', () => {
it('should values', () => {
const values = binaryTree.values();
expect([...values]).toEqual(['b', 'a', 'c']);
});
test('should iterative method return undefined when the node is null', () => {
it('should iterative method return undefined when the node is null', () => {
const tree = new BinaryTree();
tree.addMany([-10, -10, -10, 9, 9, 20, null, null, 15, 7, 8, null, 2, null, 6, null, null, 8, 8, 8]);
const bfsResult = tree.bfs(undefined, undefined, undefined, true);

View file

@ -873,13 +873,13 @@ describe('BST operations test recursively', () => {
});
describe('BST isBST', function () {
test('isBST', () => {
it('isBST', () => {
const bst = new BST<number, number>();
bst.addMany([1, 2, 3, 9, 8, 5, 6, 7, 4]);
expect(bst.isBST()).toBe(true);
});
test('isBST when variant is Max', () => {
it('isBST when variant is Max', () => {
const bst = new BST<number, number>([1, 2, 3, 9, 8, 5, 6, 7, 4], {
comparator: (a, b) => b - a
});
@ -961,13 +961,13 @@ describe('BST iterative methods test', () => {
bst.add([3, 'c']);
});
test('The node obtained by get Node should match the node type', () => {
it('The node obtained by get Node should match the node type', () => {
const node3 = bst.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
});
test('forEach should iterate over all elements', () => {
it('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
bst.forEach((value, key) => {
mockCallback(value, key);
@ -979,7 +979,7 @@ describe('BST iterative methods test', () => {
expect(mockCallback.mock.calls[2]).toEqual(['c', 3]);
});
test('filter should return a new tree with filtered elements', () => {
it('filter should return a new tree with filtered elements', () => {
const filteredTree = bst.filter((value, key) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
@ -988,7 +988,7 @@ describe('BST iterative methods test', () => {
]);
});
test('map should return a new tree with modified elements', () => {
it('map should return a new tree with modified elements', () => {
const mappedTree = bst.map((value, key) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
@ -998,12 +998,12 @@ describe('BST iterative methods test', () => {
]);
});
test('reduce should accumulate values', () => {
it('reduce should accumulate values', () => {
const sum = bst.reduce((acc, value, key) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
it('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of bst) {
entries.push(entry);
@ -1017,18 +1017,18 @@ describe('BST iterative methods test', () => {
]);
});
test('should clone work well', () => {
it('should clone work well', () => {
const cloned = bst.clone();
expect(cloned.root?.left).toBe(undefined);
expect(cloned.root?.right?.value).toBe('b');
});
test('should keys', () => {
it('should keys', () => {
const keys = bst.keys();
expect([...keys]).toEqual([1, 2, 3]);
});
test('should values', () => {
it('should values', () => {
const values = bst.values();
expect([...values]).toEqual(['a', 'b', 'c']);
});

View file

@ -619,14 +619,14 @@ describe('RedBlackTree 2', () => {
rbTree.add([3, 'c']);
});
test('The node obtained by get Node should match the node type', () => {
it('The node obtained by get Node should match the node type', () => {
const node3 = rbTree.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
expect(node3).toBeInstanceOf(RedBlackTreeNode);
});
test('forEach should iterate over all elements', () => {
it('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
rbTree.forEach((value, key) => {
mockCallback(value, key);
@ -638,7 +638,7 @@ describe('RedBlackTree 2', () => {
expect(mockCallback.mock.calls[2]).toEqual(['c', 3]);
});
test('filter should return a new rbTree with filtered elements', () => {
it('filter should return a new rbTree with filtered elements', () => {
const filteredTree = rbTree.filter((value, key) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
@ -647,7 +647,7 @@ describe('RedBlackTree 2', () => {
]);
});
test('map should return a new rbTree with modified elements', () => {
it('map should return a new rbTree with modified elements', () => {
const mappedTree = rbTree.map((value, key) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
@ -657,12 +657,12 @@ describe('RedBlackTree 2', () => {
]);
});
test('reduce should accumulate values', () => {
it('reduce should accumulate values', () => {
const sum = rbTree.reduce((acc, value, key) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
it('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of rbTree) {
entries.push(entry);

View file

@ -755,14 +755,14 @@ describe('TreeMultiMap iterative methods test', () => {
treeMM.add([3, 'c'], undefined, 1);
});
test('The node obtained by get Node should match the node type', () => {
it('The node obtained by get Node should match the node type', () => {
const node3 = treeMM.getNode(3);
expect(node3).toBeInstanceOf(BinaryTreeNode);
expect(node3).toBeInstanceOf(BSTNode);
expect(node3).toBeInstanceOf(RedBlackTreeNode);
});
test('forEach should iterate over all elements', () => {
it('forEach should iterate over all elements', () => {
const mockCallback = jest.fn();
treeMM.forEach((value, key) => {
mockCallback(value, key);
@ -774,7 +774,7 @@ describe('TreeMultiMap iterative methods test', () => {
expect(mockCallback.mock.calls[2]).toEqual(['c', 3]);
});
test('filter should return a new tree with filtered elements', () => {
it('filter should return a new tree with filtered elements', () => {
const filteredTree = treeMM.filter((value, key) => key > 1);
expect(filteredTree.size).toBe(2);
expect([...filteredTree]).toEqual([
@ -783,7 +783,7 @@ describe('TreeMultiMap iterative methods test', () => {
]);
});
test('map should return a new tree with modified elements', () => {
it('map should return a new tree with modified elements', () => {
const mappedTree = treeMM.map((value, key) => (key * 2).toString());
expect(mappedTree.size).toBe(3);
expect([...mappedTree]).toEqual([
@ -793,12 +793,12 @@ describe('TreeMultiMap iterative methods test', () => {
]);
});
test('reduce should accumulate values', () => {
it('reduce should accumulate values', () => {
const sum = treeMM.reduce((acc, value, key) => acc + key, 0);
expect(sum).toBe(6);
});
test('[Symbol.iterator] should provide an iterator', () => {
it('[Symbol.iterator] should provide an iterator', () => {
const entries = [];
for (const entry of treeMM) {
entries.push(entry);
@ -812,7 +812,7 @@ describe('TreeMultiMap iterative methods test', () => {
]);
});
test('should clone work well', () => {
it('should clone work well', () => {
expect(treeMM.count).toBe(21);
expect(treeMM.getComputedCount()).toBe(21);
const cloned = treeMM.clone();
@ -820,12 +820,12 @@ describe('TreeMultiMap iterative methods test', () => {
expect(cloned.root?.right?.value).toBe('c');
});
test('should keys', () => {
it('should keys', () => {
const keys = treeMM.keys();
expect([...keys]).toEqual([1, 2, 3]);
});
test('should values', () => {
it('should values', () => {
const values = treeMM.values();
expect([...values]).toEqual(['a', 'b', 'c']);
});

View file

@ -139,14 +139,6 @@ class MyDirectedGraph<
override createEdge(src: VertexKey, dest: VertexKey, weight?: number, value?: E): EO {
return new MyEdge(src, dest, weight ?? 1, value) as EO;
}
setInEdgeMap(value: Map<VO, EO[]>) {
this._inEdgeMap = value;
}
setOutEdgeMap(value: Map<VO, EO[]>) {
this._outEdgeMap = value;
}
}
describe('Inherit from DirectedGraph and perform operations', () => {
@ -172,8 +164,8 @@ describe('Inherit from DirectedGraph and perform operations', () => {
myGraph.addVertex(2, 'data2');
myGraph.addEdge(1, 2, 10, 'edge-data1-2');
myGraph.addEdge(new MyEdge(2, 1, 20, 'edge-data2-1'));
myGraph.setInEdgeMap(myGraph.inEdgeMap);
myGraph.setOutEdgeMap(myGraph.outEdgeMap);
myGraph.inEdgeMap = myGraph.inEdgeMap;
myGraph.outEdgeMap = myGraph.outEdgeMap;
expect(myGraph.edgeSet().length).toBe(2);
// TODO
@ -205,11 +197,14 @@ describe('Inherit from DirectedGraph and perform operations', () => {
});
it('Remove edge between vertexMap', () => {
expect(myGraph.isEmpty()).toBe(true);
myGraph.addVertex(1, 'data1');
myGraph.addVertex(2, 'data2');
myGraph.addEdge(1, 2, 10, 'edge-data1-2');
expect(myGraph.isEmpty()).toBe(false);
const removedEdge = myGraph.deleteEdgeSrcToDest(1, 2);
expect(myGraph.deleteEdgeSrcToDest(2, 10)).toBe(undefined);
const edgeAfterRemoval = myGraph.getEdge(1, 2);
expect(removedEdge).toBeInstanceOf(MyEdge);
@ -220,6 +215,25 @@ describe('Inherit from DirectedGraph and perform operations', () => {
expect(edgeAfterRemoval).toBe(undefined);
});
it('should clear', () => {
expect(myGraph.isEmpty()).toBe(true);
myGraph.addVertex(1, 'data1');
myGraph.addVertex(2, 'data2');
myGraph.addEdge(1, 2, 10, 'edge-data1-2');
expect(myGraph.isEmpty()).toBe(false);
myGraph.clear();
expect(myGraph.isEmpty()).toBe(true);
});
it('should clone', () => {
myGraph.addVertex(1, 'data1');
myGraph.addVertex(2, 'data2');
myGraph.addEdge(1, 2, 10, 'edge-data1-2');
const cloned = myGraph.clone();
expect(cloned.hasVertex(1)).toBe(true);
expect(cloned.hasEdge(1, 2)).toBe(true);
});
it('Topological sort', () => {
const sorted = myGraph.topologicalSort();
@ -656,7 +670,7 @@ describe('DirectedGraph iterative Methods', () => {
vertexMap.forEach(vertex => graph.addVertex(vertex));
});
test('[Symbol.iterator] should iterate over all vertexMap', () => {
it('[Symbol.iterator] should iterate over all vertexMap', () => {
const iteratedVertices = [];
for (const vertex of graph) {
iteratedVertices.push(vertex[0]);
@ -664,13 +678,13 @@ describe('DirectedGraph iterative Methods', () => {
expect(iteratedVertices).toEqual(vertexMap);
});
test('forEach should apply a function to each vertex', () => {
it('forEach should apply a function to each vertex', () => {
const result: VertexKey[] = [];
graph.forEach((value, key) => key && result.push(key));
expect(result).toEqual(vertexMap);
});
test('filter should return vertexMap that satisfy the condition', () => {
it('filter should return vertexMap that satisfy the condition', () => {
const filtered = graph.filter((value, vertex) => vertex === 'A' || vertex === 'B');
expect(filtered).toEqual([
['A', undefined],
@ -678,17 +692,17 @@ describe('DirectedGraph iterative Methods', () => {
]);
});
test('map should apply a function to each vertex and return a new array', () => {
it('map should apply a function to each vertex and return a new array', () => {
const mapped = graph.map((value, vertex) => vertex + '_mapped');
expect(mapped).toEqual(vertexMap.map(v => v + '_mapped'));
});
test('reduce should accumulate a value based on each vertex', () => {
it('reduce should accumulate a value based on each vertex', () => {
const concatenated = graph.reduce((acc, value, key) => acc + key, '');
expect(concatenated).toBe(vertexMap.join(''));
});
test('Removing an edge of a DirectedGraph should delete additional edges', () => {
it('Removing an edge of a DirectedGraph should delete additional edges', () => {
const dg = new DirectedGraph();
dg.addVertex('hello');
dg.addVertex('hi');
@ -705,7 +719,7 @@ describe('DirectedGraph iterative Methods', () => {
expect(dg.incomingEdgesOf('Hi')).toEqual([]);
});
test('Removing a vertex of a DirectedGraph should delete additional edges', () => {
it('Removing a vertex of a DirectedGraph should delete additional edges', () => {
const graph = new DirectedGraph();
graph.addVertex('Hello');
@ -717,7 +731,7 @@ describe('DirectedGraph iterative Methods', () => {
expect(graph.incomingEdgesOf('Hi')).toEqual([]);
});
test('Removing a vertex from a DirectedGraph should remove its edges', () => {
it('Removing a vertex from a DirectedGraph should remove its edges', () => {
const dg = new DirectedGraph();
dg.addVertex('hello');
dg.addVertex('world');
@ -740,7 +754,7 @@ describe('DirectedGraph iterative Methods', () => {
});
describe('DirectedGraph getCycles', () => {
test('should getCycles return correct result', () => {
it('should getCycles return correct result', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
@ -758,7 +772,7 @@ describe('DirectedGraph getCycles', () => {
expect(cycles[0]).toEqual(['B', 'D', 'E']);
});
test('should simple cycles graph getCycles return correct result', () => {
it('should simple cycles graph getCycles return correct result', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
@ -779,7 +793,7 @@ describe('DirectedGraph getCycles', () => {
]);
});
test('should 3 cycles graph getCycles return correct result', () => {
it('should 3 cycles graph getCycles return correct result', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
@ -812,7 +826,7 @@ describe('DirectedGraph getCycles', () => {
});
describe('DirectedGraph tarjan', () => {
test('should simple cycles graph tarjan cycles return correct result', () => {
it('should simple cycles graph tarjan cycles return correct result', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
@ -853,14 +867,14 @@ describe('DirectedGraph tarjan', () => {
return graph;
}
test('should tarjan cycles return correct result', () => {
it('should tarjan cycles return correct result', () => {
const graph = createExampleGraph1();
const cycles = graph.getCycles();
expect(cycles.length).toBe(1);
expect(cycles).toEqual([['B', 'D', 'E']]);
});
test('should tarjan SCCs return correct result', () => {
it('should tarjan SCCs return correct result', () => {
const graph = createExampleGraph1();
const sccs = graph.tarjan().SCCs;
expect(sccs.size).toBe(3);
@ -878,7 +892,7 @@ describe('DirectedGraph tarjan', () => {
return graph;
}
test('should 3 cycles graph tarjan cycles return correct result', () => {
it('should 3 cycles graph tarjan cycles return correct result', () => {
const graph = createExampleGraph2();
const cycles = graph.getCycles();
expect(cycles.length).toBe(3);
@ -889,7 +903,7 @@ describe('DirectedGraph tarjan', () => {
]);
});
test('should 3 cycles graph tarjan SCCs return correct result', () => {
it('should 3 cycles graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph2();
const sccs = graph.tarjan().SCCs;
expect(sccs.size).toBe(2);
@ -919,7 +933,7 @@ describe('DirectedGraph tarjan', () => {
return graph;
}
test('should cuttable graph tarjan cycles return correct result', () => {
it('should cuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph3();
const cycles = graph.getCycles();
expect(cycles.length).toBe(2);
@ -929,7 +943,7 @@ describe('DirectedGraph tarjan', () => {
]);
});
test('should cuttable graph tarjan SCCs return correct result', () => {
it('should cuttable graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph3();
const sccs = graph.tarjan().SCCs;
expect(sccs.size).toBe(3);
@ -951,7 +965,7 @@ describe('DirectedGraph tarjan', () => {
return graph;
}
test('should more cuttable graph tarjan cycles return correct result', () => {
it('should more cuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph4();
const cycles = graph.getCycles();
expect(cycles.length).toBe(4);
@ -963,7 +977,7 @@ describe('DirectedGraph tarjan', () => {
]);
});
test('should more cuttable graph tarjan SCCs return correct result', () => {
it('should more cuttable graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph4();
const sccs = graph.tarjan().SCCs;
expect(sccs.size).toBe(3);
@ -976,7 +990,7 @@ describe('DirectedGraph tarjan', () => {
return graph;
}
test('should uncuttable graph tarjan cycles return correct result', () => {
it('should uncuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph5();
const cycles = graph.getCycles();
expect(cycles.length).toBe(4);
@ -988,7 +1002,7 @@ describe('DirectedGraph tarjan', () => {
]);
});
test('should uncuttable graph tarjan SCCs return correct result', () => {
it('should uncuttable graph tarjan SCCs return correct result', () => {
const graph = createExampleGraph5();
const sccs = graph.tarjan().SCCs;
expect(sccs.size).toBe(3);

View file

@ -1,8 +1,9 @@
import { MapEdge, MapGraph, MapVertex } from '../../../../src';
describe('MapGraph Operation Test', () => {
it('dijkstra shortest path', () => {
const mapGraph = new MapGraph([5.500338, 100.173665]);
let mapGraph: MapGraph;
beforeEach(() => {
mapGraph = new MapGraph([5.500338, 100.173665]);
mapGraph.addVertex(new MapVertex('Surin', '', 5.466724, 100.274805));
mapGraph.addVertex(new MapVertex('Batu Feringgi Beach', '', 5.475141, 100.27667));
@ -27,6 +28,9 @@ describe('MapGraph Operation Test', () => {
mapGraph.addEdge('Trinity Auto', 'Saanen Goat Farm', 26.3);
mapGraph.addEdge('The Breeza', 'Penang Airport', 24.8);
mapGraph.addEdge('Penang Airport', 'Saanen Goat Farm', 21.2);
});
it('dijkstra shortest path', () => {
const expected1 = ['Surin', 'Lotus', 'The Breeza', 'Trinity Auto', 'Saanen Goat Farm'];
const minPathBetween = mapGraph.getMinPathBetween('Surin', 'Saanen Goat Farm');
@ -42,6 +46,24 @@ describe('MapGraph Operation Test', () => {
expect(surinToSaanenGoatFarmViaDij?.minPath.map(v => v.key)).toEqual(expected2);
expect(surinToSaanenGoatFarmViaDij?.minDist).toBe(25.2);
});
it('should clone', () => {
const cloned = mapGraph.clone();
const expected1 = ['Surin', 'Lotus', 'The Breeza', 'Trinity Auto', 'Saanen Goat Farm'];
const minPathBetween = cloned.getMinPathBetween('Surin', 'Saanen Goat Farm');
expect(minPathBetween?.map(v => v.key)).toEqual(expected1);
const surinToSaanenGoatFarmDij = cloned.dijkstra('Surin', 'Saanen Goat Farm', true, true);
expect(surinToSaanenGoatFarmDij?.minPath.map(v => v.key)).toEqual(expected1);
expect(surinToSaanenGoatFarmDij?.minDist).toBe(41.1);
cloned.addEdge('Surin', 'Batu Feringgi Beach', 1.5);
const expected2 = ['Surin', 'Batu Feringgi Beach', 'Hard Rock Hotel', 'Saanen Goat Farm'];
const minPathBetweenViaBFB = cloned.getMinPathBetween('Surin', 'Saanen Goat Farm', true);
expect(minPathBetweenViaBFB?.map(v => v.key)).toEqual(expected2);
const surinToSaanenGoatFarmViaDij = cloned.dijkstra('Surin', 'Saanen Goat Farm', true, true);
expect(surinToSaanenGoatFarmViaDij?.minPath.map(v => v.key)).toEqual(expected2);
expect(surinToSaanenGoatFarmViaDij?.minDist).toBe(25.2);
});
});
describe('MapGraph', () => {

View file

@ -174,7 +174,7 @@ describe('UndirectedGraph', () => {
expect(minWeightedPath?.minPath?.[4]?.key).toBe('Intersection_5');
});
test('Removing an edge of a UndirectedGraph should not delete additional edges', () => {
it('Removing an edge of a UndirectedGraph should not delete additional edges', () => {
const dg = new UndirectedGraph();
dg.addVertex('hello');
dg.addVertex('hi');
@ -190,7 +190,7 @@ describe('UndirectedGraph', () => {
expect(dg.getEdge('hello', 'hey')).toBeInstanceOf(UndirectedEdge);
});
test('Removing a vertex of a UndirectedGraph should delete additional edges', () => {
it('Removing a vertex of a UndirectedGraph should delete additional edges', () => {
const graph = new UndirectedGraph();
graph.addVertex('Hello');
@ -202,7 +202,7 @@ describe('UndirectedGraph', () => {
expect(graph.edgesOf('Hi')).toEqual([]);
});
test('Removing a vertex from a UndirectedGraph should remove its edges', () => {
it('Removing a vertex from a UndirectedGraph should remove its edges', () => {
const dg = new UndirectedGraph();
dg.addVertex('hello');
dg.addVertex('world');
@ -274,7 +274,7 @@ it('Should return Infinity if dest is not found', () => {
});
describe('UndirectedGraph getCycles', () => {
test('should getCycles return correct result', () => {
it('should getCycles return correct result', () => {
const graph = new UndirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
@ -296,7 +296,7 @@ describe('UndirectedGraph getCycles', () => {
]);
});
test('should simple cycles graph getCycles return correct result', () => {
it('should simple cycles graph getCycles return correct result', () => {
const graph = new UndirectedGraph();
graph.addVertex('A');
@ -318,7 +318,7 @@ describe('UndirectedGraph getCycles', () => {
]);
});
test('should 3 cycles graph getCycles return correct result', () => {
it('should 3 cycles graph getCycles return correct result', () => {
const graph = new UndirectedGraph();
graph.addVertex('A');
@ -358,7 +358,7 @@ describe('UndirectedGraph getCycles', () => {
});
describe('UndirectedGraph tarjan', () => {
test('should simple cycles graph tarjan cycles return correct result', () => {
it('should simple cycles graph tarjan cycles return correct result', () => {
const graph = new UndirectedGraph();
graph.addVertex('A');
@ -396,38 +396,38 @@ describe('UndirectedGraph tarjan', () => {
return graph;
}
test('should tarjan cut vertexes return correct result', () => {
it('should tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph1();
const cutVertices = graph.tarjan().cutVertices;
expect(cutVertices.length).toBe(0);
});
test('should tarjan bridges return correct result', () => {
it('should tarjan bridges return correct result', () => {
const graph = createExampleGraph1();
const bridges = graph.tarjan().bridges;
expect(bridges.length).toBe(0);
});
test('should 3 cycles graph tarjan cut vertexes return correct result', () => {
it('should 3 cycles graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph1();
const cutVertices = graph.tarjan().cutVertices;
expect(cutVertices.length).toBe(0);
});
test('should 3 cycles graph tarjan bridges return correct result', () => {
it('should 3 cycles graph tarjan bridges return correct result', () => {
const graph = createExampleGraph1();
const bridges = graph.tarjan().bridges;
expect(bridges.length).toBe(0);
});
test('should cuttable graph tarjan cut vertexes return correct result', () => {
it('should cuttable graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph3();
const cutVertices = graph.tarjan().cutVertices;
expect(cutVertices.length).toBe(3);
expect(cutVertices.map(cv => cv.key)).toEqual(['B', 'E', 'A']);
});
test('should cuttable graph tarjan bridges return correct result', () => {
it('should cuttable graph tarjan bridges return correct result', () => {
const graph = createExampleGraph3();
const bridges = graph.tarjan().bridges;
expect(bridges.length).toBe(2);
@ -437,14 +437,14 @@ describe('UndirectedGraph tarjan', () => {
]);
});
test('should more cuttable graph tarjan cut vertexes return correct result', () => {
it('should more cuttable graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph4();
const cutVertices = graph.tarjan().cutVertices;
expect(cutVertices.length).toBe(4);
expect(cutVertices.map(cv => cv.key)).toEqual(['H', 'B', 'E', 'A']);
});
test('should more cuttable graph tarjan bridges return correct result', () => {
it('should more cuttable graph tarjan bridges return correct result', () => {
const graph = createExampleGraph4();
const bridges = graph.tarjan().bridges;
expect(bridges.length).toBe(2);
@ -454,13 +454,13 @@ describe('UndirectedGraph tarjan', () => {
]);
});
test('should uncuttable graph tarjan cut vertexes return correct result', () => {
it('should uncuttable graph tarjan cut vertexes return correct result', () => {
const graph = createExampleGraph5();
const cutVertices = graph.tarjan().cutVertices;
expect(cutVertices.length).toBe(1);
});
test('should uncuttable graph tarjan bridges return correct result', () => {
it('should uncuttable graph tarjan bridges return correct result', () => {
const graph = createExampleGraph5();
const bridges = graph.tarjan().bridges;
expect(bridges.length).toBe(0);
@ -477,7 +477,7 @@ describe('UndirectedGraph tarjan', () => {
return graph;
}
test('should 3 cycles graph tarjan cycles return correct result', () => {
it('should 3 cycles graph tarjan cycles return correct result', () => {
const graph = createExampleGraph2();
const cycles = graph.getCycles();
expect(cycles.length).toBe(10);
@ -515,7 +515,7 @@ describe('UndirectedGraph tarjan', () => {
return graph;
}
test('should cuttable graph tarjan cycles return correct result', () => {
it('should cuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph3();
const cycles = graph.getCycles();
expect(cycles.length).toBe(2);
@ -525,7 +525,7 @@ describe('UndirectedGraph tarjan', () => {
]);
});
// test('should cuttable graph tarjan CCs return correct result', () => {
// it('should cuttable graph tarjan CCs return correct result', () => {
// const graph = createExampleGraph3();
// const ccs = graph.tarjan().CCs;
// expect(ccs.size).toBe(3);
@ -547,7 +547,7 @@ describe('UndirectedGraph tarjan', () => {
return graph;
}
test('should more cuttable graph tarjan cycles return correct result', () => {
it('should more cuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph4();
const cycles = graph.getCycles();
expect(cycles.length).toBe(5);
@ -560,7 +560,7 @@ describe('UndirectedGraph tarjan', () => {
]);
});
// test('should more cuttable graph tarjan SCCs return correct result', () => {
// it('should more cuttable graph tarjan SCCs return correct result', () => {
// const graph = createExampleGraph4();
// const ccs = graph.tarjan().CCs;
// expect(ccs.size).toBe(3);
@ -573,7 +573,7 @@ describe('UndirectedGraph tarjan', () => {
return graph;
}
test('should uncuttable graph tarjan cycles return correct result', () => {
it('should uncuttable graph tarjan cycles return correct result', () => {
const graph = createExampleGraph5();
const cycles = graph.getCycles();
expect(cycles.length).toBe(13);
@ -594,7 +594,7 @@ describe('UndirectedGraph tarjan', () => {
]);
});
// test('should uncuttable graph tarjan SCCs return correct result', () => {
// it('should uncuttable graph tarjan SCCs return correct result', () => {
// const graph = createExampleGraph5();
// const ccs = graph.tarjan().CCs;
// expect(ccs.size).toBe(3);

View file

@ -13,7 +13,7 @@ describe('HashMap', () => {
expect(hashMap.isEmpty()).toBe(true);
});
it('should put and get values', () => {
it('should set and get values', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.set('three', 3);
@ -127,10 +127,11 @@ describe('HashMap', () => {
it('should handle object keys correctly', () => {
const keyObj = { id: 1 };
hashMap.set(keyObj, 'objectValue');
expect(hashMap.has(keyObj)).toBe(true);
expect(hashMap.get(keyObj)).toBe('objectValue');
});
test('Inheritability test', () => {
it('Inheritability test', () => {
class ExtendedHashMap<K, V> extends HashMap<K, V> {
someOtherParam?: string;
@ -154,7 +155,7 @@ describe('HashMap', () => {
expect(eHM.get('one')).toBe(1);
});
test('should raw elements toEntry', () => {
it('should raw elements toEntry', () => {
const rawCollection = [
{ id: 1, name: 'item 1' },
{ id: 2, name: 'item 2' }
@ -238,17 +239,19 @@ describe('HashMap', () => {
describe('HashMap for coordinate object keys', () => {
const hashMap: HashMap<[number, number], number> = new HashMap();
const codObjs: [number, number][] = [];
test('set elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
codObjs.push(codObj);
for (let i = 0; i < 10; i++) {
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
codObjs.push(codObj);
}
it('set elements in hash map', () => {
for (let i = 0; i < codObjs.length; i++) {
const codObj = codObjs[i];
hashMap.set(codObj, i);
}
});
test('get elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
it('get elements in hash map', () => {
for (let i = 0; i < codObjs.length; i++) {
const codObj = codObjs[i];
if (codObj) {
expect(hashMap.get(codObj)).toBe(i);
@ -256,8 +259,12 @@ describe('HashMap', () => {
}
});
test('delete elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
it('should spread elements in hash map', () => {
expect([...hashMap]).toEqual(codObjs.map(codObj => [codObj, codObj[1]]));
});
it('delete elements in hash map', () => {
for (let i = 0; i < 10; i++) {
if (i === 500) expect(hashMap.size).toBe(500);
const codObj = codObjs[i];
if (codObj) hashMap.delete(codObj);
@ -285,11 +292,11 @@ describe('HashMap', () => {
]);
});
test('keys', () => {
it('keys', () => {
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
});
test('values', () => {
it('values', () => {
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
});
});
@ -304,31 +311,31 @@ describe('HashMap', () => {
hashMap.set('key3', 'value3');
});
test('every() returns true if all elements match the condition', () => {
it('every() returns true if all elements match the condition', () => {
expect(hashMap.every(value => typeof value === 'string')).toBe(true);
});
test('some() returns true if any element matches the condition', () => {
it('some() returns true if any element matches the condition', () => {
expect(hashMap.some((value, key) => key === 'key1')).toBe(true);
});
test('forEach() should execute a function for each element', () => {
it('forEach() should execute a function for each element', () => {
const mockCallback = jest.fn();
hashMap.forEach(mockCallback);
expect(mockCallback.mock.calls.length).toBe(3);
});
test('map() should transform each element', () => {
it('map() should transform each element', () => {
const newHashMap = hashMap.map(value => value.toUpperCase());
expect(newHashMap.get('key1')).toBe('VALUE1');
});
test('filter() should remove elements that do not match the condition', () => {
it('filter() should remove elements that do not match the condition', () => {
const filteredHashMap = hashMap.filter((value, key) => key !== 'key1');
expect(filteredHashMap.has('key1')).toBe(false);
});
test('reduce() should accumulate values', () => {
it('reduce() should accumulate values', () => {
const result = hashMap.reduce((acc, value) => acc + value, '');
expect(result).toBe('value1value2value3');
});
@ -347,6 +354,7 @@ describe('LinkedHashMap', () => {
});
it('should add a key-value pair', () => {
expect(hashMap.first).toBe(undefined);
hashMap.set('key1', 'value1');
expect(hashMap.get('key1')).toBe('value1');
});
@ -441,29 +449,99 @@ describe('LinkedHashMap', () => {
compareHashMaps(hashMap, stdMap);
});
test('should iterate correctly with reverse iterators', () => {
it('should iterate correctly with reverse iterators', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
const iterator = hashMap.reverseBegin();
expect(iterator.next().value).toEqual(['key2', 'value2']);
});
test('should return the last element', () => {
it('should return the last element', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
expect(hashMap.last).toEqual(['key2', 'value2']);
});
test('should return undefined for empty map', () => {
it('should return undefined for empty map', () => {
expect(hashMap.last).toBeUndefined();
});
test('should get element at specific index', () => {
it('should get element at specific index', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
expect(hashMap.at(1)).toBe('value2');
});
it('should hashFn, objHashFn, toEntryFn work well', () => {
const data: Array<{ name: number }> = [{ name: 1 }, { name: 2 }, { name: 3 }];
const hm = new LinkedHashMap(data, {
hashFn: key => String(key),
objHashFn: obj => obj,
toEntryFn: ({ name }) => [{ name }, name]
});
expect(hm.hashFn).toBeTruthy();
expect(hm.objHashFn).toBeTruthy();
expect(hm.toEntryFn).toBeTruthy();
expect([...hm]).toEqual([
[{ name: 1 }, 1],
[{ name: 2 }, 2],
[{ name: 3 }, 3]
]);
});
it('should begin, reverseBegin', () => {
const data: Array<{ name: number }> = [{ name: 1 }, { name: 2 }, { name: 3 }];
const hm = new LinkedHashMap(data, {
hashFn: key => String(key),
objHashFn: obj => obj,
toEntryFn: ({ name }) => [{ name }, name]
});
expect(hm.begin().next()).toEqual({
done: false,
value: [
{
name: 1
},
1
]
});
expect(hm.reverseBegin().next()).toEqual({
done: false,
value: [
{
name: 3
},
3
]
});
});
it('should clone', () => {
hashMap = new LinkedHashMap<string, number>();
hashMap.set('one', 1);
hashMap.set('two', 2);
for (let i = 3; i <= 100; i++) {
hashMap.set(i.toString(), i);
}
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
expect(hashMap.get('86')).toBe(86);
expect(hashMap.size).toBe(100);
hashMap.delete('two');
expect(hashMap.size).toBe(99);
const cloned = hashMap.clone();
expect(cloned.get('one')).toBe(1);
expect(cloned.get('two')).toBe(undefined);
expect(cloned.get('86')).toBe(86);
expect(cloned.size).toBe(99);
});
describe('LinkedHashMap basic', () => {
let hashMap: LinkedHashMap<string, number>;
@ -506,6 +584,9 @@ describe('LinkedHashMap', () => {
hashMap.delete('one');
expect(hashMap.get('one')).toBeUndefined();
expect(hashMap.size).toBe(1);
hashMap.deleteAt(0);
// expect(hashMap.get('two')).toBe(undefined); // TODO #99
expect(hashMap.size).toBe(0);
});
it('should clear the LinkedHashMap', () => {
@ -570,7 +651,7 @@ describe('LinkedHashMap', () => {
const hashMap: LinkedHashMap<[number, number], number> = new LinkedHashMap();
const codObjs: [number, number][] = [];
test('set elements in hash map', () => {
it('set elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
codObjs.push(codObj);
@ -578,7 +659,7 @@ describe('LinkedHashMap', () => {
}
});
test('get elements in hash map', () => {
it('get elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj = codObjs[i];
if (codObj) {
@ -587,7 +668,7 @@ describe('LinkedHashMap', () => {
}
});
test('delete elements in hash map', () => {
it('delete elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
if (i === 500) expect(hashMap.size).toBe(500);
const codObj = codObjs[i];
@ -616,15 +697,15 @@ describe('LinkedHashMap', () => {
]);
});
test('keys', () => {
it('keys', () => {
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
});
test('values', () => {
it('values', () => {
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
});
test('entries', () => {
it('entries', () => {
expect([...hm.entries()]).toEqual([
[2, 2],
[3, 3],
@ -634,21 +715,61 @@ describe('LinkedHashMap', () => {
]);
});
test('every', () => {
it('every', () => {
expect(hm.every(value => value > 4)).toBe(false);
});
test('some', () => {
it('some', () => {
expect(hm.some(value => value > 6)).toBe(false);
});
test('hasValue', () => {
it('hasValue', () => {
expect(hm.hasValue(3)).toBe(true);
expect(hm.hasValue(7)).toBe(false);
});
test('print', () => {
it('print', () => {
// hm.print();
});
});
describe('HashMap HOF', () => {
let hashMap: LinkedHashMap;
beforeEach(() => {
hashMap = new LinkedHashMap<string, string>();
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
hashMap.set('key3', 'value3');
});
it('every() returns true if all elements match the condition', () => {
expect(hashMap.every(value => typeof value === 'string')).toBe(true);
});
it('some() returns true if any element matches the condition', () => {
expect(hashMap.some((value, key) => key === 'key1')).toBe(true);
});
it('forEach() should execute a function for each element', () => {
const mockCallback = jest.fn();
hashMap.forEach(mockCallback);
expect(mockCallback.mock.calls.length).toBe(3);
});
it('map() should transform each element', () => {
const newHashMap = hashMap.map(value => value.toUpperCase());
expect(newHashMap.get('key1')).toBe('VALUE1');
});
it('filter() should remove elements that do not match the condition', () => {
const filteredHashMap = hashMap.filter((value, key) => key !== 'key1');
expect(filteredHashMap.has('key1')).toBe(false);
});
it('reduce() should accumulate values', () => {
const result = hashMap.reduce((acc, value) => acc + value, '');
expect(result).toBe('value1value2value3');
});
});
});

View file

@ -2,9 +2,15 @@ import { FibonacciHeap, Heap, MaxHeap, MinHeap } from '../../../../src';
import { logBigOMetricsWrap } from '../../../utils';
describe('Heap Operation Test', () => {
it('should initiate heap', function () {
const hp = new Heap<number>();
hp.add(1);
expect(hp.size).toBe(1);
});
it('should heap add and delete work well', function () {
const hp = new MinHeap<number>();
expect(hp.delete(1)).toBe(false);
hp.add(2);
hp.add(3);
hp.add(1);
@ -23,6 +29,7 @@ describe('Heap Operation Test', () => {
it('should numeric heap work well', function () {
const minNumHeap = new MinHeap<number>();
expect(minNumHeap.poll()).toBe(undefined);
minNumHeap.add(1);
minNumHeap.add(6);
minNumHeap.add(2);
@ -219,8 +226,47 @@ describe('Heap Operation Test', () => {
expect([...heap.sort()]).toEqual([1, 3, 4, 5, 6, 7, 8]);
});
it('should getter leaf', function () {
const hp = new Heap<number>();
expect(hp.leaf).toBe(undefined);
hp.add(1);
expect(hp.leaf).toBe(1);
});
it('should error', function () {
expect(() => {
new Heap([{ key: 1 }, { key: 2 }, { key: 3 }]);
}).toThrow(
"When comparing object types, a custom comparator must be defined in the constructor's options parameter."
);
});
});
describe('Heap HOF', () => {
let hp: Heap;
beforeEach(() => {
hp = new Heap([{ key: 1 }, { key: 2 }, { key: 3 }], { comparator: (a, b) => a.key - b.key });
});
it('should filter', () => {
const filtered = hp.filter(({ key }) => key % 2 === 1);
expect([...filtered]).toEqual([{ key: 1 }, { key: 3 }]);
});
it('should map', () => {
const mapped = hp.map(
({ key }) => [key, key],
(a, b) => a[0] - b[0]
);
expect([...mapped]).toEqual([
[1, 1],
[2, 2],
[3, 3]
]);
});
});
describe('FibonacciHeap', () => {
let heap: FibonacciHeap<number>;
@ -411,41 +457,3 @@ describe('FibonacciHeap Stress Test', () => {
);
});
});
// describe('Competitor performance compare', () => {
// const minHeap = new MinHeap<number>();
// const cHeap = new CHeap<number>();
// const cPQ = new PriorityQueue<number>(undefined, (a, b) => a - b);
// const n = 100000;
//
// it('should add performance well', () => {
// const heapCost = calcRunTime(() => {
// for (let i = 0; i < n; i++) {
// minHeap.add(i);
// }
// })
//
// console.log(`heapCost: ${heapCost}`)
// });
//
// it('should add performance well', () => {
//
// const cHeapCost = calcRunTime(() => {
// for (let i = 0; i < n; i++) {
// cHeap.push(i);
// }
// })
//
// console.log(`cHeapCost: ${cHeapCost}`)
// });
//
// it('should add performance well', () => {
//
// const cPQCost = calcRunTime(() => {
// for (let i = 0; i < n; i++) {
// cPQ.push(i);
// }
// })
// console.log(`cPQCost: ${cPQCost}`)
// });
// });

View file

@ -90,22 +90,22 @@ describe('Heap iterative methods', () => {
}
});
test('Heap is iterable', () => {
it('Heap is iterable', () => {
expect([...heap]).toEqual([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]);
});
test('forEach method calls a function for each element', () => {
it('forEach method calls a function for each element', () => {
const mockCallback = jest.fn();
heap.forEach(mockCallback);
expect(mockCallback.mock.calls.length).toBe(10);
});
test('filter method returns filtered elements', () => {
it('filter method returns filtered elements', () => {
const result = heap.filter(x => x > 50);
expect([...result]).toEqual([60, 70, 80, 90, 100]);
});
test('map method correctly maps elements', () => {
it('map method correctly maps elements', () => {
const result = heap.map(
x => x / 10,
(a: number, b: number) => a - b
@ -113,7 +113,7 @@ describe('Heap iterative methods', () => {
expect([...result]).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
});
test('reduce method correctly reduces elements', () => {
it('reduce method correctly reduces elements', () => {
const result = heap.reduce((acc, curr) => acc + curr, 0);
expect(result).toBe(550); // 10+20+...+100 = 550
});

View file

@ -20,14 +20,27 @@ describe('DoublyLinkedList Operation Test', () => {
expect(list.getNodeAt(-1)).toBe(undefined);
expect(list.getNodeAt(5)).toBe(undefined);
expect(list.addAt(5, 6)).toBe(true);
expect(list.addAt(-1, 6)).toBe(false);
expect(list.addAt(7, 6)).toBe(false);
expect(list.addAt(100, 6)).toBe(false);
});
it('should addBefore', () => {
expect(list.addBefore(1, 0)).toBe(true);
expect(list.addBefore(list.getNode(1)!, 2)).toBe(true);
expect([...list]).toEqual([0, 2, 1, 2, 3, 4, 5]);
});
it('should deleteAt', () => {
expect(list.deleteAt(1)).toBeTruthy();
expect(list.deleteAt(1)).toBe(true);
expect(list.deleteAt(-1)).toBe(false);
expect(list.deleteAt(list.size)).toBe(false);
expect(list.size).toBe(4);
expect(list.deleteAt(4)).toBe(false);
expect([...list]).toEqual([1, 3, 4, 5]);
expect(list.isEmpty()).toBe(false);
expect(list.deleteAt(3)).toBe(true);
expect([...list]).toEqual([1, 3, 4]);
});
it('should delete tail', () => {
@ -94,6 +107,13 @@ describe('DoublyLinkedList Operation Test', () => {
expect(list.tail).toBe(undefined);
});
it('should initialize with toElementFn', () => {
const dl = new DoublyLinkedList([{ key: 1 }, { key: 2 }, { key: 3 }], { toElementFn: ({ key }) => key });
expect([...dl]).toEqual([1, 2, 3]);
expect(dl.first).toBe(1);
expect(dl.last).toBe(3);
});
it('should push elements to the list', () => {
list.push(1);
list.push(2);
@ -111,8 +131,13 @@ describe('DoublyLinkedList Operation Test', () => {
expect(list.size).toBe(1);
expect(list.head!.value).toBe(1);
expect(list.tail!.value).toBe(1);
list.pop();
expect([...list]).toEqual([]);
list.pop();
expect([...list]).toEqual([]);
});
it('should insert elements at specific positions', () => {
expect(list.at(0)).toBe(undefined);
list.push(1);
list.push(2);
list.push(3);
@ -134,6 +159,8 @@ describe('DoublyLinkedList Operation Test', () => {
expect(list.size).toBe(6);
expect(list.at(5)).toBe(4);
expect(list.tail!.value).toBe(4);
expect(list.at(-1)).toBe(undefined);
expect(list.at(6)).toBe(undefined);
});
it('should delete elements at specific positions', () => {
@ -445,9 +472,11 @@ describe('iterable methods', () => {
expect(dl.reduce((accumulator, element) => accumulator + element, 0)).toEqual(6);
});
test('values', () => {
it('values', () => {
const dl = new DoublyLinkedList<number>();
dl.push(1);
dl.shift();
expect([...dl]).toEqual([]);
dl.unshift(1);
dl.push(2);
dl.push(3);
dl.delete(2);
@ -458,7 +487,7 @@ describe('iterable methods', () => {
expect([...dl.values()]).toEqual([3, 1]);
});
test('some', () => {
it('some', () => {
const dl = new DoublyLinkedList<number>();
dl.push(1);
dl.push(2);

View file

@ -9,6 +9,16 @@ describe('SinglyLinkedListNode', () => {
});
});
describe('SinglyLinkedList Initiate Test', () => {
it('should initiate with toElementFn', () => {
const sl = new SinglyLinkedList([{ key: 1 }, { key: 2 }, { key: 3 }, { key: 4 }, { key: 5 }], {
toElementFn: ({ key }) => key
});
expect([...sl]).toEqual([1, 2, 3, 4, 5]);
});
});
describe('SinglyLinkedList Operation Test', () => {
let list: SinglyLinkedList<number>;
let objectList: SinglyLinkedList<{
@ -95,6 +105,10 @@ describe('SinglyLinkedList Operation Test', () => {
list.push(3);
list.addAfter(2, 4);
expect(list.toArray()).toEqual([1, 2, 4, 3]);
list.addAfter(list.getNode(2)!, 4);
expect(list.toArray()).toEqual([1, 2, 4, 4, 3]);
list.addAfter(list.getNode(3)!, 4);
expect(list.toArray()).toEqual([1, 2, 4, 4, 3, 4]);
});
it('should return false if the existing value is not found', () => {
@ -132,12 +146,17 @@ describe('SinglyLinkedList Operation Test', () => {
list.push(3);
list.push(4);
list.push(5);
expect(list.delete(undefined)).toBe(false);
expect(list.delete(2)).toBe(true);
expect(list.toArray()).toEqual([1, 3, 4, 5]);
expect(list.delete(1)).toBe(true);
expect(list.toArray()).toEqual([3, 4, 5]);
expect(list.delete(5)).toBe(true);
expect(list.toArray()).toEqual([3, 4]);
expect(list.delete(4)).toBe(true);
expect(list.toArray()).toEqual([3]);
expect(list.delete(3)).toBe(true);
expect(list.toArray()).toEqual([]);
});
it('should return false if the value is not found', () => {
@ -229,11 +248,14 @@ describe('SinglyLinkedList Operation Test', () => {
describe('addBefore', () => {
it('should insert an element before an existing value', () => {
expect(list.addBefore(2, 4)).toBe(false);
list.push(1);
list.push(2);
list.push(3);
list.addBefore(2, 4);
expect(list.toArray()).toEqual([1, 4, 2, 3]);
expect(list.addBefore(list.getNode(2)!, 4)).toBe(true);
expect([...list]).toEqual([1, 4, 4, 2, 3]);
});
it('should insert an element at the beginning', () => {
@ -281,7 +303,11 @@ describe('SinglyLinkedList Operation Test', () => {
it('should delete and return the first element', () => {
list.push(1);
list.push(2);
expect(list.first).toBe(1);
expect(list.last).toBe(2);
const removed = list.deleteAt(0);
expect(list.first).toBe(2);
expect(list.last).toBe(2);
expect(removed).toBe(true);
expect(list.toArray()).toEqual([2]);
});
@ -321,6 +347,9 @@ describe('SinglyLinkedList Operation Test', () => {
list.addAt(1, 3);
list.addAt(1, 2);
expect(list.toArray()).toEqual([1, 2, 3]);
expect(list.addAt(5, 5)).toBe(false);
expect(list.addAt(-1, -1)).toBe(false);
expect(list.toArray()).toEqual([1, 2, 3]);
});
});
@ -354,6 +383,7 @@ describe('SinglyLinkedList Operation Test', () => {
it('should clone', function () {
const sList = new SinglyLinkedList<string>();
sList.delete('1');
sList.push('1');
sList.push('6');
sList.push('2');
@ -367,6 +397,8 @@ describe('SinglyLinkedList Operation Test', () => {
sList.delete('5');
expect([...sList]).toEqual(['1', '6', '0', '9']);
expect([...cloned]).toEqual(['1', '6', '0', '5', '9']);
sList.delete(sList.getNode('0'));
expect([...sList]).toEqual(['1', '6', '9']);
});
describe('countOccurrences', () => {

View file

@ -22,6 +22,14 @@ describe('Matrix', () => {
]);
});
it('should initiate with empty', () => {
matrix = new Matrix([], { rows: 2, cols: 2 });
expect(matrix.data).toEqual([
[0, 0],
[0, 0]
]);
});
it('should get a value at a specific position', () => {
expect(matrix.get(1, 1)).toBe(0);
expect(matrix.get(2, 2)).toBe(0);
@ -213,7 +221,7 @@ describe('Matrix', () => {
});
describe('transpose', () => {
test('should transpose a matrix with numeric values correctly', () => {
it('should transpose a matrix with numeric values correctly', () => {
const originalMatrix = new Matrix([
[1, 2, 3],
[4, 5, 6],
@ -231,7 +239,7 @@ describe('Matrix', () => {
]);
});
test('should transpose an empty matrix correctly', () => {
it('should transpose an empty matrix correctly', () => {
const originalMatrix = new Matrix([]);
const transposedMatrix = originalMatrix.transpose();
@ -241,7 +249,7 @@ describe('Matrix', () => {
expect(transposedMatrix.data).toEqual([]);
});
test('should throw an error when transposing a non-rectangular matrix', () => {
it('should throw an error when transposing a non-rectangular matrix', () => {
const originalMatrix = new Matrix([
[1, 2, 3],
[4, 5]
@ -292,10 +300,32 @@ describe('Matrix', () => {
[-0.046511627906976744, -0.023255813953488372, 0.23255813953488372]
]);
});
it('should throw error when cols does not equal to rows', () => {
const data: number[][] = [
[4, 7, 2],
[2, 6, 3]
];
const matrix = new Matrix(data);
expect(() => matrix.inverse()).toThrow('Matrix must be square for inversion.');
});
it('should clone', () => {
const data: number[][] = [
[4, 7, 2],
[2, 6, 3]
];
const matrix = new Matrix(data);
const cloned = matrix.clone();
expect(cloned instanceof Matrix).toBe(true);
expect(cloned.data).toEqual(data);
});
});
describe('dot', () => {
test('should calculate the dot product of two matrices', () => {
it('should calculate the dot product of two matrices', () => {
const matrix1 = new Matrix([
[1, 2],
[3, 4]
@ -313,7 +343,7 @@ describe('Matrix', () => {
]);
});
test('should throw an error for incompatible matrices', () => {
it('should throw an error for incompatible matrices', () => {
const matrix1 = new Matrix([
[1, 2],
[3, 4]

View file

@ -129,4 +129,35 @@ describe('MaxPriorityQueue Operation Test', () => {
expect([...maxPQ.sort()]).toEqual([8, 7, 6, 5, 4, 3, 1]);
});
it('should MaxPriorityQueue filter, map work well', function () {
const minPQ2 = new MaxPriorityQueue<number>([]);
minPQ2.refill([2, 5, 8, 1, 6, 7, 4]);
const cloned = minPQ2.clone();
const filtered = cloned.filter(item => item % 2 === 1);
expect(filtered instanceof MaxPriorityQueue).toBe(true);
expect([...filtered]).toEqual([7, 1, 5]);
const mapped = filtered.map(
item => ({ key: item }),
(a, b) => b.key - a.key
);
expect(mapped instanceof MaxPriorityQueue).toBe(true);
expect([...mapped]).toEqual([{ key: 7 }, { key: 1 }, { key: 5 }]);
});
it('should MaxPriorityQueue throw an error while initialed with object data', function () {
expect(() => {
new MaxPriorityQueue<{ key: number }>([{ key: 7 }, { key: 1 }, { key: 7 }]);
}).toThrow(
"When comparing object types, a custom comparator must be defined in the constructor's options parameter."
);
});
it('should MaxPriorityQueue comparator return 0 when equal values are added', function () {
const duplicated = new MaxPriorityQueue<number>([7, 1, 7, 7]);
expect(duplicated.size).toBe(4);
expect([...duplicated]).toEqual([7, 7, 7, 1]);
});
});

View file

@ -60,4 +60,21 @@ describe('MinPriorityQueue Operation Test', () => {
const sortedArray = priorityQueue.sort();
expect(sortedArray).toEqual([1, 3, 5, 7]);
});
it('should MinPriorityQueue filter, map work well', function () {
const minPQ2 = new MinPriorityQueue<number>([]);
minPQ2.refill([2, 5, 8, 1, 6, 7, 4]);
const cloned = minPQ2.clone();
const filtered = cloned.filter(item => item % 2 === 1);
expect(filtered instanceof MinPriorityQueue).toBe(true);
expect([...filtered]).toEqual([1, 5, 7]);
const mapped = filtered.map(
item => ({ key: item }),
(a, b) => a.key - b.key
);
expect(mapped instanceof MinPriorityQueue).toBe(true);
expect([...mapped]).toEqual([{ key: 1 }, { key: 5 }, { key: 7 }]);
});
});

View file

@ -52,6 +52,23 @@ describe('PriorityQueue Operation Test', () => {
expect(minPQ1.dfs('POST')).toEqual([4, 3, 5, 2, 8, 7, 6, 1]);
expect(minPQ1.dfs('PRE')).toEqual([1, 2, 3, 4, 5, 6, 8, 7]);
});
it('should PriorityQueue filter, map work well', function () {
const minPQ2 = new PriorityQueue<number>([], {
comparator: (a, b) => a - b
});
minPQ2.refill([2, 5, 8, 3, 1, 6, 7, 4]);
const filtered = minPQ2.filter(item => item % 2 === 1);
expect(filtered instanceof PriorityQueue).toBe(true);
expect([...filtered]).toEqual([1, 3, 5, 7]);
const mapped = filtered.map(
item => ({ key: item }),
(a, b) => a.key - b.key
);
expect(mapped instanceof PriorityQueue).toBe(true);
expect([...mapped]).toEqual([{ key: 1 }, { key: 3 }, { key: 5 }, { key: 7 }]);
});
});
describe('Priority Queue Performance Test', () => {

View file

@ -10,19 +10,19 @@ describe('Deque - Basic Operations', () => {
deque = new Deque<number>([1, 2]);
});
test('push should add elements to the end', () => {
it('push should add elements to the end', () => {
expect(deque.size).toBe(2);
expect(deque.last).toBe(2);
});
test('pop should remove elements from the end', () => {
it('pop should remove elements from the end', () => {
expect(deque.pop()).toBe(2);
expect(deque.size).toBe(1);
expect(deque.pop()).toBe(1);
expect(deque.isEmpty()).toBeTruthy();
});
test('unshift should add elements to the beginning', () => {
it('unshift should add elements to the beginning', () => {
deque.clear();
deque.unshift(1);
deque.unshift(2);
@ -30,7 +30,7 @@ describe('Deque - Basic Operations', () => {
expect(deque.first).toBe(2);
});
test('shift should remove elements from the beginning', () => {
it('shift should remove elements from the beginning', () => {
deque.clear();
deque.unshift(1);
deque.unshift(2);
@ -40,17 +40,17 @@ describe('Deque - Basic Operations', () => {
expect(deque.isEmpty()).toBeTruthy();
});
test('at should retrieve the correct element', () => {
it('at should retrieve the correct element', () => {
expect(deque.at(0)).toBe(1);
expect(deque.at(1)).toBe(2);
});
test('setAt should set the correct element', () => {
it('setAt should set the correct element', () => {
deque.setAt(0, 3);
expect(deque.at(0)).toBe(3);
});
test('should at after shifting', () => {
it('should at after shifting', () => {
deque.clear();
for (let i = 0; i < 100; i++) {
deque.push(i);
@ -65,7 +65,7 @@ describe('Deque - Basic Operations', () => {
}
});
test('should at after popping', () => {
it('should at after popping', () => {
deque.clear();
for (let i = 0; i < 100; i++) {
deque.push(i);
@ -115,14 +115,14 @@ describe('Deque - Complex Operations', () => {
deque = new Deque<number>();
});
test('addAt should insert elements at the specified position', () => {
deque.push(1);
deque.push(3);
it('addAt should insert elements at the specified position', () => {
deque.addAt(0, 1);
deque.addAt(1, 3);
deque.addAt(1, 2);
expect(deque.toArray()).toEqual([1, 2, 3]);
});
test('cut should remove elements after the specified position', () => {
it('cut should remove elements after the specified position', () => {
deque.push(1);
deque.push(2);
deque.push(3);
@ -136,9 +136,17 @@ describe('Deque - Complex Operations', () => {
expect([...dq1.cut(3, true)]).toEqual([1, 2, 3, 4]);
expect(dq1.size).toBe(4);
expect([...dq1]).toEqual([1, 2, 3, 4]);
const dqCut = dq1.cut(2);
expect(dqCut.toArray()).toEqual([1, 2, 3]);
const dqCutFromBeginning = dqCut.cut(0, true);
expect(dqCutFromBeginning.toArray()).toEqual([1]);
dqCutFromBeginning.cut(-1, true);
expect(dqCutFromBeginning.toArray()).toEqual([]);
const dqCutFromNegative = dqCutFromBeginning.cut(-1);
expect([...dqCutFromNegative]).toEqual([]);
});
test('cutRest should remove elements after the specified position', () => {
it('cutRest should remove elements after the specified position', () => {
deque.push(1);
deque.push(2);
deque.push(3);
@ -160,17 +168,28 @@ describe('Deque - Complex Operations', () => {
const dq1 = new Deque([1, 2, 3, 4, 5, 6, 7]);
expect([...dq1.cutRest(3)]).toEqual([4, 5, 6, 7]);
expect([...dq1]).toEqual([1, 2, 3, 4, 5, 6, 7]);
const dq2 = dq1.cutRest(0, true);
expect(dq2.toArray()).toEqual([1, 2, 3, 4, 5, 6, 7]);
dq2.cutRest(-1, true);
expect(dq2.toArray()).toEqual([1, 2, 3, 4, 5, 6, 7]);
const dq3 = dq2.cutRest(-1);
expect([...dq3]).toEqual([1, 2, 3, 4, 5, 6, 7]);
});
test('deleteAt should remove the element at the specified position', () => {
it('deleteAt should remove the element at the specified position', () => {
deque.push(1);
deque.push(2);
deque.push(3);
deque.deleteAt(1);
expect(deque.toArray()).toEqual([1, 3]);
deque.deleteAt(1);
deque.deleteAt(0);
expect(deque.toArray()).toEqual([]);
});
test('delete should remove all instances of an element', () => {
it('delete should remove all instances of an element', () => {
deque.delete(2);
expect(deque.toArray()).toEqual([]);
deque.push(1);
deque.push(2);
deque.push(2);
@ -179,7 +198,7 @@ describe('Deque - Complex Operations', () => {
expect(deque.toArray()).toEqual([1, 3]);
});
test('reverse should reverse the order of elements', () => {
it('reverse should reverse the order of elements', () => {
deque.push(1);
deque.push(2);
deque.push(3);
@ -187,16 +206,19 @@ describe('Deque - Complex Operations', () => {
expect(deque.toArray()).toEqual([3, 2, 1]);
});
test('unique should remove duplicate elements', () => {
it('unique should remove duplicate elements', () => {
deque.push(1);
const noNeedUnique = deque.unique();
expect(noNeedUnique).toBe(deque);
deque.push(2);
deque.push(2);
deque.push(3);
deque.unique();
const uniquer = deque.unique();
expect(uniquer).toBe(deque);
expect(deque.toArray()).toEqual([1, 2, 3]);
});
test('sort should sort elements according to a comparator', () => {
it('sort should sort elements according to a comparator', () => {
deque.push(3);
deque.push(1);
deque.push(2);
@ -204,7 +226,43 @@ describe('Deque - Complex Operations', () => {
expect([...deque]).toEqual([1, 2, 3]);
});
test('shrinkToFit should reduce the memory footprint', () => {});
it('shrinkToFit should reduce the memory footprint', () => {
deque.shrinkToFit();
expect(deque.size).toBe(0);
expect(deque.has(1)).toBe(false);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(0);
expect(deque.firstInBucket).toBe(2048);
expect(deque.lastInBucket).toBe(2048);
expect(deque.bucketCount).toBe(1);
expect(deque.buckets[0][0]).toEqual(undefined);
expect(deque.buckets.length).toEqual(1);
deque.push(1);
deque.shrinkToFit();
deque = new Deque([1, 2, 3, 4, 5], { bucketSize: 2 });
expect(deque.size).toBe(5);
expect(deque.has(1)).toBe(true);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(2);
expect(deque.firstInBucket).toBe(0);
expect(deque.lastInBucket).toBe(0);
expect(deque.bucketCount).toBe(3);
expect(deque.buckets[0][0]).toBe(1);
expect(deque.buckets[2][0]).toBe(5);
expect(deque.buckets.length).toBe(3);
deque.shrinkToFit();
expect(deque.buckets).toEqual([[1, 2], [3, 4], [5]]);
deque.push(6);
deque.push(7);
deque.shrinkToFit();
expect(deque.buckets).toEqual([
[1, 2],
[3, 4],
[5, 6],
[7, 2]
]);
});
});
describe('Deque - Utility Operations', () => {
let deque: Deque<number>;
@ -213,7 +271,8 @@ describe('Deque - Utility Operations', () => {
deque = new Deque<number>();
});
test('find should return the first element that matches the condition', () => {
it('find should return the first element that matches the condition', () => {
expect(deque.first).toBe(undefined);
deque.push(1);
deque.push(2);
deque.push(3);
@ -221,22 +280,23 @@ describe('Deque - Utility Operations', () => {
expect(found).toBe(2);
});
test('indexOf should return the index of the first occurrence of an element', () => {
it('indexOf should return the index of the first occurrence of an element', () => {
deque.push(1);
deque.push(2);
deque.push(3);
const index = deque.indexOf(2);
expect(index).toBe(1);
expect(deque.indexOf(4)).toBe(-1);
});
test('toArray should convert the deque to an array', () => {
it('toArray should convert the deque to an array', () => {
deque.push(1);
deque.push(2);
deque.push(3);
expect(deque.toArray()).toEqual([1, 2, 3]);
});
test('filter should filter elements based on a predicate', () => {
it('filter should filter elements based on a predicate', () => {
deque.push(1);
deque.push(2);
deque.push(3);
@ -244,7 +304,7 @@ describe('Deque - Utility Operations', () => {
expect(filtered.toArray()).toEqual([2, 3]);
});
test('map should apply a function to all elements', () => {
it('map should apply a function to all elements', () => {
deque.push(1);
deque.push(2);
deque.push(3);
@ -252,7 +312,7 @@ describe('Deque - Utility Operations', () => {
expect(mapped.toArray()).toEqual([2, 4, 6]);
});
test('print should print the deque elements', () => {
it('print should print the deque elements', () => {
// const consoleSpy = jest.spyOn(console, 'log');
// deque.push(1);
// deque.push(2);
@ -260,7 +320,7 @@ describe('Deque - Utility Operations', () => {
// expect(consoleSpy).toHaveBeenCalledWith([1, 2]);
});
test('should maxLen work well', () => {
it('should maxLen work well', () => {
const dequeMaxLen = new Deque([3, 4, 5, 6, 7], { maxLen: 3 });
expect(dequeMaxLen.size).toBe(3);
expect(dequeMaxLen.toArray()).toEqual([5, 6, 7]);
@ -286,42 +346,43 @@ describe('Deque - Additional Operations', () => {
deque = new Deque<number>();
});
test('push should add an element to the end', () => {
it('push should add an element to the end', () => {
deque.push(1);
deque.push(2);
expect(deque.last).toBe(2);
expect(deque.size).toBe(2);
});
test('pop should remove and return the last element', () => {
it('pop should remove and return the last element', () => {
deque.push(1);
deque.push(2);
expect(deque.pop()).toBe(2);
expect(deque.size).toBe(1);
});
test('unshift should add an element to the beginning', () => {
it('unshift should add an element to the beginning', () => {
deque.unshift(1);
deque.unshift(2);
expect(deque.first).toBe(2);
expect(deque.size).toBe(2);
});
test('shift should remove and return the first element', () => {
it('shift should remove and return the first element', () => {
deque.shift();
deque.unshift(1);
deque.unshift(2);
expect(deque.shift()).toBe(2);
expect(deque.size).toBe(1);
});
test('clear should reset the deque', () => {
it('clear should reset the deque', () => {
deque.unshift(1);
deque.clear();
expect(deque.size).toBe(0);
expect(deque.isEmpty()).toBeTruthy();
});
test('begin should yield elements from the beginning', () => {
it('begin should yield elements from the beginning', () => {
deque.push(1);
deque.push(2);
const iterator = deque.begin();
@ -329,7 +390,7 @@ describe('Deque - Additional Operations', () => {
expect(iterator.next().value).toBe(2);
});
test('reverseBegin should yield elements in reverse order', () => {
it('reverseBegin should yield elements in reverse order', () => {
deque.push(1);
deque.push(2);
const iterator = deque.reverseBegin();
@ -347,13 +408,13 @@ describe('Deque - push Method', () => {
});
});
test('push should add an element when deque is empty', () => {
it('push should add an element when deque is empty', () => {
deque.push(1);
expect(deque.last).toBe(1);
expect(deque.size).toBe(1);
});
test('push should add an element when lastInBucket is not at max', () => {
it('push should add an element when lastInBucket is not at max', () => {
for (let i = 0; i < bucketSize - 1; i++) {
deque.push(i);
}
@ -362,7 +423,7 @@ describe('Deque - push Method', () => {
expect(deque.size).toBe(bucketSize);
});
test('push should add an element and move to next bucket when last bucket is full', () => {
it('push should add an element and move to next bucket when last bucket is full', () => {
for (let i = 0; i < bucketSize; i++) {
deque.push(i);
}
@ -371,7 +432,7 @@ describe('Deque - push Method', () => {
expect(deque.size).toBe(bucketSize + 1);
});
test('push should add an element and reallocate when last bucket and lastInBucket are at max', () => {
it('push should add an element and reallocate when last bucket and lastInBucket are at max', () => {
for (let i = 0; i < 100; i++) {
deque.push(i);
}
@ -391,20 +452,20 @@ describe('Deque - pop Method', () => {
});
});
test('pop should remove and return the last element', () => {
it('pop should remove and return the last element', () => {
deque.push(1);
deque.push(2);
expect(deque.pop()).toBe(2);
expect(deque.size).toBe(1);
});
test('pop should handle popping the only element', () => {
it('pop should handle popping the only element', () => {
deque.push(1);
expect(deque.pop()).toBe(1);
expect(deque.isEmpty()).toBeTruthy();
});
test('pop should adjust bucketLast and lastInBucket correctly', () => {
it('pop should adjust bucketLast and lastInBucket correctly', () => {
for (let i = 0; i < 100; i++) {
deque.push(i);
}
@ -424,13 +485,13 @@ describe('Deque - unshift Method', () => {
});
});
test('unshift should add an element to the beginning when deque is empty', () => {
it('unshift should add an element to the beginning when deque is empty', () => {
deque.unshift(1);
expect(deque.first).toBe(1);
expect(deque.size).toBe(1);
});
test('unshift should add an element to the beginning and adjust firstInBucket', () => {
it('unshift should add an element to the beginning and adjust firstInBucket', () => {
for (let i = 0; i < 100; i++) {
deque.unshift(i);
}
@ -439,7 +500,7 @@ describe('Deque - unshift Method', () => {
expect(deque.first).toBe(0);
});
test('unshift should add an element and reallocate when needed', () => {
it('unshift should add an element and reallocate when needed', () => {
for (let i = 0; i < 100; i++) {
deque.unshift(i);
}
@ -458,20 +519,20 @@ describe('Deque - shift Method', () => {
});
});
test('shift should remove and return the first element', () => {
it('shift should remove and return the first element', () => {
deque.push(1);
deque.push(2);
expect(deque.shift()).toBe(1);
expect(deque.size).toBe(1);
});
test('shift should handle shifting the only element', () => {
it('shift should handle shifting the only element', () => {
deque.push(1);
expect(deque.shift()).toBe(1);
expect(deque.isEmpty()).toBeTruthy();
});
test('shift should adjust bucketFirst and firstInBucket correctly', () => {
it('shift should adjust bucketFirst and firstInBucket correctly', () => {
for (let i = 0; i < 100; i++) {
deque.push(i);
}
@ -481,3 +542,183 @@ describe('Deque - shift Method', () => {
}
});
});
describe('Deque', () => {
it('should initialize with default iterable with length function', () => {
class IterableNumbers {
private readonly _elements: number[] = [];
constructor(elements: number[]) {
this._elements = elements;
}
*[Symbol.iterator]() {
for (let i = 0; i < this._elements.length; ++i) {
yield this._elements[i];
}
}
length() {
return this._elements.length;
}
}
const numbers = new IterableNumbers([1, 6, 7, 3, 2, 4, 5]);
const deque = new Deque(numbers, { bucketSize: 3 });
expect(deque.size).toBe(7);
expect(deque.bucketSize).toBe(3);
expect(deque.maxLen).toBe(-1);
});
it('should initialize with default iterable with size function', () => {
class IterableNumbersWithSize {
private readonly _elements: number[] = [];
constructor(elements: number[]) {
this._elements = elements;
}
*[Symbol.iterator]() {
for (let i = 0; i < this._elements.length; ++i) {
yield this._elements[i];
}
}
size() {
return this._elements.length;
}
}
const numbers = new IterableNumbersWithSize([1, 6, 7, 3, 2, 4, 5]);
const deque = new Deque(numbers, { bucketSize: 3 });
expect(deque.size).toBe(7);
expect(deque.bucketSize).toBe(3);
expect(deque.maxLen).toBe(-1);
});
it('should initialize via toElementFn', () => {
const objArr: Array<{
key: number;
}> = [{ key: 1 }, { key: 6 }, { key: 7 }, { key: 3 }, { key: 2 }, { key: 4 }, { key: 5 }];
const deque = new Deque<number>(objArr, { toElementFn: item => item.key });
expect(deque.size).toBe(7);
expect(deque.has(1)).toBe(true);
expect(deque.has(7)).toBe(true);
expect(deque.has(8)).toBe(false);
});
it('should bucket properties are correct', () => {
const objArr: Array<{
key: number;
}> = [{ key: 1 }, { key: 6 }, { key: 7 }, { key: 3 }, { key: 2 }, { key: 4 }, { key: 5 }];
const deque = new Deque<number>(objArr, { toElementFn: item => item.key, bucketSize: 3 });
expect(deque.size).toBe(7);
expect(deque.has(1)).toBe(true);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(2);
expect(deque.firstInBucket).toBe(1);
expect(deque.lastInBucket).toBe(1); // TODO may be a problem
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[, 1, 6],
[7, 3, 2],
[4, 5]
]);
});
it('should pop work well when bucket boundary is reached', () => {
const deque = new Deque<number>([1, 6, 7, 3, 2, 4, 5], { bucketSize: 3 });
expect(deque.size).toBe(7);
expect(deque.has(1)).toBe(true);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(2);
expect(deque.firstInBucket).toBe(1);
expect(deque.lastInBucket).toBe(1); // TODO may be a problem
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[, 1, 6],
[7, 3, 2],
[4, 5]
]);
for (let i = 0; i < 3; ++i) deque.pop();
expect(deque.size).toBe(4);
expect(deque.has(1)).toBe(true);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(1);
expect(deque.firstInBucket).toBe(1);
expect(deque.lastInBucket).toBe(1);
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[, 1, 6],
[7, 3, 2],
[4, 5]
]); // TODO may be a problem
deque.pop();
expect(deque.size).toBe(3);
expect(deque.has(1)).toBe(true);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(1);
expect(deque.firstInBucket).toBe(1);
expect(deque.lastInBucket).toBe(0);
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[, 1, 6],
[7, 3, 2],
[4, 5]
]); // TODO may be a problem
});
it('should shift work well when bucket boundary is reached and should shrinkToFit', () => {
const deque = new Deque<number>([1, 6, 7, 3, 2, 4, 5], { bucketSize: 3 });
expect(deque.size).toBe(7);
expect(deque.has(1)).toBe(true);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(2);
expect(deque.firstInBucket).toBe(1);
expect(deque.lastInBucket).toBe(1); // TODO may be a problem
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[, 1, 6],
[7, 3, 2],
[4, 5]
]);
for (let i = 0; i < 3; ++i) deque.shift();
expect(deque.size).toBe(4);
expect(deque.has(1)).toBe(false);
expect(deque.bucketFirst).toBe(1);
expect(deque.bucketLast).toBe(2);
expect(deque.firstInBucket).toBe(1);
expect(deque.lastInBucket).toBe(1);
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[, 1, 6],
[7, 3, 2],
[4, 5]
]); // TODO may be a problem
deque.shift();
expect(deque.size).toBe(3);
expect(deque.has(1)).toBe(false);
expect(deque.bucketFirst).toBe(1);
expect(deque.bucketLast).toBe(2);
expect(deque.firstInBucket).toBe(2);
expect(deque.lastInBucket).toBe(1);
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[, 1, 6],
[7, 3, 2],
[4, 5]
]); // TODO may be a problem
deque.shrinkToFit();
expect(deque.size).toBe(3);
expect(deque.has(1)).toBe(false);
expect(deque.bucketFirst).toBe(0);
expect(deque.bucketLast).toBe(1);
expect(deque.firstInBucket).toBe(2);
expect(deque.lastInBucket).toBe(1);
expect(deque.bucketCount).toBe(3);
expect(deque.buckets).toEqual([
[7, 3, 2],
[4, 5]
]); // TODO may be a problem
});
});

View file

@ -10,68 +10,68 @@ describe('Queue', () => {
queue = new Queue<number>();
});
test('new Queue() should create an empty queue', () => {
it('new Queue() should create an empty queue', () => {
expect(queue.size).toBe(0);
expect(queue.isEmpty()).toBeTruthy();
});
test('push should add elements to the queue', () => {
it('push should add elements to the queue', () => {
queue.push(1);
queue.push(2);
expect(queue.size).toBe(2);
});
test('shift should remove the first element', () => {
it('shift should remove the first element', () => {
queue.push(1);
queue.push(2);
expect(queue.shift()).toBe(1);
expect(queue.size).toBe(1);
});
test('shift should return undefined if queue is empty', () => {
it('shift should return undefined if queue is empty', () => {
expect(queue.shift()).toBeUndefined();
});
test('first should return the first element without removing it', () => {
it('first should return the first element without removing it', () => {
queue.push(1);
queue.push(2);
expect(queue.first).toBe(1);
expect(queue.size).toBe(2);
});
test('first should return undefined if queue is empty', () => {
it('first should return undefined if queue is empty', () => {
expect(queue.first).toBeUndefined();
});
test('size should return the number of elements', () => {
it('size should return the number of elements', () => {
queue.push(1);
queue.push(2);
expect(queue.size).toBe(2);
});
test('isEmpty should return true if the queue is empty', () => {
it('isEmpty should return true if the queue is empty', () => {
expect(queue.isEmpty()).toBeTruthy();
});
test('isEmpty should return false if the queue is not empty', () => {
it('isEmpty should return false if the queue is not empty', () => {
queue.push(1);
expect(queue.isEmpty()).toBeFalsy();
});
test('toArray should return an array of queue elements', () => {
it('toArray should return an array of queue elements', () => {
queue.push(1);
queue.push(2);
expect(queue.toArray()).toEqual([1, 2]);
});
test('clear should remove all elements from the queue', () => {
it('clear should remove all elements from the queue', () => {
queue.push(1);
queue.push(2);
queue.clear();
expect(queue.size).toBe(0);
});
test('forEach should iterate over all elements', () => {
it('forEach should iterate over all elements', () => {
const arr: number[] = [];
queue.push(1);
queue.push(2);
@ -80,7 +80,7 @@ describe('Queue', () => {
});
// Boundary value testing
test('push and shift with many elements', () => {
it('push and shift with many elements', () => {
for (let i = 0; i < 1000; i++) {
queue.push(i);
}
@ -90,7 +90,7 @@ describe('Queue', () => {
expect(queue.isEmpty()).toBeTruthy();
});
test('compact method should work well', () => {
it('compact method should work well', () => {
for (let i = 0; i < 1000; i++) queue.push(i);
for (let i = 0; i < 499; i++) queue.shift();
@ -100,7 +100,7 @@ describe('Queue', () => {
expect(queue.elements.length).toBe(501);
});
test('should at after shifting', () => {
it('should at after shifting', () => {
for (let i = 0; i < 100; i++) {
queue.push(i);
}
@ -114,7 +114,7 @@ describe('Queue', () => {
}
});
test('should toElementFn', () => {
it('should toElementFn', () => {
const queue = new Queue<string, { id: string }>([{ id: '1' }, { id: '5' }, { id: '3' }, { id: '4' }, { id: '2' }], {
toElementFn: rawElement => rawElement.id
});
@ -177,6 +177,29 @@ describe('Queue', () => {
expect([...queue]).toEqual(['1', '6', '9']);
expect([...cloned]).toEqual(['1', '6', '0', '5', '9']);
});
it('should set autoCompactRatio', function () {
const queue = new Queue<number>();
queue.autoCompactRatio = 0.3;
queue.push(1);
queue.push(2);
queue.push(3);
queue.push(4);
queue.push(5);
queue.push(6);
queue.push(7);
queue.push(8);
queue.push(9);
queue.push(10);
expect(queue.elements.length).toBe(10);
while (queue.size > 7) queue.shift();
expect(queue.size).toBe(7);
expect(queue.elements.length).toBe(10);
queue.shift();
expect(queue.size).toBe(6);
expect(queue.elements.length).toBe(6);
});
});
describe('Queue - Advanced Methods', () => {
@ -186,7 +209,7 @@ describe('Queue - Advanced Methods', () => {
queue = new Queue<number>();
});
test('reduce should apply a function against an accumulator and each element', () => {
it('reduce should apply a function against an accumulator and each element', () => {
queue.push(1);
queue.push(2);
queue.push(3);
@ -194,13 +217,13 @@ describe('Queue - Advanced Methods', () => {
expect(sum).toBe(6);
});
test('reduce should return initial value for empty queue', () => {
it('reduce should return initial value for empty queue', () => {
const initialValue = 0;
const sum = queue.reduce((acc, val) => acc + val, initialValue);
expect(sum).toBe(initialValue);
});
test('filter should return a new queue with all elements that pass the test implemented by provided function', () => {
it('filter should return a new queue with all elements that pass the test implemented by provided function', () => {
queue.push(1);
queue.push(2);
queue.push(3);
@ -208,12 +231,12 @@ describe('Queue - Advanced Methods', () => {
expect(filteredQueue.toArray()).toEqual([2, 3]);
});
test('filter should return an empty queue for empty queue', () => {
it('filter should return an empty queue for empty queue', () => {
const filteredQueue = queue.filter(val => val > 1);
expect(filteredQueue.isEmpty()).toBeTruthy();
});
test('map should create a new queue with the results of calling a provided function on every element', () => {
it('map should create a new queue with the results of calling a provided function on every element', () => {
queue.push(1);
queue.push(2);
queue.push(3);
@ -221,7 +244,7 @@ describe('Queue - Advanced Methods', () => {
expect(mappedQueue.toArray()).toEqual([2, 4, 6]);
});
test('map should return an empty queue for empty queue', () => {
it('map should return an empty queue for empty queue', () => {
const mappedQueue = queue.map(val => val * 2);
expect(mappedQueue.isEmpty()).toBeTruthy();
});
@ -233,31 +256,31 @@ describe('Queue - Additional Methods', () => {
queue = new Queue<number>();
});
test('peekLast should return the last element without removing it', () => {
it('peekLast should return the last element without removing it', () => {
queue.push(1);
queue.push(2);
expect(queue.last).toBe(2);
expect(queue.size).toBe(2);
});
test('peekLast should return undefined if queue is empty', () => {
it('peekLast should return undefined if queue is empty', () => {
expect(queue.last).toBeUndefined();
});
test('at should return the element at the specified index', () => {
it('at should return the element at the specified index', () => {
queue.push(1);
queue.push(2);
queue.push(3);
expect(queue.at(1)).toBe(2);
});
test('at should return undefined for an invalid index', () => {
it('at should return undefined for an invalid index', () => {
queue.push(1);
expect(queue.at(3)).toBeUndefined();
expect(queue.at(-1)).toBeUndefined();
});
test('print should not throw any errors', () => {
it('print should not throw any errors', () => {
expect(() => {
queue.push(1);
// queue.print();
@ -266,19 +289,19 @@ describe('Queue - Additional Methods', () => {
});
describe('Queue - Static and Clone Methods', () => {
test('fromArray should create a new queue from an array', () => {
it('fromArray should create a new queue from an array', () => {
const array = [1, 2, 3];
const queue = Queue.fromArray(array);
expect(queue.toArray()).toEqual(array);
expect(queue.size).toBe(array.length);
});
test('fromArray should create an empty queue from an empty array', () => {
it('fromArray should create an empty queue from an empty array', () => {
const queue = Queue.fromArray([]);
expect(queue.isEmpty()).toBeTruthy();
});
test('clone should create a new queue with the same elements', () => {
it('clone should create a new queue with the same elements', () => {
const originalQueue = new Queue<number>();
originalQueue.push(1);
originalQueue.push(2);
@ -288,7 +311,7 @@ describe('Queue - Static and Clone Methods', () => {
expect(clonedQueue.size).toBe(originalQueue.size);
});
test('clone should not affect the original queue when mutated', () => {
it('clone should not affect the original queue when mutated', () => {
const originalQueue = new Queue<number>();
originalQueue.push(1);
originalQueue.push(2);
@ -306,18 +329,16 @@ describe('LinkedListQueue', () => {
beforeEach(() => {
queue = new LinkedListQueue<string>();
queue.push('A');
queue.push('B');
});
it('should push elements to the end of the queue', () => {
queue.push('A');
queue.push('B');
expect(queue.first).toBe('A');
expect(queue.size).toBe(2);
});
it('should shift elements from the front of the queue', () => {
queue.push('A');
queue.push('B');
const dequeued = queue.shift();
expect(dequeued).toBe('A');
expect(queue.first).toBe('B');
@ -325,8 +346,12 @@ describe('LinkedListQueue', () => {
});
it('should peek at the front of the queue', () => {
queue.push('A');
queue.push('B');
expect(queue.first).toBe('A');
});
it('should clone method work correctly', () => {
const cloned = queue.clone();
expect(cloned instanceof LinkedListQueue).toBe(true);
expect(cloned.size).toBe(2);
});
});

View file

@ -19,6 +19,7 @@ describe('Stack', () => {
});
it('should peek at the top element without removing it', () => {
expect(stack.peek()).toBe(undefined);
stack.push(1);
stack.push(2);
stack.push(3);
@ -93,7 +94,7 @@ describe('Stack iterative methods', () => {
stack.push(3);
});
test('should iterate through the stack', () => {
it('should iterate through the stack', () => {
const result: number[] = [];
for (const element of stack) {
result.push(element);
@ -102,7 +103,7 @@ describe('Stack iterative methods', () => {
expect(result).toEqual([1, 2, 3]); // iteration should start from the top of the stack
});
test('should apply forEach to the stack', () => {
it('should apply forEach to the stack', () => {
const result: number[] = [];
stack.forEach(element => {
result.push(element);
@ -111,23 +112,36 @@ describe('Stack iterative methods', () => {
expect(result).toEqual([1, 2, 3]);
});
test('should filter elements in the stack', () => {
it('should filter elements in the stack', () => {
const filteredStack = stack.filter(element => element > 1);
expect(filteredStack.size).toBe(2);
expect([...filteredStack]).toEqual([2, 3]);
});
test('should map elements in the stack', () => {
it('should map elements in the stack', () => {
const mappedStack = stack.map(element => element * 2);
expect(mappedStack.size).toBe(3);
expect([...mappedStack]).toEqual([2, 4, 6]);
});
test('should reduce elements in the stack', () => {
it('should reduce elements in the stack', () => {
const sum = stack.reduce((accumulator, element) => accumulator + element, 0);
expect(sum).toBe(6);
});
it('should toElementFn', () => {
const stack = new Stack([{ key: 1 }, { key: 2 }, { key: 5 }, { key: 3 }], { toElementFn: item => item.key });
expect(stack.size).toBe(4);
expect([...stack]).toEqual([1, 2, 5, 3]);
});
it('should fromArray', () => {
const stack = Stack.fromArray([1, 2, 5, 3]);
expect(stack instanceof Stack).toBe(true);
expect(stack.size).toBe(4);
expect([...stack]).toEqual([1, 2, 5, 3]);
});
});

View file

@ -0,0 +1,58 @@
import { TreeNode } from '../../../../src';
describe('TreeNode', () => {
it('should create a tree node with key and value', () => {
const node = new TreeNode<string>('root', 'RootValue');
expect(node.key).toBe('root');
expect(node.value).toBe('RootValue');
expect(node.children).toEqual(undefined);
});
it('should allow setting and getting key and value', () => {
const node = new TreeNode<string>('node1', 'Value1');
node.key = 'newKey';
node.value = 'newValue';
expect(node.key).toBe('newKey');
expect(node.value).toBe('newValue');
});
it('should add a single child node', () => {
const parent = new TreeNode<string>('parent');
const child = new TreeNode<string>('child', 'ChildValue');
parent.addChildren(child);
expect(parent.children).toHaveLength(1);
expect(parent.children?.[0].key).toBe('child');
expect(parent.children?.[0].value).toBe('ChildValue');
});
it('should add multiple children nodes', () => {
const parent = new TreeNode<string>('parent');
const child1 = new TreeNode<string>('child1');
const child2 = new TreeNode<string>('child2');
parent.addChildren([child1, child2]);
expect(parent.children).toHaveLength(2);
expect(parent.children?.[0].key).toBe('child1');
expect(parent.children?.[1].key).toBe('child2');
parent.children = [];
expect(parent.children[0]).toBe(undefined);
expect(parent.children[1]).toBe(undefined);
});
it('should calculate the correct height of the tree', () => {
const root = new TreeNode<string>('root');
const child1 = new TreeNode<string>('child1');
const child2 = new TreeNode<string>('child2');
const grandChild = new TreeNode<string>('grandChild');
root.addChildren(child1);
root.addChildren(child2);
child1.addChildren(grandChild);
expect(root.getHeight()).toBe(2); // root -> child1 -> grandChild (height = 2)
});
});

View file

@ -22,6 +22,31 @@ describe('TrieNode', () => {
node.isEnd = true;
expect(node.isEnd).toBe(true);
});
it('should set key property correctly', () => {
const node = new TrieNode('a');
node.isEnd = false;
expect(node).toEqual({
_children: new Map(),
_isEnd: false,
_key: 'a'
});
node.key = 'b';
expect(node.key).toBe('b');
expect(node).toEqual({
_children: new Map(),
_isEnd: false,
_key: 'b'
});
});
it('should set children property correctly', () => {
const node = new TrieNode('a');
node.isEnd = false;
const children = new Map<string, TrieNode>([['p', new TrieNode('p')]]);
node.children = children;
expect(node.children).toEqual(children);
});
});
describe('Trie', () => {
@ -865,29 +890,45 @@ describe('Trie class', () => {
trie = new Trie(['apple', 'app', 'banana', 'band', 'bandana']);
});
test('[Symbol.iterator] should iterate over all words', () => {
it('[Symbol.iterator] should iterate over all words', () => {
const words = [...trie];
expect(words).toEqual(['app', 'apple', 'banana', 'band', 'bandana']);
});
test('forEach should execute a callback for each word', () => {
it('forEach should execute a callback for each word', () => {
const mockCallback = jest.fn();
trie.forEach(mockCallback);
expect(mockCallback).toHaveBeenCalledTimes(5);
});
test('filter should return words that satisfy the predicate', () => {
it('filter should return words that satisfy the predicate', () => {
const filteredWords = trie.filter(word => word.startsWith('ba'));
expect([...filteredWords]).toEqual(['banana', 'band', 'bandana']);
});
test('map should apply a function to each word', () => {
it('map should apply a function to each word', () => {
const mappedWords = trie.map(word => word.length.toString());
expect([...mappedWords]).toEqual(['3', '5', '6', '4', '7']);
});
test('reduce should reduce the words to a single value', () => {
it('reduce should reduce the words to a single value', () => {
const concatenatedWords = trie.reduce((acc, word) => acc + word, '');
expect(concatenatedWords).toEqual('appapplebananabandbandana');
});
it('reduce should new Trie with toElementFn be correct', () => {
const trieB = new Trie([{ name: 'apple' }, { name: 'app' }, { name: 'arm' }], { toElementFn: item => item.name });
expect(trieB.isEmpty()).toBe(false);
expect(trieB.size).toBe(3);
expect(trieB.has('apple')).toBe(true);
expect(trieB.has('app')).toBe(true);
expect(trieB.has('arm')).toBe(true);
expect(trieB.hasPrefix('ap')).toBe(true);
trieB.clear();
expect(trieB.size).toBe(0);
expect(trieB.has('apple')).toBe(false);
expect(trieB.has('app')).toBe(false);
expect(trieB.has('arm')).toBe(false);
expect(trieB.hasPrefix('ap')).toBe(false);
});
});