From 610e12f5d59bb4700649b44b981480b8044f8b35 Mon Sep 17 00:00:00 2001 From: Peter Hovanec Date: Tue, 5 Nov 2024 13:41:38 +0100 Subject: [PATCH] added misc functions and test them --- src/ordinalTree/OrdinalNode.js | 33 +++++++--- src/ordinalTree/OrdinalTree.js | 60 ++++++++++++----- test/ordinal.spec.js | 115 +++++++++++++++++++++++++++++---- 3 files changed, 171 insertions(+), 37 deletions(-) diff --git a/src/ordinalTree/OrdinalNode.js b/src/ordinalTree/OrdinalNode.js index 023d221..72d38f7 100644 --- a/src/ordinalTree/OrdinalNode.js +++ b/src/ordinalTree/OrdinalNode.js @@ -1,28 +1,43 @@ - - class OrdinalNode { constructor(value) { - this.value = value; - this.children = []; - this.parent = null; + this.value = value; + this.children = []; + this.parent = null; } addChild(childNode) { - childNode.parent = this; - this.children.push( childNode); + childNode.parent = this; + this.children.push(childNode); } removeChild(childNode) { const index = this.children.indexOf(childNode); if (index > -1) { this.children.splice(index, 1); - childNode.parent = null; + childNode.parent = null; } } getChildAt(index) { - return this.children[index]; + return this.children[index]; + } + + getChildrenCount() { + return this.children.length; + } + + findChild(value) { + return this.children.find((child) => child.value === value) || null; } + + getSiblings() { + if (this.parent) { + return this.parent.children.filter((child) => child !== this); + } + return []; + } + + } export default OrdinalNode; diff --git a/src/ordinalTree/OrdinalTree.js b/src/ordinalTree/OrdinalTree.js index a875ff9..805582f 100644 --- a/src/ordinalTree/OrdinalTree.js +++ b/src/ordinalTree/OrdinalTree.js @@ -1,53 +1,83 @@ - - import OrdinalNode from "./OrdinalNode"; class OrdinalTree { constructor() { - this.root = null; + this.root = null; } - add(value, parentValue = null) { const newNode = new OrdinalNode(value); if (this.root === null) { - this.root = newNode; + this.root = newNode; } else { const parent = this.findNode(this.root, parentValue); if (parent) { - parent.addChild(newNode); + parent.addChild(newNode); } else { console.error("Parent not found"); } } } - findNode(currentNode, value) { if (currentNode.value === value) { - return currentNode; + return currentNode; } for (const child of currentNode.children) { const foundNode = this.findNode(child, value); if (foundNode) { - return foundNode; + return foundNode; } } - return null; + return null; } - traverse(callback) { const traverseNode = (node) => { - callback(node); - node.children.forEach(traverseNode); + callback(node); + node.children.forEach(traverseNode); }; if (this.root) { - traverseNode(this.root); + traverseNode(this.root); } } - + + remove(value) { + const nodeToRemove = this.findNode(this.root, value); + if (nodeToRemove && nodeToRemove.parent) { + nodeToRemove.parent.removeChild(nodeToRemove); + } else if (nodeToRemove === this.root) { + this.root = null; // If the root is being removed + } + } + + getHeight() { + const heightOfNode = (node) => { + if (!node) return -1; + const heights = node.children.map(heightOfNode); + return 1 + Math.max(-1, ...heights); + }; + return heightOfNode(this.root); + } + + getAllValues() { + const values = []; + this.traverse((node) => values.push(node.value)); + return values; + } + + findNodeWithCallback(callback) { + const findNode = (node) => { + if (callback(node)) return node; + for (const child of node.children) { + const foundNode = findNode(child); + if (foundNode) return foundNode; + } + return null; + }; + return findNode(this.root); + } } export default OrdinalTree; diff --git a/test/ordinal.spec.js b/test/ordinal.spec.js index f52e983..5f1e737 100644 --- a/test/ordinal.spec.js +++ b/test/ordinal.spec.js @@ -1,12 +1,10 @@ - - import { OrdinalTree, OrdinalNode } from "../src/ordinalTree/index"; describe("OrdinalTree", () => { let tree; beforeEach(() => { - tree = new OrdinalTree(); + tree = new OrdinalTree(); }); it("should create a tree with a root node", () => { @@ -19,21 +17,19 @@ describe("OrdinalTree", () => { tree.add("Root"); tree.add("Child 1", "Root"); tree.add("Child 2", "Root"); - + expect(tree.root.children.length).toBe(2); - expect(tree.root.children[0].value).toBe("Child 1"); - expect(tree.root.children[1].value).toBe("Child 2"); + expect(tree.root.children[0].value).toBe("Child 1"); + expect(tree.root.children[1].value).toBe("Child 2"); }); - - it("should retrieve a child at a specific index", () => { tree.add("Root"); tree.add("Child 1", "Root"); tree.add("Child 2", "Root"); - const childAtIndex = tree.root.getChildAt(1); - expect(childAtIndex.value).toBe("Child 2"); + const childAtIndex = tree.root.getChildAt(1); + expect(childAtIndex.value).toBe("Child 2"); }); it("should add grandchildren to a child node", () => { @@ -69,7 +65,7 @@ describe("OrdinalTree", () => { tree.traverse((node) => values.push(node.value)); - expect(values).toEqual(["Root", "Child 1", "Child 2"]); + expect(values).toEqual(["Root", "Child 1", "Child 2"]); }); it("should remove a child node", () => { @@ -82,14 +78,65 @@ describe("OrdinalTree", () => { tree.root.removeChild(child1); expect(tree.root.children.length).toBe(1); - expect(tree.root.children[0].value).toBe("Child 2"); + expect(tree.root.children[0].value).toBe("Child 2"); + }); + + // Tests for new functions + + it("should remove a node from the tree", () => { + tree.add("Root"); + tree.add("Child 1", "Root"); + tree.add("Child 2", "Root"); + + expect(tree.root.children.length).toBe(2); + tree.remove("Child 1"); + expect(tree.root.children.length).toBe(1); + expect(tree.root.children[0].value).toBe("Child 2"); + }); + + it("should set root to null if the root is removed", () => { + tree.add("Root"); + expect(tree.root.value).toBe("Root"); + tree.remove("Root"); + expect(tree.root).toBeNull(); + }); + + it("should get the height of the tree", () => { + tree.add("Root"); + tree.add("Child 1", "Root"); + tree.add("Child 2", "Root"); + tree.add("Grandchild 1", "Child 1"); + + expect(tree.getHeight()).toBe(2); // Height should be 2 + }); + + it("should get all values in the tree", () => { + tree.add("Root"); + tree.add("Child 1", "Root"); + tree.add("Child 2", "Root"); + + const allValues = tree.getAllValues(); + expect(allValues).toEqual(["Root", "Child 1", "Child 2"]); + }); + + it("should find a node with a callback", () => { + tree.add("Root"); + tree.add("Child 1", "Root"); + tree.add("Child 2", "Root"); + + const foundNode = tree.findNodeWithCallback( + (node) => node.value === "Child 1" + ); + expect(foundNode).toBeTruthy(); + expect(foundNode.value).toBe("Child 1"); }); }); + describe("OrdinalNode", () => { let node; beforeEach(() => { - node = new OrdinalNode("Test Node"); + node = new OrdinalNode("Test Node"); }); it("should initialize a node with the correct value", () => { @@ -116,4 +163,46 @@ describe("OrdinalNode", () => { expect(node.children.length).toBe(0); expect(childNode.parent).toBeNull(); }); + + it("should get the number of children", () => { + const childNode1 = new OrdinalNode("Child 1"); + const childNode2 = new OrdinalNode("Child 2"); + node.addChild(childNode1); + node.addChild(childNode2); + + expect(node.getChildrenCount()).toBe(2); + }); + + it("should find a child by value", () => { + const childNode = new OrdinalNode("Child Node"); + node.addChild(childNode); + + const foundChild = node.findChild("Child Node"); + expect(foundChild).toBe(childNode); + }); + + it("should return null when child is not found", () => { + const childNode = new OrdinalNode("Child Node"); + node.addChild(childNode); + + const foundChild = node.findChild("Non-existing Child"); + expect(foundChild).toBeNull(); + }); + + it("should get siblings", () => { + const siblingNode1 = new OrdinalNode("Sibling 1"); + const siblingNode2 = new OrdinalNode("Sibling 2"); + const childNode = new OrdinalNode("Child"); + + node.addChild(siblingNode1); + node.addChild(childNode); + node.addChild(siblingNode2); + + const siblings = childNode.getSiblings(); + expect(siblings.length).toBe(2); + expect(siblings).toContain(siblingNode1); + expect(siblings).toContain(siblingNode2); + }); + + });