Validating Red-Black Tree Operations in javascript-algorithms
This comprehensive test suite validates the implementation of a Red-Black Tree data structure, focusing on node coloring, tree balancing, and various rotation operations. The tests ensure proper maintenance of Red-Black Tree properties through insertions and structural modifications.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
trekhleb/javascript-algorithms
src/data-structures/tree/red-black-tree/__test__/RedBlackTree.test.js
import RedBlackTree from '../RedBlackTree';
describe('RedBlackTree', () => {
it('should always color first inserted node as black', () => {
const tree = new RedBlackTree();
const firstInsertedNode = tree.insert(10);
expect(tree.isNodeColored(firstInsertedNode)).toBe(true);
expect(tree.isNodeBlack(firstInsertedNode)).toBe(true);
expect(tree.isNodeRed(firstInsertedNode)).toBe(false);
expect(tree.toString()).toBe('10');
expect(tree.root.height).toBe(0);
});
it('should always color new leaf node as red', () => {
const tree = new RedBlackTree();
const firstInsertedNode = tree.insert(10);
const secondInsertedNode = tree.insert(15);
const thirdInsertedNode = tree.insert(5);
expect(tree.isNodeBlack(firstInsertedNode)).toBe(true);
expect(tree.isNodeRed(secondInsertedNode)).toBe(true);
expect(tree.isNodeRed(thirdInsertedNode)).toBe(true);
expect(tree.toString()).toBe('5,10,15');
expect(tree.root.height).toBe(1);
});
it('should balance itself', () => {
const tree = new RedBlackTree();
tree.insert(5);
tree.insert(10);
tree.insert(15);
tree.insert(20);
tree.insert(25);
tree.insert(30);
expect(tree.toString()).toBe('5,10,15,20,25,30');
expect(tree.root.height).toBe(3);
});
it('should balance itself when parent is black', () => {
const tree = new RedBlackTree();
const node1 = tree.insert(10);
expect(tree.isNodeBlack(node1)).toBe(true);
const node2 = tree.insert(-10);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeRed(node2)).toBe(true);
const node3 = tree.insert(20);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeRed(node2)).toBe(true);
expect(tree.isNodeRed(node3)).toBe(true);
const node4 = tree.insert(-20);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
const node5 = tree.insert(25);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
const node6 = tree.insert(6);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
expect(tree.isNodeRed(node6)).toBe(true);
expect(tree.toString()).toBe('-20,-10,6,10,20,25');
expect(tree.root.height).toBe(2);
const node7 = tree.insert(4);
expect(tree.root.left.value).toEqual(node2.value);
expect(tree.toString()).toBe('-20,-10,4,6,10,20,25');
expect(tree.root.height).toBe(3);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeRed(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeBlack(node4)).toBe(true);
expect(tree.isNodeBlack(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
expect(tree.isNodeBlack(node6)).toBe(true);
expect(tree.isNodeRed(node7)).toBe(true);
});
it('should balance itself when uncle is red', () => {
const tree = new RedBlackTree();
const node1 = tree.insert(10);
const node2 = tree.insert(-10);
const node3 = tree.insert(20);
const node4 = tree.insert(-20);
const node5 = tree.insert(6);
const node6 = tree.insert(15);
const node7 = tree.insert(25);
const node8 = tree.insert(2);
const node9 = tree.insert(8);
expect(tree.toString()).toBe('-20,-10,2,6,8,10,15,20,25');
expect(tree.root.height).toBe(3);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeRed(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeBlack(node4)).toBe(true);
expect(tree.isNodeBlack(node5)).toBe(true);
expect(tree.isNodeRed(node6)).toBe(true);
expect(tree.isNodeRed(node7)).toBe(true);
expect(tree.isNodeRed(node8)).toBe(true);
expect(tree.isNodeRed(node9)).toBe(true);
const node10 = tree.insert(4);
expect(tree.toString()).toBe('-20,-10,2,4,6,8,10,15,20,25');
expect(tree.root.height).toBe(3);
expect(tree.root.value).toBe(node5.value);
expect(tree.isNodeBlack(node5)).toBe(true);
expect(tree.isNodeRed(node1)).toBe(true);
expect(tree.isNodeRed(node2)).toBe(true);
expect(tree.isNodeRed(node10)).toBe(true);
expect(tree.isNodeRed(node6)).toBe(true);
expect(tree.isNodeRed(node7)).toBe(true);
expect(tree.isNodeBlack(node4)).toBe(true);
expect(tree.isNodeBlack(node8)).toBe(true);
expect(tree.isNodeBlack(node9)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
});
it('should do left-left rotation', () => {
const tree = new RedBlackTree();
const node1 = tree.insert(10);
const node2 = tree.insert(-10);
const node3 = tree.insert(20);
const node4 = tree.insert(7);
const node5 = tree.insert(15);
expect(tree.toString()).toBe('-10,7,10,15,20');
expect(tree.root.height).toBe(2);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
const node6 = tree.insert(13);
expect(tree.toString()).toBe('-10,7,10,13,15,20');
expect(tree.root.height).toBe(2);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node5)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node6)).toBe(true);
expect(tree.isNodeRed(node3)).toBe(true);
});
it('should do left-right rotation', () => {
const tree = new RedBlackTree();
const node1 = tree.insert(10);
const node2 = tree.insert(-10);
const node3 = tree.insert(20);
const node4 = tree.insert(7);
const node5 = tree.insert(15);
expect(tree.toString()).toBe('-10,7,10,15,20');
expect(tree.root.height).toBe(2);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
const node6 = tree.insert(17);
expect(tree.toString()).toBe('-10,7,10,15,17,20');
expect(tree.root.height).toBe(2);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node6)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
expect(tree.isNodeRed(node3)).toBe(true);
});
it('should do recoloring, left-left and left-right rotation', () => {
const tree = new RedBlackTree();
const node1 = tree.insert(10);
const node2 = tree.insert(-10);
const node3 = tree.insert(20);
const node4 = tree.insert(-20);
const node5 = tree.insert(6);
const node6 = tree.insert(15);
const node7 = tree.insert(30);
const node8 = tree.insert(1);
const node9 = tree.insert(9);
expect(tree.toString()).toBe('-20,-10,1,6,9,10,15,20,30');
expect(tree.root.height).toBe(3);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeRed(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeBlack(node4)).toBe(true);
expect(tree.isNodeBlack(node5)).toBe(true);
expect(tree.isNodeRed(node6)).toBe(true);
expect(tree.isNodeRed(node7)).toBe(true);
expect(tree.isNodeRed(node8)).toBe(true);
expect(tree.isNodeRed(node9)).toBe(true);
tree.insert(4);
expect(tree.toString()).toBe('-20,-10,1,4,6,9,10,15,20,30');
expect(tree.root.height).toBe(3);
});
it('should do right-left rotation', () => {
const tree = new RedBlackTree();
const node1 = tree.insert(10);
const node2 = tree.insert(-10);
const node3 = tree.insert(20);
const node4 = tree.insert(-20);
const node5 = tree.insert(6);
const node6 = tree.insert(30);
expect(tree.toString()).toBe('-20,-10,6,10,20,30');
expect(tree.root.height).toBe(2);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node3)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
expect(tree.isNodeRed(node6)).toBe(true);
const node7 = tree.insert(25);
const rightNode = tree.root.right;
const rightLeftNode = rightNode.left;
const rightRightNode = rightNode.right;
expect(rightNode.value).toBe(node7.value);
expect(rightLeftNode.value).toBe(node3.value);
expect(rightRightNode.value).toBe(node6.value);
expect(tree.toString()).toBe('-20,-10,6,10,20,25,30');
expect(tree.root.height).toBe(2);
expect(tree.isNodeBlack(node1)).toBe(true);
expect(tree.isNodeBlack(node2)).toBe(true);
expect(tree.isNodeBlack(node7)).toBe(true);
expect(tree.isNodeRed(node4)).toBe(true);
expect(tree.isNodeRed(node5)).toBe(true);
expect(tree.isNodeRed(node3)).toBe(true);
expect(tree.isNodeRed(node6)).toBe(true);
});
it('should do left-left rotation with left grand-parent', () => {
const tree = new RedBlackTree();
tree.insert(20);
tree.insert(15);
tree.insert(25);
tree.insert(10);
tree.insert(5);
expect(tree.toString()).toBe('5,10,15,20,25');
expect(tree.root.height).toBe(2);
});
it('should do right-right rotation with left grand-parent', () => {
const tree = new RedBlackTree();
tree.insert(20);
tree.insert(15);
tree.insert(25);
tree.insert(17);
tree.insert(19);
expect(tree.toString()).toBe('15,17,19,20,25');
expect(tree.root.height).toBe(2);
});
it('should throw an error when trying to remove node', () => {
const removeNodeFromRedBlackTree = () => {
const tree = new RedBlackTree();
tree.remove(1);
};
expect(removeNodeFromRedBlackTree).toThrowError();
});
});