indexmanager_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package util
  11. import (
  12. "fmt"
  13. "strings"
  14. "testing"
  15. "devt.de/krotik/common/bitutil"
  16. "devt.de/krotik/eliasdb/hash"
  17. "devt.de/krotik/eliasdb/storage"
  18. )
  19. func TestIndexManager(t *testing.T) {
  20. sm := storage.NewMemoryStorageManager("testsm")
  21. htree, _ := hash.NewHTree(sm)
  22. im := NewIndexManager(htree)
  23. obj1 := make(map[string]string)
  24. obj1["aaa"] = "DDD voldaaa ddd"
  25. obj1["bbb"] = "vbbb"
  26. im.Index("testkey", obj1)
  27. if res, _ := im.LookupWord("aaa", "ddd"); fmt.Sprint(res) != "map[testkey:[1 3]]" {
  28. t.Error("Unexpected lookup result:", res)
  29. return
  30. }
  31. CaseSensitiveWordIndex = true
  32. sm = storage.NewMemoryStorageManager("testsm")
  33. htree, _ = hash.NewHTree(sm)
  34. im = NewIndexManager(htree)
  35. im.Index("testkey", obj1)
  36. if res, _ := im.LookupWord("aaa", "ddd"); fmt.Sprint(res) != "map[testkey:[3]]" {
  37. t.Error("Unexpected lookup result:", res)
  38. return
  39. }
  40. if res, _ := im.Count("aaa", "ddd"); res != 1 {
  41. t.Error("Unexpected count result:", res)
  42. return
  43. }
  44. CaseSensitiveWordIndex = false
  45. sm = storage.NewMemoryStorageManager("testsm")
  46. htree, _ = hash.NewHTree(sm)
  47. im = NewIndexManager(htree)
  48. im.Index("testkey", obj1)
  49. if res, _ := im.LookupWord("aaa", "ddd"); fmt.Sprint(res) != "map[testkey:[1 3]]" {
  50. t.Error("Unexpected lookup result:", res)
  51. return
  52. }
  53. for i := 0; i < 6; i++ {
  54. sm.AccessMap[uint64(i)] = storage.AccessCacheAndFetchError
  55. }
  56. if _, err := im.LookupWord("aaa", "ddd"); !strings.Contains(err.Error(), "Slot not found") {
  57. t.Error("Unexpected lookup result:", err)
  58. return
  59. }
  60. if err := im.Index("testkey", obj1); !strings.Contains(err.Error(), "Slot not found") {
  61. t.Error("Unexpected index result:", err)
  62. return
  63. }
  64. if err := im.Deindex("testkey", obj1); !strings.Contains(err.Error(), "Slot not found") {
  65. t.Error("Unexpected index result:", err)
  66. return
  67. }
  68. for i := 0; i < 6; i++ {
  69. delete(sm.AccessMap, uint64(i))
  70. }
  71. obj2 := make(map[string]string)
  72. obj2["aaa"] = "ddd vnewaaa"
  73. obj2["ccc"] = "ccc"
  74. if err := im.Reindex("testkey", obj2, obj1); err != nil {
  75. t.Error(err)
  76. return
  77. }
  78. if res := countChildren(htree); res != 5 {
  79. t.Error("Unexpected number of children:", res)
  80. return
  81. }
  82. if res, err := im.LookupWord("aaa", "DdD"); fmt.Sprint(res) != "map[testkey:[1]]" {
  83. t.Error("Unexpected lookup result:", res, err)
  84. return
  85. }
  86. if res, _ := im.Count("aaa", "dDD"); res != 1 {
  87. t.Error("Unexpected count result:", res)
  88. return
  89. }
  90. if res, _ := im.Count("aab", "dDD"); res != 0 {
  91. t.Error("Unexpected count result:", res)
  92. return
  93. }
  94. if err := im.Deindex("testkey", obj2); err != nil {
  95. t.Error(err)
  96. return
  97. }
  98. if res := countChildren(htree); res != 0 {
  99. t.Error("Unexpected number of children:", res)
  100. return
  101. }
  102. }
  103. func TestPhraseSearch(t *testing.T) {
  104. sm := storage.NewMemoryStorageManager("testsm")
  105. htree, _ := hash.NewHTree(sm)
  106. im := NewIndexManager(htree)
  107. obj1 := make(map[string]string)
  108. obj1["aaa"] = "the Is xxx The grass Is grEEn zzz"
  109. im.Index("testkey", obj1)
  110. obj2 := make(map[string]string)
  111. obj2["aaa"] = "the Is xxx The grass Is graY zzz"
  112. im.Index("testkey2", obj2)
  113. obj3 := make(map[string]string)
  114. obj3["aaa"] = "green grass is green zzz"
  115. im.Index("testkey3", obj3)
  116. obj4 := make(map[string]string)
  117. obj4["aaa"] = "green grass is so green zzz"
  118. obj4["bbb"] = "test"
  119. im.Index("testkey4", obj4)
  120. res, err := im.LookupPhrase("aaa", "grass is green")
  121. if fmt.Sprint(res) != "[testkey testkey3]" || err != nil {
  122. t.Error("Unexpected lookup result:", res, err)
  123. }
  124. res, err = im.LookupPhrase("aaa", "zzz")
  125. if fmt.Sprint(res) != "[testkey testkey2 testkey3 testkey4]" || err != nil {
  126. t.Error("Unexpected lookup result:", res, err)
  127. }
  128. res, err = im.LookupPhrase("bbb", "test")
  129. if fmt.Sprint(res) != "[testkey4]" || err != nil {
  130. t.Error("Unexpected lookup result:", res, err)
  131. }
  132. // Test empty return cases
  133. res, err = im.LookupPhrase("bbb", "")
  134. if res != nil || err != nil {
  135. t.Error("Unexpected result:", res, err)
  136. }
  137. res, err = im.LookupPhrase("bbb", "b")
  138. if res != nil || err != nil {
  139. t.Error("Unexpected result:", res, err)
  140. }
  141. for i := 0; i < 10; i++ {
  142. sm.AccessMap[uint64(i)] = storage.AccessCacheAndFetchError
  143. }
  144. res, err = im.LookupPhrase("aaa", "grass is green")
  145. if res != nil || !strings.Contains(err.Error(), "Slot not found") {
  146. t.Error("Unexpected result:", res, err)
  147. }
  148. if _, err := im.Count("aaa", "grass"); !strings.Contains(err.Error(), "Slot not found") {
  149. t.Error("Unexpected count result:", err)
  150. return
  151. }
  152. for i := 0; i < 10; i++ {
  153. delete(sm.AccessMap, uint64(i))
  154. }
  155. }
  156. func TestUpdateIndex(t *testing.T) {
  157. sm := storage.NewMemoryStorageManager("testsm")
  158. htree, _ := hash.NewHTree(sm)
  159. im := NewIndexManager(htree)
  160. obj1 := make(map[string]string)
  161. obj1["aaa"] = "vnewaaa ddd"
  162. obj1["bbb"] = "vbbb"
  163. obj2 := make(map[string]string)
  164. obj2["aaa"] = "ddd voldaaa"
  165. obj2["ccc"] = "ccc"
  166. // Insert into the index
  167. im.updateIndex("123", obj2, nil)
  168. // Check that the entries exist
  169. entry, _ := htree.Get([]byte(PrefixAttrWord + "aaa" + "ddd"))
  170. pos := entry.(*indexEntry).WordPos["123"]
  171. if fmt.Sprint(bitutil.UnpackList(pos)) != "[1]" {
  172. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  173. return
  174. }
  175. entry, _ = htree.Get([]byte(PrefixAttrWord + "aaa" + "voldaaa"))
  176. pos = entry.(*indexEntry).WordPos["123"]
  177. if fmt.Sprint(bitutil.UnpackList(pos)) != "[2]" {
  178. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  179. return
  180. }
  181. entry, _ = htree.Get([]byte(PrefixAttrWord + "ccc" + "ccc"))
  182. pos = entry.(*indexEntry).WordPos["123"]
  183. if fmt.Sprint(bitutil.UnpackList(pos)) != "[1]" {
  184. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  185. return
  186. }
  187. if res := countChildren(htree); res != 5 {
  188. t.Error("Unexpected number of children:", res)
  189. return
  190. }
  191. // Update the index
  192. im.updateIndex("123", obj1, obj2)
  193. if res := countChildren(htree); res != 5 {
  194. t.Error("Unexpected number of children:", res)
  195. return
  196. }
  197. // Check that the entries exist
  198. entry, _ = htree.Get([]byte(PrefixAttrWord + "aaa" + "ddd"))
  199. pos = entry.(*indexEntry).WordPos["123"]
  200. if fmt.Sprint(bitutil.UnpackList(pos)) != "[2]" {
  201. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  202. return
  203. }
  204. entry, _ = htree.Get([]byte(PrefixAttrWord + "aaa" + "voldaaa"))
  205. if entry != nil {
  206. t.Error("Unexpected result")
  207. return
  208. }
  209. entry, _ = htree.Get([]byte(PrefixAttrWord + "aaa" + "vnewaaa"))
  210. pos = entry.(*indexEntry).WordPos["123"]
  211. if fmt.Sprint(bitutil.UnpackList(pos)) != "[1]" {
  212. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  213. return
  214. }
  215. entry, _ = htree.Get([]byte(PrefixAttrWord + "bbb" + "vbbb"))
  216. pos = entry.(*indexEntry).WordPos["123"]
  217. if fmt.Sprint(bitutil.UnpackList(pos)) != "[1]" {
  218. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  219. return
  220. }
  221. // Delete from the index
  222. im.updateIndex("123", nil, obj1)
  223. if res := countChildren(htree); res != 0 {
  224. t.Error("Unexpected number of children:", res)
  225. return
  226. }
  227. }
  228. func countChildren(tree *hash.HTree) int {
  229. var count int
  230. it := hash.NewHTreeIterator(tree)
  231. for it.HasNext() {
  232. it.Next()
  233. count++
  234. }
  235. return count
  236. }
  237. func TestAddRemoveIndexHashEntry(t *testing.T) {
  238. sm := storage.NewMemoryStorageManager("testsm")
  239. htree, _ := hash.NewHTree(sm)
  240. im := NewIndexManager(htree)
  241. oldsetting := CaseSensitiveWordIndex
  242. CaseSensitiveWordIndex = false
  243. im.addIndexHashEntry("mykey2", "myattr", "testvalue")
  244. im.addIndexHashEntry("mykey3", "myattr", "testvalue")
  245. sm.AccessMap[2] = storage.AccessCacheAndFetchError
  246. if err := im.addIndexHashEntry("mykey2", "myattr", "testvalue"); err != storage.ErrSlotNotFound {
  247. t.Error(err)
  248. return
  249. }
  250. if err := im.removeIndexHashEntry("mykey2", "myattr", "testvalue"); err != storage.ErrSlotNotFound {
  251. t.Error(err)
  252. return
  253. }
  254. if _, err := im.LookupValue("myattr", "testvalue"); !strings.Contains(err.Error(), "Slot not found") {
  255. t.Error(err)
  256. return
  257. }
  258. delete(sm.AccessMap, 2)
  259. // Test lookup
  260. res, _ := im.LookupValue("myattr", "testvalue")
  261. if fmt.Sprint(res) != "[mykey2 mykey3]" {
  262. t.Error("Unexpected lookup value result:", res)
  263. return
  264. }
  265. res, _ = im.LookupValue("myattr", "testvalue2")
  266. if fmt.Sprint(res) != "[]" {
  267. t.Error("Unexpected lookup value result:", res)
  268. return
  269. }
  270. im.removeIndexHashEntry("mykey2", "myattr", "testvalue")
  271. im.removeIndexHashEntry("mykey3", "myattr", "testvalue")
  272. if count := countChildren(htree); count != 0 {
  273. t.Error("Unexpected child count:", count)
  274. return
  275. }
  276. // Check handling of non-existent entries
  277. if res := im.removeIndexHashEntry("mykey4", "myattr", "testvalue"); res != nil {
  278. t.Error("Unexpected result:", res)
  279. return
  280. }
  281. // Test case sensitive case
  282. CaseSensitiveWordIndex = true
  283. im.addIndexHashEntry("mykey2", "myattr", "testValue")
  284. im.addIndexHashEntry("mykey3", "myattr", "testValue")
  285. if count := countChildren(htree); count != 1 {
  286. t.Error("Unexpected child count:", count)
  287. return
  288. }
  289. res, _ = im.LookupValue("myattr", "testvalue")
  290. if fmt.Sprint(res) != "[]" {
  291. t.Error("Unexpected lookup value result:", res)
  292. return
  293. }
  294. res, _ = im.LookupValue("myattr", "testValue")
  295. if fmt.Sprint(res) != "[mykey2 mykey3]" {
  296. t.Error("Unexpected lookup value result:", res)
  297. return
  298. }
  299. im.removeIndexHashEntry("mykey2", "myattr", "testvalue")
  300. im.removeIndexHashEntry("mykey3", "myattr", "testvalue")
  301. if count := countChildren(htree); count != 1 {
  302. t.Error("Unexpected child count:", count)
  303. return
  304. }
  305. im.removeIndexHashEntry("mykey2", "myattr", "testValue")
  306. im.removeIndexHashEntry("mykey3", "myattr", "testValue")
  307. if count := countChildren(htree); count != 0 {
  308. t.Error("Unexpected child count:", count)
  309. return
  310. }
  311. CaseSensitiveWordIndex = oldsetting
  312. }
  313. func TestAddRemoveIndexEntry(t *testing.T) {
  314. sm := storage.NewMemoryStorageManager("testsm")
  315. htree, _ := hash.NewHTree(sm)
  316. im := NewIndexManager(htree)
  317. im.addIndexEntry("mykey", "myattr", "myword", []uint64{1, 5, 7})
  318. im.addIndexEntry("mykey2", "myattr", "myword", []uint64{10, 12, 80})
  319. entry, _ := htree.Get([]byte(PrefixAttrWord + "myattr" + "myword"))
  320. pos := entry.(*indexEntry).WordPos["mykey"]
  321. if fmt.Sprint(bitutil.UnpackList(pos)) != "[1 5 7]" {
  322. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  323. return
  324. }
  325. pos = entry.(*indexEntry).WordPos["mykey2"]
  326. if fmt.Sprint(bitutil.UnpackList(pos)) != "[10 12 80]" {
  327. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  328. return
  329. }
  330. testAddIndexPanic(t, im)
  331. sm.AccessMap[2] = storage.AccessCacheAndFetchError
  332. if res := im.addIndexEntry("mykey2", "myattr", "myword", []uint64{10, 12, 80}); res != storage.ErrSlotNotFound {
  333. t.Error("Unexpected result:", res)
  334. return
  335. }
  336. if res := im.removeIndexEntry("mykey2", "myattr", "myword", []uint64{10, 12, 80}); res != storage.ErrSlotNotFound {
  337. t.Error("Unexpected result:", res)
  338. return
  339. }
  340. delete(sm.AccessMap, 2)
  341. im.removeIndexEntry("mykey", "myattr", "myword", []uint64{1, 5, 7})
  342. entry, _ = htree.Get([]byte(PrefixAttrWord + "myattr" + "myword"))
  343. if res := len(entry.(*indexEntry).WordPos); res != 1 {
  344. t.Error("Unexpected length:", res)
  345. return
  346. }
  347. pos = entry.(*indexEntry).WordPos["mykey2"]
  348. if fmt.Sprint(bitutil.UnpackList(pos)) != "[10 12 80]" {
  349. t.Error("Unexpected result:", fmt.Sprint(bitutil.UnpackList(pos)))
  350. return
  351. }
  352. if im.removeIndexEntry("mykey3", "myattr", "myword", []uint64{10, 12, 80}) != nil {
  353. t.Error("Unexpected result")
  354. return
  355. }
  356. entry, _ = htree.Get([]byte(PrefixAttrWord + "myattr" + "myword"))
  357. if len(entry.(*indexEntry).WordPos) != 1 {
  358. t.Error("Unexpected length")
  359. return
  360. }
  361. if im.removeIndexEntry("mykey2", "myattr2", "myword", []uint64{10, 12, 80}) != nil {
  362. t.Error("Unexpected result")
  363. return
  364. }
  365. entry, _ = htree.Get([]byte(PrefixAttrWord + "myattr" + "myword"))
  366. if len(entry.(*indexEntry).WordPos) != 1 {
  367. t.Error("Unexpected length")
  368. return
  369. }
  370. if posres := fmt.Sprint(bitutil.UnpackList(entry.(*indexEntry).WordPos["mykey2"])); posres != "[10 12 80]" {
  371. t.Error("Unexpected pos list:", posres)
  372. return
  373. }
  374. // Test adding in non standard order
  375. if im.addIndexEntry("mykey2", "myattr", "myword", []uint64{45, 13}) != nil {
  376. t.Error("Unexpected result")
  377. return
  378. }
  379. if posres := fmt.Sprint(bitutil.UnpackList(entry.(*indexEntry).WordPos["mykey2"])); posres != "[10 12 13 45 80]" {
  380. t.Error("Unexpected pos list:", posres)
  381. return
  382. }
  383. // Test removal in non standard order
  384. if im.removeIndexEntry("mykey2", "myattr", "myword", []uint64{10, 80, 45, 13}) != nil {
  385. t.Error("Unexpected result")
  386. return
  387. }
  388. if posres := fmt.Sprint(bitutil.UnpackList(entry.(*indexEntry).WordPos["mykey2"])); posres != "[12]" {
  389. t.Error("Unexpected pos list:", posres)
  390. return
  391. }
  392. }
  393. func TestIndexManagerHashErrors(t *testing.T) {
  394. sm := storage.NewMemoryStorageManager("testsm")
  395. htree, _ := hash.NewHTree(sm)
  396. im := NewIndexManager(htree)
  397. obj1 := make(map[string]string)
  398. obj1["aaa"] = "DDD voldaaa ddd"
  399. obj2 := make(map[string]string)
  400. obj2["aaa"] = "DDDe voldaaa ddd"
  401. im.Index("testkey", obj1)
  402. sm.AccessMap[4] = storage.AccessCacheAndFetchError
  403. if err := im.Index("testkey", obj1); err == nil {
  404. t.Error("Error expected")
  405. return
  406. }
  407. if err := im.Reindex("testkey", obj1, obj1); err == nil {
  408. t.Error("Error expected")
  409. return
  410. }
  411. if err := im.Deindex("testkey", obj1); err == nil {
  412. t.Error("Error expected")
  413. return
  414. }
  415. sm.AccessMap[5] = storage.AccessUpdateError
  416. if err := im.Reindex("testkey", obj1, obj2); err == nil {
  417. t.Error("Error expected")
  418. return
  419. }
  420. delete(sm.AccessMap, 4)
  421. }
  422. func testAddIndexPanic(t *testing.T, in *IndexManager) {
  423. defer func() {
  424. if r := recover(); r == nil {
  425. t.Error("Adding empty pos list did not cause a panic.")
  426. }
  427. }()
  428. in.addIndexEntry("", "", "", []uint64{})
  429. }
  430. func TestExtractWords(t *testing.T) {
  431. oldsetting := CaseSensitiveWordIndex
  432. CaseSensitiveWordIndex = false
  433. ws := extractWords(" aaa BBB ;, ccc...aaa ddd-bbb xxxx aaaa test1\n" +
  434. "test2 xxxx bbb")
  435. if res := ws.String(); res != "WordSet:\n"+
  436. " aaa [1 4]\n"+
  437. " aaaa [8]\n"+
  438. " bbb [2 6 12]\n"+
  439. " ccc [3]\n"+
  440. " ddd [5]\n"+
  441. " test1 [9]\n"+
  442. " test2 [10]\n"+
  443. " xxxx [7 11]\n" {
  444. t.Error("Unexpected WordSet string result:", res)
  445. }
  446. CaseSensitiveWordIndex = true
  447. ws = extractWords(" aaa BBB ccc aaa ddd bbb xxxx aaaa test1\n" +
  448. "test2 xxxx bbb")
  449. if res := ws.String(); res != "WordSet:\n"+
  450. " BBB [2]\n"+
  451. " aaa [1 4]\n"+
  452. " aaaa [8]\n"+
  453. " bbb [6 12]\n"+
  454. " ccc [3]\n"+
  455. " ddd [5]\n"+
  456. " test1 [9]\n"+
  457. " test2 [10]\n"+
  458. " xxxx [7 11]\n" {
  459. t.Error("Unexpected WordSet string result:", res)
  460. }
  461. CaseSensitiveWordIndex = oldsetting
  462. }
  463. func TestWordSet(t *testing.T) {
  464. ws := newWordSet(1)
  465. ws2 := newWordSet(1)
  466. ws3 := newWordSet(1)
  467. ws.Add("aaa", 1)
  468. ws.Add("bbb", 2)
  469. ws2.Add("bbb", 3)
  470. ws3.Add("ccc", 4)
  471. if !ws.Has("bbb") || ws.Has("ccc") {
  472. t.Error("Unexpected has result")
  473. return
  474. }
  475. if res := ws.String(); res != "WordSet:\n"+
  476. " aaa [1]\n"+
  477. " bbb [2]\n" {
  478. t.Error("Unexpected string result:", res)
  479. return
  480. }
  481. ws.AddAll(ws2)
  482. if res := ws2.String(); res != "WordSet:\n"+
  483. " bbb [3]\n" {
  484. t.Error("Unexpected string result:", res)
  485. return
  486. }
  487. if res := ws.String(); res != "WordSet:\n"+
  488. " aaa [1]\n"+
  489. " bbb [2 3]\n" {
  490. t.Error("Unexpected string result:", res)
  491. return
  492. }
  493. ws.Add("bbb", 1)
  494. ws.AddAll(ws3)
  495. if res := ws.String(); res != "WordSet:\n"+
  496. " aaa [1]\n"+
  497. " bbb [1 2 3]\n"+
  498. " ccc [4]\n" {
  499. t.Error("Unexpected string result:", res)
  500. return
  501. }
  502. ws.Remove("aaa", 1)
  503. ws.Remove("bbb", 2)
  504. ws.Remove("bbb", 1)
  505. if res := ws.String(); res != "WordSet:\n"+
  506. " bbb [3]\n"+
  507. " ccc [4]\n" {
  508. t.Error("Unexpected string result:", res)
  509. return
  510. }
  511. ws.Add("bbb", 4)
  512. ws.Add("bbb", 8)
  513. ws.Add("bbb", 10)
  514. ws4 := newWordSet(1)
  515. ws4.Add("bbb", 2)
  516. ws4.Add("bbb", 3)
  517. ws4.Add("bbb", 4)
  518. ws4.Add("bbb", 8)
  519. if res := ws.String(); res != "WordSet:\n"+
  520. " bbb [3 4 8 10]\n"+
  521. " ccc [4]\n" {
  522. t.Error("Unexpected string result:", res)
  523. return
  524. }
  525. ws.RemoveAll(ws4)
  526. if res := ws.String(); res != "WordSet:\n"+
  527. " bbb [10]\n"+
  528. " ccc [4]\n" {
  529. t.Error("Unexpected string result:", res)
  530. return
  531. }
  532. if res := fmt.Sprint(ws4.Pos("bbb")); res != "[2 3 4 8]" {
  533. t.Error("Unexpected pos result:", res)
  534. return
  535. }
  536. if res := ws4.Pos("abb"); res != nil {
  537. t.Error("Unexpected pos result:", res)
  538. return
  539. }
  540. // Test double entries
  541. ws.Add("ccc", 3)
  542. ws.Add("ccc", 5)
  543. ws.Add("ccc", 4)
  544. if res := ws.String(); res != "WordSet:\n"+
  545. " bbb [10]\n"+
  546. " ccc [3 4 5]\n" {
  547. t.Error("Unexpected string result:", res)
  548. return
  549. }
  550. }
  551. func TestRemoveDuplicates(t *testing.T) {
  552. if res := fmt.Sprint(removeDuplicates([]uint64{1, 2, 2, 3})); res != "[1 2 3]" {
  553. t.Error("Unexpected remove duplicates result:", res)
  554. return
  555. }
  556. if res := fmt.Sprint(removeDuplicates([]uint64{})); res != "[]" {
  557. t.Error("Unexpected remove duplicates result:", res)
  558. return
  559. }
  560. }
  561. func TestIndexManagerString(t *testing.T) {
  562. sm := storage.NewMemoryStorageManager("testsm")
  563. htree, _ := hash.NewHTree(sm)
  564. im := NewIndexManager(htree)
  565. obj1 := make(map[string]string)
  566. obj1["aaa"] = "bbb"
  567. im.Index("testkey", obj1)
  568. if res := im.String(); res != "IndexManager: 1\n"+
  569. " 1\"aaa\\b\\xf8\\xe0&\\fdA\\x85\\x10\\xce\\xfb+\\x06\\xee\\xe5\\xcd\" map[testkey:[]]\n"+
  570. " 1\"aaabbb\" map[testkey:[1]]\n" && res != "IndexManager: 1\n"+
  571. " 1\"aaabbb\" map[testkey:[1]]\n"+
  572. " 2\"aaa\\b\\xf8\\xe0&\\fdA\\x85\\x10\\xce\\xfb+\\x06\\xee\\xe5\\xcd\" map[testkey:[]]\n" {
  573. t.Error("Unexpected string output:", res)
  574. return
  575. }
  576. }