Skip to content

Commit a046261

Browse files
committed
WIP: add node.test.ts
1 parent b12a61f commit a046261

File tree

3 files changed

+256
-1
lines changed

3 files changed

+256
-1
lines changed

tests/database/database.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
} from "./helpers";
77
import "../../src/database";
88

9-
describe.only('Database Tests', function() {
9+
describe('Database Tests', function() {
1010
var defaultApp;
1111

1212
beforeEach(function() {

tests/database/event.test.ts

Whitespace-only changes.

tests/database/node.test.ts

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
import { expect } from "chai";
2+
import { PRIORITY_INDEX } from "../../src/database/core/snap/indexes/PriorityIndex";
3+
import { LeafNode } from "../../src/database/core/snap/LeafNode";
4+
import { IndexMap } from "../../src/database/core/snap/IndexMap";
5+
import { Path } from "../../src/database/core/util/Path";
6+
import { SortedMap } from "../../src/database/core/util/SortedMap";
7+
import { ChildrenNode } from "../../src/database/core/snap/ChildrenNode";
8+
import { NAME_COMPARATOR } from "../../src/database/core/snap/comparators";
9+
import { nodeFromJSON } from "../../src/database/core/snap/nodeFromJSON";
10+
11+
describe.only('Node Tests', function() {
12+
var DEFAULT_INDEX = PRIORITY_INDEX;
13+
14+
it('Create leaf nodes of various types.', function() {
15+
var x = new LeafNode(5, new LeafNode(42));
16+
expect(x.getValue()).to.equal(5);
17+
expect(x.getPriority().val()).to.equal(42);
18+
expect(x.isLeafNode()).to.equal(true);
19+
20+
x = new LeafNode('test');
21+
expect(x.getValue()).to.equal('test');
22+
x = new LeafNode(true);
23+
expect(x.getValue()).to.equal(true);
24+
});
25+
26+
it("LeafNode.updatePriority returns a new leaf node without changing the old.", function() {
27+
var x = new LeafNode("test", new LeafNode(42));
28+
var y = x.updatePriority(new LeafNode(187));
29+
30+
// old node is the same.
31+
expect(x.getValue()).to.equal("test");
32+
expect(x.getPriority().val()).to.equal(42);
33+
34+
// new node has the new priority but the old value.
35+
expect(y.getValue()).to.equal("test");
36+
expect(y.getPriority().val()).to.equal(187);
37+
});
38+
39+
it("LeafNode.updateImmediateChild returns a new children node.", function() {
40+
var x = new LeafNode("test", new LeafNode(42));
41+
var y = x.updateImmediateChild('test', new LeafNode("foo"));
42+
43+
expect(y.isLeafNode()).to.equal(false);
44+
expect(y.getPriority().val()).to.equal(42);
45+
expect(y.getImmediateChild('test').getValue()).to.equal('foo');
46+
});
47+
48+
it("LeafNode.getImmediateChild returns an empty node.", function() {
49+
var x = new LeafNode("test");
50+
expect(x.getImmediateChild('foo')).to.equal(ChildrenNode.EMPTY_NODE);
51+
});
52+
53+
it("LeafNode.getChild returns an empty node.", function() {
54+
var x = new LeafNode('test');
55+
expect(x.getChild(new Path('foo/bar'))).to.equal(ChildrenNode.EMPTY_NODE);
56+
});
57+
58+
it('ChildrenNode.updatePriority returns a new internal node without changing the old.', function() {
59+
var x = ChildrenNode.EMPTY_NODE.updateImmediateChild("child", new LeafNode(5));
60+
var children = x.children_;
61+
var y = x.updatePriority(new LeafNode(17));
62+
expect(y.children_).to.equal(x.children_);
63+
expect(x.children_).to.equal(children);
64+
expect(x.getPriority().val()).to.equal(null);
65+
expect(y.getPriority().val()).to.equal(17);
66+
});
67+
68+
it('ChildrenNode.updateImmediateChild returns a new internal node with the new child, without changing the old.',
69+
function() {
70+
var children = new SortedMap(NAME_COMPARATOR);
71+
var x = new ChildrenNode(children, ChildrenNode.EMPTY_NODE, IndexMap.Default);
72+
var newValue = new LeafNode('new value');
73+
var y = x.updateImmediateChild('test', newValue);
74+
expect(x.children_).to.equal(children);
75+
expect(y.children_.get('test')).to.equal(newValue);
76+
});
77+
78+
it("ChildrenNode.updateChild returns a new internal node with the new child, without changing the old.", function() {
79+
var children = new SortedMap(NAME_COMPARATOR);
80+
var x = new ChildrenNode(children, ChildrenNode.EMPTY_NODE, IndexMap.Default);
81+
var newValue = new LeafNode("new value");
82+
var y = x.updateChild(new Path('test/foo'), newValue);
83+
expect(x.children_).to.equal(children);
84+
expect(y.getChild(new Path('test/foo'))).to.equal(newValue);
85+
});
86+
87+
it("Node.hash() works correctly.", function() {
88+
var node = nodeFromJSON({
89+
intNode:4,
90+
doubleNode:4.5623,
91+
stringNode:"hey guys",
92+
boolNode:true
93+
});
94+
95+
// !!!NOTE!!! These hashes must match what the server generates. If you change anything so these hashes change,
96+
// make sure you change the corresponding server code.
97+
expect(node.getImmediateChild("intNode").hash()).to.equal("eVih19a6ZDz3NL32uVBtg9KSgQY=");
98+
expect(node.getImmediateChild("doubleNode").hash()).to.equal("vf1CL0tIRwXXunHcG/irRECk3lY=");
99+
expect(node.getImmediateChild("stringNode").hash()).to.equal("CUNLXWpCVoJE6z7z1vE57lGaKAU=");
100+
expect(node.getImmediateChild("boolNode").hash()).to.equal("E5z61QM0lN/U2WsOnusszCTkR8M=");
101+
102+
expect(node.hash()).to.equal("6Mc4jFmNdrLVIlJJjz2/MakTK9I=");
103+
});
104+
105+
it("Node.hash() works correctly with priorities.", function() {
106+
var node = nodeFromJSON({
107+
root: {c: {'.value': 99, '.priority': 'abc'}, '.priority': 'def'}
108+
});
109+
110+
expect(node.hash()).to.equal("Fm6tzN4CVEu5WxFDZUdTtqbTVaA=");
111+
});
112+
113+
it("Node.hash() works correctly with number priorities.", function() {
114+
var node = nodeFromJSON({
115+
root: {c: {'.value': 99, '.priority': 42}, '.priority': 3.14}
116+
});
117+
118+
expect(node.hash()).to.equal("B15QCqrzCxrI5zz1y00arWqFRFg=");
119+
});
120+
121+
it("Node.hash() stress...", function() {
122+
var node = nodeFromJSON({
123+
a:-1.7976931348623157e+308,
124+
b:1.7976931348623157e+308,
125+
c:"unicode ✔ 🐵 🌴 x͢",
126+
d:3.14159265358979323846264338327950,
127+
e: {
128+
'.value': 12345678901234568,
129+
'.priority': "🐵"
130+
},
131+
"✔": "foo",
132+
'.priority':"✔"
133+
});
134+
expect(node.getImmediateChild('a').hash()).to.equal('7HxgOBDEC92uQwhCuuvKA2rbXDA=');
135+
expect(node.getImmediateChild('b').hash()).to.equal('8R+ekVQmxs6ZWP0fdzFHxVeGnWo=');
136+
expect(node.getImmediateChild('c').hash()).to.equal('JoKoFUnbmg3/DlY70KaDWslfYPk=');
137+
expect(node.getImmediateChild('d').hash()).to.equal('Y41iC5+92GIqXfabOm33EanRI8s=');
138+
expect(node.getImmediateChild('e').hash()).to.equal('+E+Mxlqh5MhT+On05bjsZ6JaaxI=');
139+
expect(node.getImmediateChild('✔').hash()).to.equal('MRRL/+aA/uibaL//jghUpxXS/uY=');
140+
expect(node.hash()).to.equal('CyC0OU8GSkOAKnsPjheWtWC0Yxo=');
141+
});
142+
143+
it("ChildrenNode.getPredecessorChild works correctly.", function() {
144+
var node = nodeFromJSON({
145+
d: true, a: true, g: true, c: true, e: true
146+
});
147+
148+
// HACK: Pass null instead of the actual childNode, since it's not actually needed.
149+
expect(node.getPredecessorChildName('a', null, DEFAULT_INDEX)).to.equal(null);
150+
expect(node.getPredecessorChildName('c', null, DEFAULT_INDEX)).to.equal('a');
151+
expect(node.getPredecessorChildName('d', null, DEFAULT_INDEX)).to.equal('c');
152+
expect(node.getPredecessorChildName('e', null, DEFAULT_INDEX)).to.equal('d');
153+
expect(node.getPredecessorChildName('g', null, DEFAULT_INDEX)).to.equal('e');
154+
});
155+
156+
it("SortedChildrenNode.getPredecessorChild works correctly.", function() {
157+
var node = nodeFromJSON({
158+
d: { '.value': true, '.priority' : 22 },
159+
a: { '.value': true, '.priority' : 25 },
160+
g: { '.value': true, '.priority' : 19 },
161+
c: { '.value': true, '.priority' : 23 },
162+
e: { '.value': true, '.priority' : 21 }
163+
});
164+
165+
expect(node.getPredecessorChildName('a', node.getImmediateChild('a'), DEFAULT_INDEX)).to.equal('c');
166+
expect(node.getPredecessorChildName('c', node.getImmediateChild('c'), DEFAULT_INDEX)).to.equal('d');
167+
expect(node.getPredecessorChildName('d', node.getImmediateChild('d'), DEFAULT_INDEX)).to.equal('e');
168+
expect(node.getPredecessorChildName('e', node.getImmediateChild('e'), DEFAULT_INDEX)).to.equal('g');
169+
expect(node.getPredecessorChildName('g', node.getImmediateChild('g'), DEFAULT_INDEX)).to.equal(null);
170+
});
171+
172+
it("SortedChildrenNode.updateImmediateChild works correctly.", function() {
173+
var node = nodeFromJSON({
174+
d: { '.value': true, '.priority' : 22 },
175+
a: { '.value': true, '.priority' : 25 },
176+
g: { '.value': true, '.priority' : 19 },
177+
c: { '.value': true, '.priority' : 23 },
178+
e: { '.value': true, '.priority' : 21 },
179+
'.priority' : 1000
180+
});
181+
182+
node = node.updateImmediateChild('c', nodeFromJSON(false));
183+
expect(node.getImmediateChild('c').getValue()).to.equal(false);
184+
expect(node.getImmediateChild('c').getPriority().val()).to.equal(null);
185+
expect(node.getPriority().val()).to.equal(1000);
186+
});
187+
188+
it("removing nodes correctly removes intermediate nodes with no remaining children", function() {
189+
var json = {a: {b: {c: 1}}};
190+
var node = nodeFromJSON(json);
191+
var newNode = node.updateChild(new Path('a/b/c'), ChildrenNode.EMPTY_NODE);
192+
expect(newNode.isEmpty()).to.equal(true);
193+
});
194+
195+
it("removing nodes leaves intermediate nodes with other children", function() {
196+
var json = {a: {b: {c: 1}, d: 2}};
197+
var node = nodeFromJSON(json);
198+
var newNode = node.updateChild(new Path('a/b/c'), ChildrenNode.EMPTY_NODE);
199+
expect(newNode.isEmpty()).to.equal(false);
200+
expect(newNode.getChild(new Path('a/b/c')).isEmpty()).to.equal(true);
201+
expect(newNode.getChild(new Path('a/d')).val()).to.equal(2);
202+
});
203+
204+
it("removing nodes leaves other leaf nodes", function() {
205+
var json = {a: {b: {c: 1, d: 2}}};
206+
var node = nodeFromJSON(json);
207+
var newNode = node.updateChild(new Path('a/b/c'), ChildrenNode.EMPTY_NODE);
208+
expect(newNode.isEmpty()).to.equal(false);
209+
expect(newNode.getChild(new Path('a/b/c')).isEmpty()).to.equal(true);
210+
expect(newNode.getChild(new Path('a/b/d')).val()).to.equal(2);
211+
});
212+
213+
it("removing nodes correctly removes the root", function() {
214+
var json = null;
215+
var node = nodeFromJSON(json);
216+
var newNode = node.updateChild(new Path(''), ChildrenNode.EMPTY_NODE);
217+
expect(newNode.isEmpty()).to.equal(true);
218+
219+
json = {a: 1};
220+
node = nodeFromJSON(json);
221+
newNode = node.updateChild(new Path('a'), ChildrenNode.EMPTY_NODE);
222+
expect(newNode.isEmpty()).to.equal(true);
223+
});
224+
225+
it("ignores null values", function() {
226+
var json = {a: 1, b: null};
227+
var node = nodeFromJSON(json);
228+
expect(node.children_.get('b')).to.equal(null);
229+
});
230+
231+
it("Leading zeroes in path are handled properly", function() {
232+
var json = {"1": 1, "01": 2, "001": 3};
233+
var tree = nodeFromJSON(json);
234+
expect(tree.getChild(new Path("1")).val()).to.equal(1);
235+
expect(tree.getChild(new Path("01")).val()).to.equal(2);
236+
expect(tree.getChild(new Path("001")).val()).to.equal(3);
237+
});
238+
239+
it("Treats leading zeroes as objects, not array", function() {
240+
var json = {"3": 1, "03": 2};
241+
var tree = nodeFromJSON(json);
242+
var val = tree.val();
243+
expect(val).to.deep.equal(json);
244+
});
245+
246+
it("Updating empty children doesn't overwrite leaf node", function() {
247+
var empty = ChildrenNode.EMPTY_NODE;
248+
var node = nodeFromJSON("value");
249+
expect(node).to.deep.equal(node.updateChild(new Path(".priority"), empty));
250+
expect(node).to.deep.equal(node.updateChild(new Path("child"), empty));
251+
expect(node).to.deep.equal(node.updateChild(new Path("child/.priority"), empty));
252+
expect(node).to.deep.equal(node.updateImmediateChild("child", empty));
253+
expect(node).to.deep.equal(node.updateImmediateChild(".priority", empty));
254+
});
255+
});

0 commit comments

Comments
 (0)