1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import * as Tree from './tree';
6 import { initTreeNode } from './tree';
7 import { pipe } from 'lodash/fp';
9 describe('Tree', () => {
10 let tree: Tree.Tree<string>;
13 tree = Tree.createTree();
16 it('sets new node', () => {
17 const newTree = Tree.setNode(initTreeNode({ id: 'Node 1', value: 'Value 1' }))(tree);
18 expect(Tree.getNode('Node 1')(newTree)).toEqual(initTreeNode({ id: 'Node 1', value: 'Value 1' }));
21 it('appends a subtree', () => {
22 const newTree = Tree.setNode(initTreeNode({ id: 'Node 1', value: 'Value 1' }))(tree);
23 const subtree = Tree.setNode(initTreeNode({ id: 'Node 2', value: 'Value 2' }))(Tree.createTree());
24 const mergedTree = Tree.appendSubtree('Node 1', subtree)(newTree);
25 expect(Tree.getNode('Node 1')(mergedTree)).toBeDefined();
26 expect(Tree.getNode('Node 2')(mergedTree)).toBeDefined();
29 it('adds new node reference to parent children', () => {
31 Tree.setNode(initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' })),
32 Tree.setNode(initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 'Value 2' })),
35 expect(Tree.getNode('Node 1')(newTree)).toEqual({
36 ...initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' }),
41 it('gets node ancestors', () => {
43 initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' }),
44 initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 'Value 1' }),
45 initTreeNode({ id: 'Node 3', parent: 'Node 2', value: 'Value 1' }),
46 ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
47 expect(Tree.getNodeAncestorsIds('Node 3')(newTree)).toEqual(['Node 1', 'Node 2']);
50 it('gets node descendants', () => {
52 initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' }),
53 initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 'Value 1' }),
54 initTreeNode({ id: 'Node 2.1', parent: 'Node 2', value: 'Value 1' }),
55 initTreeNode({ id: 'Node 3', parent: 'Node 1', value: 'Value 1' }),
56 initTreeNode({ id: 'Node 3.1', parent: 'Node 3', value: 'Value 1' }),
57 ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
58 expect(Tree.getNodeDescendantsIds('Node 1')(newTree)).toEqual(['Node 2', 'Node 3', 'Node 2.1', 'Node 3.1']);
61 it('gets root descendants', () => {
63 initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' }),
64 initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 'Value 1' }),
65 initTreeNode({ id: 'Node 2.1', parent: 'Node 2', value: 'Value 1' }),
66 initTreeNode({ id: 'Node 3', parent: 'Node 1', value: 'Value 1' }),
67 initTreeNode({ id: 'Node 3.1', parent: 'Node 3', value: 'Value 1' }),
68 ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
69 expect(Tree.getNodeDescendantsIds('')(newTree)).toEqual(['Node 1', 'Node 2', 'Node 3', 'Node 2.1', 'Node 3.1']);
72 it('gets node children', () => {
74 initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' }),
75 initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 'Value 1' }),
76 initTreeNode({ id: 'Node 2.1', parent: 'Node 2', value: 'Value 1' }),
77 initTreeNode({ id: 'Node 3', parent: 'Node 1', value: 'Value 1' }),
78 initTreeNode({ id: 'Node 3.1', parent: 'Node 3', value: 'Value 1' }),
79 ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
80 expect(Tree.getNodeChildrenIds('Node 1')(newTree)).toEqual(['Node 2', 'Node 3']);
83 it('gets root children', () => {
85 initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' }),
86 initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 'Value 1' }),
87 initTreeNode({ id: 'Node 2.1', parent: 'Node 2', value: 'Value 1' }),
88 initTreeNode({ id: 'Node 3', parent: '', value: 'Value 1' }),
89 initTreeNode({ id: 'Node 3.1', parent: 'Node 3', value: 'Value 1' }),
90 ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
91 expect(Tree.getNodeChildrenIds('')(newTree)).toEqual(['Node 1', 'Node 3']);
94 it('maps tree', () => {
96 initTreeNode({ id: 'Node 1', parent: '', value: 'Value 1' }),
97 initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 'Value 2' }),
98 ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
99 const mappedTree = Tree.mapTreeValues<string, number>(value => parseInt(value.split(' ')[1], 10))(newTree);
100 expect(Tree.getNode('Node 2')(mappedTree)).toEqual(initTreeNode({ id: 'Node 2', parent: 'Node 1', value: 2 }));
103 it('expands node ancestor chains', () => {
105 initTreeNode({ id: 'Root Node 1', parent: '', value: 'Value 1' }),
106 initTreeNode({ id: 'Node 1.1', parent: 'Root Node 1', value: 'Value 1' }),
107 initTreeNode({ id: 'Node 1.1.1', parent: 'Node 1.1', value: 'Value 1' }),
108 initTreeNode({ id: 'Node 1.2', parent: 'Root Node 1', value: 'Value 1' }),
110 initTreeNode({ id: 'Root Node 2', parent: '', value: 'Value 1' }),
111 initTreeNode({ id: 'Node 2.1', parent: 'Root Node 2', value: 'Value 1' }),
112 initTreeNode({ id: 'Node 2.1.1', parent: 'Node 2.1', value: 'Value 1' }),
114 initTreeNode({ id: 'Root Node 3', parent: '', value: 'Value 1' }),
115 initTreeNode({ id: 'Node 3.1', parent: 'Root Node 3', value: 'Value 1' }),
116 ].reduce((tree, node) => Tree.setNode(node)(tree), tree);
118 const expandedTree = Tree.expandNodeAncestors(
119 'Node 1.1.1', // Expands 1.1 and 1
120 'Node 2.1', // Expands 2
123 expect(Tree.getNode('Root Node 1')(expandedTree)?.expanded).toEqual(true);
124 expect(Tree.getNode('Node 1.1')(expandedTree)?.expanded).toEqual(true);
125 expect(Tree.getNode('Node 1.1.1')(expandedTree)?.expanded).toEqual(false);
126 expect(Tree.getNode('Node 1.2')(expandedTree)?.expanded).toEqual(false);
127 expect(Tree.getNode('Root Node 2')(expandedTree)?.expanded).toEqual(true);
128 expect(Tree.getNode('Node 2.1')(expandedTree)?.expanded).toEqual(false);
129 expect(Tree.getNode('Node 2.1.1')(expandedTree)?.expanded).toEqual(false);
130 expect(Tree.getNode('Root Node 3')(expandedTree)?.expanded).toEqual(false);
131 expect(Tree.getNode('Node 3.1')(expandedTree)?.expanded).toEqual(false);