treenode_test.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. // Copyright 2010 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.structs.TreeNodeTest');
  15. goog.setTestOnly('goog.structs.TreeNodeTest');
  16. goog.require('goog.structs.TreeNode');
  17. goog.require('goog.testing.jsunit');
  18. function testConstructor() {
  19. var node = new goog.structs.TreeNode('key', 'value');
  20. assertEquals('key', 'key', node.getKey());
  21. assertEquals('value', 'value', node.getValue());
  22. assertNull('parent', node.getParent());
  23. assertArrayEquals('children', [], node.getChildren());
  24. assertTrue('leaf', node.isLeaf());
  25. }
  26. function testClone() {
  27. var node1 = new goog.structs.TreeNode(1, '1');
  28. var node2 = new goog.structs.TreeNode(2, '2');
  29. var node3 = new goog.structs.TreeNode(3, '3');
  30. node1.addChild(node2);
  31. node2.addChild(node3);
  32. var clone = node2.clone();
  33. assertEquals('key', 2, clone.getKey());
  34. assertEquals('value', '2', clone.getValue());
  35. assertNull('parent', clone.getParent());
  36. assertArrayEquals('children', [], clone.getChildren());
  37. }
  38. function testDeepClone() {
  39. var node1 = new goog.structs.TreeNode(1, '1');
  40. var node2 = new goog.structs.TreeNode(2, '2');
  41. var node3 = new goog.structs.TreeNode(3, '3');
  42. node1.addChild(node2);
  43. node2.addChild(node3);
  44. var clone = node2.deepClone();
  45. assertEquals('key', 2, clone.getKey());
  46. assertEquals('value', '2', clone.getValue());
  47. assertNull('parent', clone.getParent());
  48. assertEquals('number of children', 1, clone.getChildren().length);
  49. assertEquals('first child key', 3, clone.getChildAt(0).getKey());
  50. assertNotEquals('first child has been cloned', node3, clone.getChildAt(0));
  51. }
  52. function testGetParent() {
  53. var node1 = new goog.structs.TreeNode(1, null);
  54. var node2 = new goog.structs.TreeNode(2, null);
  55. node1.addChild(node2);
  56. assertEquals('parent', node1, node2.getParent());
  57. assertNull('orphan', node1.getParent());
  58. }
  59. function testIsLeaf() {
  60. var node1 = new goog.structs.TreeNode(1, null);
  61. var node2 = new goog.structs.TreeNode(2, null);
  62. node1.addChild(node2);
  63. assertFalse('not leaf', node1.isLeaf());
  64. assertTrue('leaf', node2.isLeaf());
  65. }
  66. function testIsLastChild() {
  67. var node1 = new goog.structs.TreeNode(1, '1');
  68. var node2 = new goog.structs.TreeNode(2, '2');
  69. var node3 = new goog.structs.TreeNode(3, '3');
  70. node1.addChild(node2);
  71. node1.addChild(node3);
  72. assertFalse('root', node1.isLastChild());
  73. assertFalse('first child out of the two', node2.isLastChild());
  74. assertTrue('second child out of the two', node3.isLastChild());
  75. }
  76. function testGetChildren() {
  77. var node1 = new goog.structs.TreeNode(1, null);
  78. var node2 = new goog.structs.TreeNode(2, null);
  79. node1.addChild(node2);
  80. assertArrayEquals('1 child', [node2], node1.getChildren());
  81. assertArrayEquals('no children', [], node2.getChildren());
  82. }
  83. function testGetChildAt() {
  84. var node1 = new goog.structs.TreeNode(1, null);
  85. var node2 = new goog.structs.TreeNode(2, null);
  86. node1.addChild(node2);
  87. assertNull('index too low', node1.getChildAt(-1));
  88. assertEquals('first child', node2, node1.getChildAt(0));
  89. assertNull('index too high', node1.getChildAt(1));
  90. assertNull('no children', node2.getChildAt(0));
  91. }
  92. function testGetChildCount() {
  93. var node1 = new goog.structs.TreeNode(1, null);
  94. var node2 = new goog.structs.TreeNode(2, null);
  95. node1.addChild(node2);
  96. assertEquals('child count of root node', 1, node1.getChildCount());
  97. assertEquals('child count of leaf node', 0, node2.getChildCount());
  98. }
  99. function testGetDepth() {
  100. var node1 = new goog.structs.TreeNode(1, null);
  101. var node2 = new goog.structs.TreeNode(2, null);
  102. var node3 = new goog.structs.TreeNode(3, null);
  103. node1.addChild(node2);
  104. node2.addChild(node3);
  105. assertEquals('no parent', 0, node1.getDepth());
  106. assertEquals('1 ancestor', 1, node2.getDepth());
  107. assertEquals('2 ancestors', 2, node3.getDepth());
  108. }
  109. function testGetAncestors() {
  110. var node1 = new goog.structs.TreeNode(1, null);
  111. var node2 = new goog.structs.TreeNode(2, null);
  112. var node3 = new goog.structs.TreeNode(3, null);
  113. node1.addChild(node2);
  114. node2.addChild(node3);
  115. assertArrayEquals('no ancestors', [], node1.getAncestors());
  116. assertArrayEquals('2 ancestors', [node2, node1], node3.getAncestors());
  117. }
  118. function testGetRoot() {
  119. var node1 = new goog.structs.TreeNode(1, null);
  120. var node2 = new goog.structs.TreeNode(2, null);
  121. node1.addChild(node2);
  122. assertEquals('no ancestors', node1, node1.getRoot());
  123. assertEquals('has ancestors', node1, node2.getRoot());
  124. }
  125. function testGetSubtreeKeys() {
  126. var root = new goog.structs.TreeNode('root', null);
  127. var child1 = new goog.structs.TreeNode('child1', null);
  128. var child2 = new goog.structs.TreeNode('child2', null);
  129. var grandchild = new goog.structs.TreeNode('grandchild', null);
  130. root.addChild(child1);
  131. root.addChild(child2);
  132. child1.addChild(grandchild);
  133. assertArrayEquals(
  134. 'node hierarchy', ['child1', ['grandchild'], 'child2'],
  135. root.getSubtreeKeys());
  136. }
  137. function testContains() {
  138. var node1 = new goog.structs.TreeNode(1, null);
  139. var node2 = new goog.structs.TreeNode(2, null);
  140. var node3 = new goog.structs.TreeNode(3, null);
  141. var node4 = new goog.structs.TreeNode(4, null);
  142. node1.addChild(node2);
  143. node2.addChild(node3);
  144. node2.addChild(node4);
  145. assertTrue('parent', node1.contains(node2));
  146. assertTrue('grandparent', node1.contains(node3));
  147. assertFalse('child', node2.contains(node1));
  148. assertFalse('grandchild', node3.contains(node1));
  149. assertFalse('sibling', node3.contains(node4));
  150. }
  151. function testFindCommonAncestor() {
  152. var findCommonAncestor = goog.structs.TreeNode.findCommonAncestor;
  153. var node1 = new goog.structs.TreeNode(1, null);
  154. var node2 = new goog.structs.TreeNode(2, null);
  155. var node3 = new goog.structs.TreeNode(3, null);
  156. var node4 = new goog.structs.TreeNode(4, null);
  157. var node5 = new goog.structs.TreeNode(5, null);
  158. node1.addChild(node2);
  159. node2.addChild(node3);
  160. node1.addChild(node4);
  161. assertNull('0 nodes', findCommonAncestor());
  162. assertEquals('1 node', node2, findCommonAncestor(node2));
  163. assertEquals('same nodes', node3, findCommonAncestor(node3, node3));
  164. assertEquals('node and child node', node2, findCommonAncestor(node2, node3));
  165. assertEquals('node and parent node', node1, findCommonAncestor(node2, node1));
  166. assertEquals('siblings', node1, findCommonAncestor(node2, node4));
  167. assertEquals(
  168. 'all nodes', node1, findCommonAncestor(node2, node3, node4, node1));
  169. assertNull('disconnected nodes', findCommonAncestor(node3, node5));
  170. }
  171. function testGetNodeByKey() {
  172. var node1 = new goog.structs.TreeNode(1, null);
  173. var node2 = new goog.structs.TreeNode(2, null);
  174. var node3 = new goog.structs.TreeNode(3, null);
  175. var node4 = new goog.structs.TreeNode(4, null);
  176. var node5 = new goog.structs.TreeNode(2, null);
  177. var node6 = new goog.structs.TreeNode(3, null);
  178. node1.addChild(node2);
  179. node2.addChild(node3);
  180. node1.addChild(node4);
  181. node4.addChild(node5);
  182. node1.addChild(node6);
  183. assertEquals('root', node1, node1.getNodeByKey(1));
  184. assertEquals('child with unique key', node5, node4.getNodeByKey(2));
  185. assertEquals('child with duplicate keys', node2, node1.getNodeByKey(2));
  186. assertEquals('grandchild with duplicate keys', node3, node1.getNodeByKey(3));
  187. assertNull('disconnected', node2.getNodeByKey(4));
  188. assertNull('missing', node1.getNodeByKey(5));
  189. }
  190. function testForEachChild() {
  191. var node1 = new goog.structs.TreeNode(1, null);
  192. var node2 = new goog.structs.TreeNode(2, null);
  193. var node3 = new goog.structs.TreeNode(3, null);
  194. node1.addChild(node2);
  195. node1.addChild(node3);
  196. var thisContext = {};
  197. var visitedNodes = [];
  198. var indices = [];
  199. node1.forEachChild(function(node, index, children) {
  200. assertEquals('value of this', thisContext, this);
  201. visitedNodes.push(node);
  202. indices.push(index);
  203. assertArrayEquals('children argument', [node2, node3], children);
  204. }, thisContext);
  205. assertArrayEquals('visited nodes', [node2, node3], visitedNodes);
  206. assertArrayEquals('index of visited nodes', [0, 1], indices);
  207. }
  208. function testForEachDescendant() {
  209. var node1 = new goog.structs.TreeNode(1, null);
  210. var node2 = new goog.structs.TreeNode(2, null);
  211. var node3 = new goog.structs.TreeNode(3, null);
  212. var node4 = new goog.structs.TreeNode(4, null);
  213. node1.addChild(node2);
  214. node2.addChild(node3);
  215. node2.addChild(node4);
  216. var thisContext = {};
  217. var visitedNodes = [];
  218. node1.forEachDescendant(function(node) {
  219. assertEquals('value of this', thisContext, this);
  220. visitedNodes.push(node);
  221. }, thisContext);
  222. assertArrayEquals('visited nodes', [node2, node3, node4], visitedNodes);
  223. }
  224. function testTraverse() {
  225. var node1 = new goog.structs.TreeNode(1, null);
  226. var node2 = new goog.structs.TreeNode(2, null);
  227. var node3 = new goog.structs.TreeNode(3, null);
  228. var node4 = new goog.structs.TreeNode(4, null);
  229. node1.addChild(node2);
  230. node2.addChild(node3);
  231. node2.addChild(node4);
  232. var thisContext = {};
  233. var visitedNodes = [];
  234. node1.traverse(function(node) {
  235. assertEquals('value of this', thisContext, this);
  236. visitedNodes.push(node);
  237. }, thisContext);
  238. assertArrayEquals(
  239. 'callback returns nothing => all nodes are visited',
  240. [node1, node2, node3, node4], visitedNodes);
  241. visitedNodes = [];
  242. node1.traverse(function(node) {
  243. visitedNodes.push(node);
  244. return node != node2; // Cut off at node2.
  245. });
  246. assertArrayEquals(
  247. 'children of node2 are skipped', [node1, node2], visitedNodes);
  248. }
  249. function testAddChild() {
  250. var node1 = new goog.structs.TreeNode(1, null);
  251. var node2 = new goog.structs.TreeNode(2, null);
  252. var node3 = new goog.structs.TreeNode(3, null);
  253. assertArrayEquals('0 children', [], node1.getChildren());
  254. node1.addChild(node2);
  255. assertArrayEquals('1 child', [node2], node1.getChildren());
  256. assertEquals('parent is set', node1, node2.getParent());
  257. node1.addChild(node3);
  258. assertArrayEquals('2 children', [node2, node3], node1.getChildren());
  259. }
  260. function testAddChildAt() {
  261. var node1 = new goog.structs.TreeNode(1, null);
  262. var node2 = new goog.structs.TreeNode(2, null);
  263. var node3 = new goog.structs.TreeNode(3, null);
  264. var node4 = new goog.structs.TreeNode(4, null);
  265. var node5 = new goog.structs.TreeNode(5, null);
  266. node1.addChildAt(node2, 0);
  267. assertArrayEquals('add first child', [node2], node1.getChildren());
  268. assertEquals('parent is set', node1, node2.getParent());
  269. node1.addChildAt(node3, 0);
  270. assertArrayEquals('add to the front', [node3, node2], node1.getChildren());
  271. node1.addChildAt(node4, 1);
  272. assertArrayEquals(
  273. 'add to the middle', [node3, node4, node2], node1.getChildren());
  274. node1.addChildAt(node5, 3);
  275. assertArrayEquals(
  276. 'add to the end', [node3, node4, node2, node5], node1.getChildren());
  277. }
  278. function testReplaceChildAt() {
  279. var root = new goog.structs.TreeNode(0, null);
  280. var node1 = new goog.structs.TreeNode(1, null);
  281. root.addChild(node1);
  282. var node2 = new goog.structs.TreeNode(2, null);
  283. assertEquals('original node', node1, root.replaceChildAt(node2, 0));
  284. assertEquals('parent is set', root, node2.getParent());
  285. assertArrayEquals('children are updated', [node2], root.getChildren());
  286. assertNull('old child node is detached', node1.getParent());
  287. }
  288. function testReplaceChild() {
  289. var root = new goog.structs.TreeNode(0, null);
  290. var node1 = new goog.structs.TreeNode(1, null);
  291. root.addChild(node1);
  292. var node2 = new goog.structs.TreeNode(2, null);
  293. assertEquals('original node', node1, root.replaceChild(node2, node1));
  294. assertEquals('parent is set', root, node2.getParent());
  295. assertArrayEquals('children are updated', [node2], root.getChildren());
  296. assertNull('old child node is detached', node1.getParent());
  297. }
  298. function testRemoveChildAt() {
  299. var node1 = new goog.structs.TreeNode(1, null);
  300. var node2 = new goog.structs.TreeNode(2, null);
  301. var node3 = new goog.structs.TreeNode(3, null);
  302. node1.addChild(node2);
  303. node1.addChild(node3);
  304. assertNull('index too low', node1.removeChildAt(-1));
  305. assertNull('index too high', node1.removeChildAt(2));
  306. assertArrayEquals('node1 is intact', [node2, node3], node1.getChildren());
  307. assertEquals('remove first child', node2, node1.removeChildAt(0));
  308. assertArrayEquals('remove from the front', [node3], node1.getChildren());
  309. assertNull('parent is unset', node2.getParent());
  310. assertEquals('remove last child', node3, node1.removeChildAt(0));
  311. assertArrayEquals('remove last child', [], node1.getChildren());
  312. assertTrue('node1 became leaf', node1.isLeaf());
  313. }
  314. function testRemoveChild() {
  315. var node1 = new goog.structs.TreeNode(1, null);
  316. var node2 = new goog.structs.TreeNode(2, null);
  317. var node3 = new goog.structs.TreeNode(3, null);
  318. node1.addChild(node2);
  319. node1.addChild(node3);
  320. assertNull('remove null', node1.removeChild(null));
  321. assertNull('remove non-child', node1.removeChild(node1));
  322. assertArrayEquals('node1 is intact', [node2, node3], node1.getChildren());
  323. assertEquals('remove node3, return value', node3, node1.removeChild(node3));
  324. assertArrayEquals('node is removed', [node2], node1.getChildren());
  325. }
  326. function testRemoveChildren() {
  327. var node1 = new goog.structs.TreeNode(1, null);
  328. var node2 = new goog.structs.TreeNode(2, null);
  329. var node3 = new goog.structs.TreeNode(3, null);
  330. node1.addChild(node2);
  331. node1.addChild(node3);
  332. node2.removeChildren();
  333. assertArrayEquals(
  334. 'removing a leaf node\'s children has no effect', [],
  335. node2.getChildren());
  336. assertEquals('node still has parent', node1, node2.getParent());
  337. node1.removeChildren();
  338. assertArrayEquals('children have been removed', [], node1.getChildren());
  339. assertNull('children\'s parents have been unset', node2.getParent());
  340. }