trie_test.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. // Copyright 2007 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.TrieTest');
  15. goog.setTestOnly('goog.structs.TrieTest');
  16. goog.require('goog.object');
  17. goog.require('goog.structs');
  18. goog.require('goog.structs.Trie');
  19. goog.require('goog.testing.jsunit');
  20. function makeTrie() {
  21. var trie = new goog.structs.Trie();
  22. trie.add('hello', 1);
  23. trie.add('hi', 'howdy');
  24. trie.add('', 'an empty string key');
  25. trie.add('empty value', '');
  26. trie.add('zero', 0);
  27. trie.add('object', {});
  28. trie.add('null', null);
  29. trie.add('hello, world', 2);
  30. trie.add('world', {});
  31. return trie;
  32. }
  33. function checkTrie(trie) {
  34. assertEquals('get, should be 1', trie.get('hello'), 1);
  35. assertEquals('get, should be "howdy"', trie.get('hi'), 'howdy');
  36. assertEquals(
  37. 'get, should be "an empty string key"', trie.get(''),
  38. 'an empty string key');
  39. assertEquals('get, should be ""', trie.get('empty value'), '');
  40. assertEquals('get, should be ""', typeof trie.get('empty value'), 'string');
  41. assertEquals('get, should be an object', typeof trie.get('object'), 'object');
  42. assertEquals('get, should be 0', trie.get('zero'), 0);
  43. assertEquals('get "null", should be null', trie.get('null'), null);
  44. assertEquals('get, should be 2', trie.get('hello, world'), 2);
  45. assertEquals('get, should be an object', typeof trie.get('world'), 'object');
  46. }
  47. function testTrieFormation() {
  48. var t = makeTrie();
  49. checkTrie(t);
  50. }
  51. function testFailureOfMultipleAdds() {
  52. var t = new goog.structs.Trie();
  53. t.add('hello', 'testing');
  54. assertThrows('Error should be thrown when same key added twice.', function() {
  55. t.add('hello', 'test');
  56. });
  57. t = new goog.structs.Trie();
  58. t.add('null', null);
  59. assertThrows('Error should be thrown when same key added twice.', function() {
  60. t.add('null', 'hi!');
  61. });
  62. t = new goog.structs.Trie();
  63. t.add('null', 'blah');
  64. assertThrows('Error should be thrown when same key added twice.', function() {
  65. t.add('null', null);
  66. });
  67. }
  68. function testTrieClone() {
  69. var trieOne = makeTrie();
  70. var trieTwo = new goog.structs.Trie(trieOne);
  71. checkTrie(trieTwo);
  72. }
  73. function testTrieFromObject() {
  74. var someObject = {
  75. 'hello': 1,
  76. 'hi': 'howdy',
  77. '': 'an empty string key',
  78. 'empty value': '',
  79. 'object': {},
  80. 'zero': 0,
  81. 'null': null,
  82. 'hello, world': 2,
  83. 'world': {}
  84. };
  85. var trie = new goog.structs.Trie(someObject);
  86. checkTrie(trie);
  87. }
  88. function testTrieGetValues() {
  89. var trie = makeTrie();
  90. var values = trie.getValues();
  91. assertTrue(
  92. 'getValues, should contain "howdy"',
  93. goog.object.contains(values, 'howdy'));
  94. assertTrue('getValues, should contain 1', goog.object.contains(values, 1));
  95. assertTrue('getValues, should contain 0', goog.object.contains(values, 0));
  96. assertTrue('getValues, should contain ""', goog.object.contains(values, ''));
  97. assertTrue(
  98. 'getValues, should contain null', goog.object.contains(values, null));
  99. assertEquals(
  100. 'goog.structs.getCount(getValues()) should be 9',
  101. goog.structs.getCount(values), 9);
  102. }
  103. function testTrieGetKeys() {
  104. var trie = makeTrie();
  105. var keys = trie.getKeys();
  106. assertTrue(
  107. 'getKeys, should contain "hello"', goog.object.contains(keys, 'hello'));
  108. assertTrue(
  109. 'getKeys, should contain "empty value"',
  110. goog.object.contains(keys, 'empty value'));
  111. assertTrue('getKeys, should contain ""', goog.object.contains(keys, ''));
  112. assertTrue(
  113. 'getKeys, should contain "zero"', goog.object.contains(keys, 'zero'));
  114. assertEquals(
  115. 'goog.structs.getCount(getKeys()) should be 9',
  116. goog.structs.getCount(keys), 9);
  117. }
  118. function testTrieCount() {
  119. var trieOne = makeTrie();
  120. var trieTwo = new goog.structs.Trie();
  121. assertEquals('count, should be 9', trieOne.getCount(), 9);
  122. assertEquals('count, should be 0', trieTwo.getCount(), 0);
  123. }
  124. function testRemoveKeyFromTrie() {
  125. var trie = new goog.structs.Trie();
  126. trie.add('key1', 'value1');
  127. trie.add('key2', 'value2');
  128. trie.add('ke', 'value3');
  129. trie.add('zero', 0);
  130. trie.remove('key2');
  131. assertEquals('get "key1", should be "value1"', trie.get('key1'), 'value1');
  132. assertUndefined('get "key2", should be undefined', trie.get('key2'));
  133. trie.remove('zero');
  134. assertUndefined('get "zero", should be undefined', trie.get('zero'));
  135. trie.remove('ke');
  136. assertUndefined('get "ke", should be undefined', trie.get('ke'));
  137. assertEquals('get "key1", should be "value1"', trie.get('key1'), 'value1');
  138. trie.add('a', 'value4');
  139. assertTrue(
  140. 'testing internal structure, a should be a child',
  141. 'a' in trie.childNodes_);
  142. trie.remove('a');
  143. assertFalse(
  144. 'testing internal structure, a should no longer be a child',
  145. 'a' in trie.childNodes_);
  146. trie.add('xyza', 'value');
  147. trie.remove('xyza', 'value');
  148. assertFalse('Should not have "x"', 'x' in trie.childNodes_);
  149. trie.add('xyza', null);
  150. assertTrue('Should have "x"', 'x' in trie.childNodes_);
  151. trie.remove('xyza');
  152. assertFalse('Should not have "x"', 'x' in trie.childNodes_);
  153. trie.add('xyza', 'value');
  154. trie.add('xb', 'value');
  155. trie.remove('xyza');
  156. assertTrue('get "x" should be defined', 'x' in trie.childNodes_);
  157. assertFalse(
  158. 'get "y" should be undefined', 'y' in trie.childNodes_['x'].childNodes_);
  159. trie.add('akey', 'value1');
  160. trie.add('akey1', 'value2');
  161. trie.remove('akey1');
  162. assertEquals('get "akey", should be "value1"', 'value1', trie.get('akey'));
  163. assertUndefined('get "akey1", should be undefined', trie.get('akey1'));
  164. }
  165. function testRemoveKeyFromTrieWithNulls() {
  166. var trie = new goog.structs.Trie();
  167. trie.add('key1', null);
  168. trie.add('key2', 'value2');
  169. trie.add('ke', 'value3');
  170. trie.add('zero', 0);
  171. trie.remove('key2');
  172. assertEquals('get "key1", should be null', trie.get('key1'), null);
  173. assertUndefined('get "key2", should be undefined', trie.get('key2'));
  174. trie.remove('zero');
  175. assertUndefined('get "zero", should be undefined', trie.get('zero'));
  176. trie.remove('ke');
  177. assertUndefined('get "ke", should be undefined', trie.get('ke'));
  178. assertEquals('get "key1", should be null', trie.get('key1'), null);
  179. trie.add('a', 'value4');
  180. assertTrue(
  181. 'testing internal structure, a should be a child',
  182. 'a' in trie.childNodes_);
  183. trie.remove('a');
  184. assertFalse(
  185. 'testing internal structure, a should no longer be a child',
  186. 'a' in trie.childNodes_);
  187. trie.add('xyza', null);
  188. trie.add('xb', 'value');
  189. trie.remove('xyza');
  190. assertTrue('Should have "x"', 'x' in trie.childNodes_);
  191. assertFalse('Should not have "y"', 'y' in trie.childNodes_['x'].childNodes_);
  192. }
  193. function testRemoveKeyException() {
  194. var trie = new goog.structs.Trie();
  195. trie.add('abcdefg', 'value');
  196. trie.add('abcz', 'value');
  197. trie.add('abc', 'value');
  198. assertThrows(
  199. 'Remove should throw an error on removal of non-existent key',
  200. function() { trie.remove('abcdefge'); });
  201. }
  202. function testTrieIsEmpty() {
  203. var trieOne = new goog.structs.Trie();
  204. var trieTwo = makeTrie();
  205. assertTrue('isEmpty, should be empty', trieOne.isEmpty());
  206. assertFalse('isEmpty, should not be empty', trieTwo.isEmpty());
  207. trieOne.add('', 1);
  208. assertFalse('isEmpty, should not be empty', trieTwo.isEmpty());
  209. trieOne.remove('');
  210. assertTrue('isEmpty, should be empty', trieOne.isEmpty());
  211. trieOne.add('', 1);
  212. trieOne.add('a', 1);
  213. trieOne.remove('a');
  214. assertFalse('isEmpty, should not be empty', trieOne.isEmpty());
  215. trieOne.remove('');
  216. assertTrue('isEmpty, should be empty', trieOne.isEmpty());
  217. trieOne.add('', 1);
  218. trieOne.add('a', 1);
  219. trieOne.remove('');
  220. assertFalse('isEmpty, should not be empty', trieOne.isEmpty());
  221. trieOne.remove('a');
  222. assertTrue('isEmpty, should be empty', trieOne.isEmpty());
  223. }
  224. function testTrieClear() {
  225. var trie = new goog.structs.Trie();
  226. trie.add('key1', 'value1');
  227. trie.add('key2', 'value2');
  228. trie.add('key3', null);
  229. trie.clear();
  230. assertUndefined('get key1, should be undefined', trie.get('key1'));
  231. assertUndefined('get key2, should be undefined', trie.get('key2'));
  232. assertUndefined('get key3, should be undefined', trie.get('key3'));
  233. }
  234. function testTrieContainsKey() {
  235. var trie = makeTrie();
  236. assertTrue('containsKey, should contain "hello"', trie.containsKey('hello'));
  237. assertTrue('containsKey, should contain "hi"', trie.containsKey('hi'));
  238. assertTrue('containsKey, should contain ""', trie.containsKey(''));
  239. assertTrue(
  240. 'containsKey, should contain "empty value"',
  241. trie.containsKey('empty value'));
  242. assertTrue(
  243. 'containsKey, should contain "object"', trie.containsKey('object'));
  244. assertTrue('containsKey, should contain "zero"', trie.containsKey('zero'));
  245. assertTrue('containsKey, should contain "null"', trie.containsKey('null'));
  246. assertFalse(
  247. 'containsKey, should not contain "blah"', trie.containsKey('blah'));
  248. trie.remove('');
  249. trie.remove('hi');
  250. trie.remove('zero');
  251. trie.remove('null');
  252. assertFalse(
  253. 'containsKey, should not contain "zero"', trie.containsKey('zero'));
  254. assertFalse('containsKey, should not contain ""', trie.containsKey(''));
  255. assertFalse('containsKey, should not contain "hi"', trie.containsKey('hi'));
  256. assertFalse(
  257. 'containsKey, should not contain "null"', trie.containsKey('null'));
  258. }
  259. function testTrieContainsPrefix() {
  260. // Empty trie.
  261. var trie = new goog.structs.Trie();
  262. assertFalse('containsPrefix, should not contain ""', trie.containsPrefix(''));
  263. assertFalse(
  264. 'containsPrefix, should not contain "any"', trie.containsPrefix('any'));
  265. trie.add('key', 'value');
  266. assertTrue('containsPrefix, should contain ""', trie.containsPrefix(''));
  267. // Non-empty trie.
  268. trie = makeTrie();
  269. assertTrue('containsPrefix, should contain ""', trie.containsPrefix(''));
  270. assertFalse(
  271. 'containsPrefix, should not contain "blah"', trie.containsPrefix('blah'));
  272. assertTrue('containsPrefix, should contain "h"', trie.containsPrefix('h'));
  273. assertTrue(
  274. 'containsPrefix, should contain "hello"', trie.containsPrefix('hello'));
  275. assertTrue(
  276. 'containsPrefix, should contain "hello, world"',
  277. trie.containsPrefix('hello, world'));
  278. assertFalse(
  279. 'containsPrefix, should not contain "hello, world!"',
  280. trie.containsPrefix('hello, world!'));
  281. assertTrue('containsPrefix, should contain "nu"', trie.containsPrefix('nu'));
  282. assertTrue(
  283. 'containsPrefix, should contain "null"', trie.containsPrefix('null'));
  284. assertTrue(
  285. 'containsPrefix, should contain "empty value"',
  286. trie.containsPrefix('empty value'));
  287. // Remove nodes.
  288. trie.remove('');
  289. assertTrue('containsPrefix, should contain ""', trie.containsPrefix(''));
  290. trie.remove('hi');
  291. assertTrue('containsPrefix, should contain "h"', trie.containsPrefix('h'));
  292. assertFalse(
  293. 'containsPrefix, should not contain "hi"', trie.containsPrefix('hi'));
  294. trie.remove('hello');
  295. trie.remove('hello, world');
  296. assertFalse(
  297. 'containsPrefix, should not contain "h"', trie.containsPrefix('h'));
  298. assertFalse(
  299. 'containsPrefix, should not contain "hello"',
  300. trie.containsPrefix('hello'));
  301. // Remove all nodes.
  302. trie.remove('empty value');
  303. trie.remove('zero');
  304. trie.remove('object');
  305. trie.remove('null');
  306. trie.remove('world');
  307. assertFalse('containsPrefix, should not contain ""', trie.containsPrefix(''));
  308. assertFalse(
  309. 'containsPrefix, should not contain "h"', trie.containsPrefix('h'));
  310. assertFalse(
  311. 'containsPrefix, should not contain "hi"', trie.containsPrefix('hi'));
  312. // Add some new nodes.
  313. trie.add('hi', 'value');
  314. trie.add('null', 'value');
  315. assertTrue('containsPrefix, should contain ""', trie.containsPrefix(''));
  316. assertTrue('containsPrefix, should contain "h"', trie.containsPrefix('h'));
  317. assertTrue('containsPrefix, should contain "hi"', trie.containsPrefix('hi'));
  318. assertFalse(
  319. 'containsPrefix, should not contain "hello"',
  320. trie.containsPrefix('hello'));
  321. assertFalse(
  322. 'containsPrefix, should not contain "zero"', trie.containsPrefix('zero'));
  323. // Clear the trie.
  324. trie.clear();
  325. assertFalse('containsPrefix, should not contain ""', trie.containsPrefix(''));
  326. assertFalse(
  327. 'containsPrefix, should not contain "h"', trie.containsPrefix('h'));
  328. assertFalse(
  329. 'containsPrefix, should not contain "hi"', trie.containsPrefix('hi'));
  330. }
  331. function testTrieContainsValue() {
  332. var trie = makeTrie();
  333. assertTrue(
  334. 'containsValue, should be true, should contain 1', trie.containsValue(1));
  335. assertTrue(
  336. 'containsValue, should be true, should contain "howdy"',
  337. trie.containsValue('howdy'));
  338. assertTrue(
  339. 'containsValue, should be true, should contain ""',
  340. trie.containsValue(''));
  341. assertTrue(
  342. 'containsValue, should be true, should contain 0', trie.containsValue(0));
  343. assertTrue(
  344. 'containsValue, should be true, should contain null',
  345. trie.containsValue(null));
  346. assertTrue(
  347. 'containsValue, should be true, should ' +
  348. 'contain "an empty string key"',
  349. trie.containsValue('an empty string key'));
  350. assertFalse(
  351. 'containsValue, should be false, should not contain "blah"',
  352. trie.containsValue('blah'));
  353. trie.remove('empty value');
  354. trie.remove('zero');
  355. assertFalse(
  356. 'containsValue, should be false, should not contain 0',
  357. trie.containsValue(0));
  358. assertFalse(
  359. 'containsValue, should be false, should not contain ""',
  360. trie.containsValue(''));
  361. }
  362. function testTrieHandlingOfEmptyStrings() {
  363. var trie = new goog.structs.Trie();
  364. assertEquals('get, should be undefined', trie.get(''), undefined);
  365. assertFalse('containsValue, should be false', trie.containsValue(''));
  366. assertFalse('containsKey, should be false', trie.containsKey(''));
  367. trie.add('', 'test');
  368. trie.add('test2', '');
  369. assertTrue('containsValue, should be true', trie.containsValue(''));
  370. assertTrue('containsKey, should be true', trie.containsKey(''));
  371. assertEquals('get, should be "test"', trie.get(''), 'test');
  372. assertEquals('get, should be ""', trie.get('test2'), '');
  373. trie.remove('');
  374. trie.remove('test2');
  375. assertEquals('get, should be undefined', trie.get(''), undefined);
  376. assertFalse('containsValue, should be false', trie.containsValue(''));
  377. assertFalse('containsKey, should be false', trie.containsKey(''));
  378. }
  379. function testPrefixOptionOnGetKeys() {
  380. var trie = new goog.structs.Trie();
  381. trie.add('abcdefg', 'one');
  382. trie.add('abcdefghijk', 'two');
  383. trie.add('abcde', 'three');
  384. trie.add('abcq', null);
  385. trie.add('abc', 'four');
  386. trie.add('xyz', 'five');
  387. assertEquals('getKeys, should be 1', trie.getKeys('xy').length, 1);
  388. assertEquals('getKeys, should be 1', trie.getKeys('xyz').length, 1);
  389. assertEquals('getKeys, should be 1', trie.getKeys('x').length, 1);
  390. assertEquals('getKeys, should be 4', trie.getKeys('abc').length, 5);
  391. assertEquals('getKeys, should be 2', trie.getKeys('abcdef').length, 2);
  392. assertEquals('getKeys, should be 0', trie.getKeys('abcdefgi').length, 0);
  393. }
  394. function testGetKeyAndPrefixes() {
  395. var trie = makeTrie();
  396. // Note: trie has one of its keys as ''
  397. assertEquals(
  398. 'getKeyAndPrefixes, should be 2', 2,
  399. goog.object.getCount(trie.getKeyAndPrefixes('world')));
  400. assertEquals(
  401. 'getKeyAndPrefixes, should be 2', 2,
  402. goog.object.getCount(trie.getKeyAndPrefixes('hello')));
  403. assertEquals(
  404. 'getKeyAndPrefixes, should be 2', 2,
  405. goog.object.getCount(trie.getKeyAndPrefixes('hello,')));
  406. assertEquals(
  407. 'getKeyAndPrefixes, should be 3', 3,
  408. goog.object.getCount(trie.getKeyAndPrefixes('hello, world')));
  409. assertEquals(
  410. 'getKeyAndPrefixes, should be 1', 1,
  411. goog.object.getCount(trie.getKeyAndPrefixes('hell')));
  412. }
  413. function testGetKeyAndPrefixesStartIndex() {
  414. var trie = new goog.structs.Trie();
  415. trie.add('abcdefg', 'one');
  416. trie.add('bcdefg', 'two');
  417. trie.add('abcdefghijk', 'three');
  418. trie.add('abcde', 'four');
  419. trie.add('abcq', null);
  420. trie.add('q', null);
  421. trie.add('abc', 'five');
  422. trie.add('xyz', 'six');
  423. assertEquals(
  424. 'getKeyAndPrefixes, should be 3', 3,
  425. goog.object.getCount(trie.getKeyAndPrefixes('abcdefg', 0)));
  426. assertEquals(
  427. 'getKeyAndPrefixes, should be 1', 1,
  428. goog.object.getCount(trie.getKeyAndPrefixes('abcdefg', 1)));
  429. assertEquals(
  430. 'getKeyAndPrefixes, should be 1', 1,
  431. goog.object.getCount(trie.getKeyAndPrefixes('abcq', 3)));
  432. assertEquals(
  433. 'getKeyAndPrefixes, should be 0', 0,
  434. goog.object.getCount(trie.getKeyAndPrefixes('abcd', 3)));
  435. }