| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 | /* * EliasDB * * Copyright 2016 Matthias Ladkau. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */package hashimport (	"fmt"	"testing"	"devt.de/krotik/eliasdb/storage"	"devt.de/krotik/eliasdb/storage/file")func TestIterator(t *testing.T) {	// Do a very simple case	sm := storage.NewMemoryStorageManager("testsm")	htree, _ := NewHTree(sm)	page := htree.Root	if loc := page.Location(); loc != 1 {		t.Error("Unexpected root location:", loc)		return	}	// Fill up the tree	page.Put([]byte("testkey1"), "test1")	page.Put([]byte("testkey8"), "test8")	page.Put([]byte("testkey5"), "test5")	it := NewHTreeIterator(htree)	if k, v := it.Next(); string(k) != "testkey1" || v != "test1" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey8" || v != "test8" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey5" || v != "test5" {		t.Error("Unexpected next result:", k, v)		return	}	if it.HasNext() {		t.Error("Iterator should be finished")		return	}	if k, v := it.Next(); k != nil || v != nil {		t.Error("Return values should be nil")		return	}	// Create a new iterator and try the same steps again	it = NewHTreeIterator(htree)	if k, v := it.Next(); string(k) != "testkey1" || v != "test1" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey8" || v != "test8" {		t.Error("Unexpected next result:", k, v)		return	}	// But before the iterator finishes we change the tree behind its back	page.Put([]byte("testkey2"), "test2")	page.Put([]byte("testkey3"), "test3")	page.Put([]byte("testkey4"), "test4")	page.Put([]byte("testkey6"), "test6")	page.Put([]byte("testkey7"), "test7")	page.Put([]byte("testkey9"), "test9")	page.Put([]byte("testkey100"), "test100")	page.Put([]byte("abba1"), "song1")	page.Put([]byte("tfst"), "zzzz")	// The tree has changed behind the iterator's back.	if k, v := it.Next(); string(k) != "testkey5" || v != "test5" {		t.Error("Unexpected next result:", k, v)		return	}	// We get now all the items in the Children array of the root page which	// have been inserted after the current location. The iterator then finishes	// normally.	if k, v := it.Next(); string(k) != "tfst" || v != "zzzz" {		t.Error("Unexpected next result:", k, v)		return	}	if it.HasNext() {		t.Error("Iterator should be finished")		return	}	if k, v := it.Next(); k != nil || v != nil {		t.Error("Return values should be nil")		return	}	// Create a new iterator and see that we can iterate everything	it = NewHTreeIterator(htree)	if k, v := it.Next(); string(k) != "testkey100" || v != "test100" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "abba1" || v != "song1" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey1" || v != "test1" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey8" || v != "test8" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey5" || v != "test5" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey2" || v != "test2" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey3" || v != "test3" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey4" || v != "test4" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey6" || v != "test6" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey7" || v != "test7" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "testkey9" || v != "test9" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); string(k) != "tfst" || v != "zzzz" {		t.Error("Unexpected next result:", k, v)		return	}	if it.HasNext() {		t.Error("Iterator should be finished")		return	}	if k, v := it.Next(); k != nil || v != nil {		t.Error("Return values should be nil")		return	}	// Test error case	it = NewHTreeIterator(htree)	if k, v := it.Next(); string(k) != "testkey100" || v != "test100" {		t.Error("Unexpected next result:", k, v)		return	}	sm.AccessMap[3] = storage.AccessCacheAndFetchSeriousError	if k, v := it.Next(); string(k) != "abba1" || v != "song1" {		t.Error("Unexpected next result:", k, v)		return	}	if k, v := it.Next(); k != nil || v != nil {		t.Error("Unexpected next result:", k, v)		return	}	if it.LastError != file.ErrAlreadyInUse {		t.Error("Unexpected last error pointer of iterator")		return	}	delete(sm.AccessMap, 3)	if fmt.Sprint(it) != "HTree Iterator (tree: 1)\n"+		"  path: []\n"+		"  indices: []\n"+		"  next: [] / <nil>\n" {		t.Error("Unexpected tree string representation:", it)		return	}}
 |