| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 | 
							- package rbtree
 
- import (
 
- 	"fmt"
 
- 	"io/ioutil"
 
- 	"math/rand"
 
- 	"os"
 
- 	"sort"
 
- 	"testing"
 
- 	"github.com/stretchr/testify/assert"
 
- )
 
- // Create a tree storing a set of integers
 
- func testNewIntSet() *RBTree {
 
- 	return NewRBTree(NewAllocator())
 
- }
 
- func testAssert(t *testing.T, b bool, message string) {
 
- 	assert.True(t, b, message)
 
- }
 
- func boolInsert(tree *RBTree, item int) bool {
 
- 	status, _ := tree.Insert(Item{uint32(item), uint32(item)})
 
- 	return status
 
- }
 
- func TestEmpty(t *testing.T) {
 
- 	tree := testNewIntSet()
 
- 	testAssert(t, tree.Len() == 0, "len!=0")
 
- 	testAssert(t, tree.Max().NegativeLimit(), "neglimit")
 
- 	testAssert(t, tree.Min().Limit(), "limit")
 
- 	testAssert(t, tree.FindGE(10).Limit(), "Not empty")
 
- 	testAssert(t, tree.FindLE(10).NegativeLimit(), "Not empty")
 
- 	testAssert(t, tree.Get(10) == nil, "Not empty")
 
- 	testAssert(t, tree.Limit().Equal(tree.Min()), "iter")
 
- }
 
- func TestFindGE(t *testing.T) {
 
- 	tree := testNewIntSet()
 
- 	testAssert(t, boolInsert(tree, 10), "Insert1")
 
- 	testAssert(t, !boolInsert(tree, 10), "Insert2")
 
- 	testAssert(t, tree.Len() == 1, "len==1")
 
- 	testAssert(t, tree.FindGE(10).Item().Key == 10, "FindGE 10")
 
- 	testAssert(t, tree.FindGE(11).Limit(), "FindGE 11")
 
- 	assert.Equal(t, tree.FindGE(9).Item().Key, uint32(10), "FindGE 10")
 
- }
 
- func TestFindLE(t *testing.T) {
 
- 	tree := testNewIntSet()
 
- 	testAssert(t, boolInsert(tree, 10), "insert1")
 
- 	testAssert(t, tree.FindLE(10).Item().Key == 10, "FindLE 10")
 
- 	testAssert(t, tree.FindLE(11).Item().Key == 10, "FindLE 11")
 
- 	testAssert(t, tree.FindLE(9).NegativeLimit(), "FindLE 9")
 
- }
 
- func TestGet(t *testing.T) {
 
- 	tree := testNewIntSet()
 
- 	testAssert(t, boolInsert(tree, 10), "insert1")
 
- 	assert.Equal(t, *tree.Get(10), uint32(10), "Get 10")
 
- 	testAssert(t, tree.Get(9) == nil, "Get 9")
 
- 	testAssert(t, tree.Get(11) == nil, "Get 11")
 
- }
 
- func TestDelete(t *testing.T) {
 
- 	tree := testNewIntSet()
 
- 	testAssert(t, !tree.DeleteWithKey(10), "del")
 
- 	testAssert(t, tree.Len() == 0, "dellen")
 
- 	testAssert(t, boolInsert(tree, 10), "ins")
 
- 	testAssert(t, tree.DeleteWithKey(10), "del")
 
- 	testAssert(t, tree.Len() == 0, "dellen")
 
- 	// delete was deleting after the request if request not found
 
- 	// ensure this does not regress:
 
- 	testAssert(t, boolInsert(tree, 10), "ins")
 
- 	testAssert(t, !tree.DeleteWithKey(9), "del")
 
- 	testAssert(t, tree.Len() == 1, "dellen")
 
- }
 
- func iterToString(i Iterator) string {
 
- 	s := ""
 
- 	for ; !i.Limit(); i = i.Next() {
 
- 		if s != "" {
 
- 			s = s + ","
 
- 		}
 
- 		s = s + fmt.Sprintf("%d", i.Item().Key)
 
- 	}
 
- 	return s
 
- }
 
- func reverseIterToString(i Iterator) string {
 
- 	s := ""
 
- 	for ; !i.NegativeLimit(); i = i.Prev() {
 
- 		if s != "" {
 
- 			s = s + ","
 
- 		}
 
- 		s = s + fmt.Sprintf("%d", i.Item().Key)
 
- 	}
 
- 	return s
 
- }
 
- func TestIterator(t *testing.T) {
 
- 	tree := testNewIntSet()
 
- 	for i := 0; i < 10; i = i + 2 {
 
- 		boolInsert(tree, i)
 
- 	}
 
- 	assert.Equal(t, iterToString(tree.FindGE(3)), "4,6,8")
 
- 	assert.Equal(t, iterToString(tree.FindGE(4)), "4,6,8")
 
- 	assert.Equal(t, iterToString(tree.FindGE(8)), "8")
 
- 	assert.Equal(t, iterToString(tree.FindGE(9)), "")
 
- 	assert.Equal(t, reverseIterToString(tree.FindLE(3)), "2,0")
 
- 	assert.Equal(t, reverseIterToString(tree.FindLE(2)), "2,0")
 
- 	assert.Equal(t, reverseIterToString(tree.FindLE(0)), "0")
 
- }
 
- //
 
- // Randomized tests
 
- //
 
- // oracle stores provides an interface similar to rbtree, but stores
 
- // data in an sorted array
 
- type oracle struct {
 
- 	data []int
 
- }
 
- func newOracle() *oracle {
 
- 	return &oracle{data: make([]int, 0)}
 
- }
 
- func (o *oracle) Len() int {
 
- 	return len(o.data)
 
- }
 
- // interface needed for sorting
 
- func (o *oracle) Less(i, j int) bool {
 
- 	return o.data[i] < o.data[j]
 
- }
 
- func (o *oracle) Swap(i, j int) {
 
- 	e := o.data[j]
 
- 	o.data[j] = o.data[i]
 
- 	o.data[i] = e
 
- }
 
- func (o *oracle) Insert(key int) bool {
 
- 	for _, e := range o.data {
 
- 		if e == key {
 
- 			return false
 
- 		}
 
- 	}
 
- 	n := len(o.data) + 1
 
- 	newData := make([]int, n)
 
- 	copy(newData, o.data)
 
- 	newData[n-1] = key
 
- 	o.data = newData
 
- 	sort.Sort(o)
 
- 	return true
 
- }
 
- func (o *oracle) RandomExistingKey(rand *rand.Rand) int {
 
- 	index := rand.Int31n(int32(len(o.data)))
 
- 	return o.data[index]
 
- }
 
- func (o *oracle) FindGE(t *testing.T, key int) oracleIterator {
 
- 	prev := int(-1)
 
- 	for i, e := range o.data {
 
- 		if e <= prev {
 
- 			t.Fatal("Nonsorted oracle ", e, prev)
 
- 		}
 
- 		if e >= key {
 
- 			return oracleIterator{o: o, index: i}
 
- 		}
 
- 	}
 
- 	return oracleIterator{o: o, index: len(o.data)}
 
- }
 
- func (o *oracle) FindLE(t *testing.T, key int) oracleIterator {
 
- 	iter := o.FindGE(t, key)
 
- 	if !iter.Limit() && o.data[iter.index] == key {
 
- 		return iter
 
- 	}
 
- 	return oracleIterator{o, iter.index - 1}
 
- }
 
- func (o *oracle) Delete(key int) bool {
 
- 	for i, e := range o.data {
 
- 		if e == key {
 
- 			newData := make([]int, len(o.data)-1)
 
- 			copy(newData, o.data[0:i])
 
- 			copy(newData[i:], o.data[i+1:])
 
- 			o.data = newData
 
- 			return true
 
- 		}
 
- 	}
 
- 	return false
 
- }
 
- //
 
- // Test iterator
 
- //
 
- type oracleIterator struct {
 
- 	o     *oracle
 
- 	index int
 
- }
 
- func (oiter oracleIterator) Limit() bool {
 
- 	return oiter.index >= len(oiter.o.data)
 
- }
 
- func (oiter oracleIterator) Min() bool {
 
- 	return oiter.index == 0
 
- }
 
- func (oiter oracleIterator) NegativeLimit() bool {
 
- 	return oiter.index < 0
 
- }
 
- func (oiter oracleIterator) Max() bool {
 
- 	return oiter.index == len(oiter.o.data)-1
 
- }
 
- func (oiter oracleIterator) Item() int {
 
- 	return oiter.o.data[oiter.index]
 
- }
 
- func (oiter oracleIterator) Next() oracleIterator {
 
- 	return oracleIterator{oiter.o, oiter.index + 1}
 
- }
 
- func (oiter oracleIterator) Prev() oracleIterator {
 
- 	return oracleIterator{oiter.o, oiter.index - 1}
 
- }
 
- func compareContents(t *testing.T, oiter oracleIterator, titer Iterator) {
 
- 	oi := oiter
 
- 	ti := titer
 
- 	// Test forward iteration
 
- 	testAssert(t, oi.NegativeLimit() == ti.NegativeLimit(), "rend")
 
- 	if oi.NegativeLimit() {
 
- 		oi = oi.Next()
 
- 		ti = ti.Next()
 
- 	}
 
- 	for !oi.Limit() && !ti.Limit() {
 
- 		// log.Print("Item: ", oi.Item(), ti.Item())
 
- 		if ti.Item().Key != uint32(oi.Item()) {
 
- 			t.Fatal("Wrong item", ti.Item(), oi.Item())
 
- 		}
 
- 		oi = oi.Next()
 
- 		ti = ti.Next()
 
- 	}
 
- 	if !ti.Limit() {
 
- 		t.Fatal("!ti.done", ti.Item())
 
- 	}
 
- 	if !oi.Limit() {
 
- 		t.Fatal("!oi.done", oi.Item())
 
- 	}
 
- 	// Test reverse iteration
 
- 	oi = oiter
 
- 	ti = titer
 
- 	testAssert(t, oi.Limit() == ti.Limit(), "end")
 
- 	if oi.Limit() {
 
- 		oi = oi.Prev()
 
- 		ti = ti.Prev()
 
- 	}
 
- 	for !oi.NegativeLimit() && !ti.NegativeLimit() {
 
- 		if ti.Item().Key != uint32(oi.Item()) {
 
- 			t.Fatal("Wrong item", ti.Item(), oi.Item())
 
- 		}
 
- 		oi = oi.Prev()
 
- 		ti = ti.Prev()
 
- 	}
 
- 	if !ti.NegativeLimit() {
 
- 		t.Fatal("!ti.done", ti.Item())
 
- 	}
 
- 	if !oi.NegativeLimit() {
 
- 		t.Fatal("!oi.done", oi.Item())
 
- 	}
 
- }
 
- func compareContentsFull(t *testing.T, o *oracle, tree *RBTree) {
 
- 	compareContents(t, o.FindGE(t, -1), tree.FindGE(0))
 
- }
 
- func TestRandomized(t *testing.T) {
 
- 	const numKeys = 1000
 
- 	o := newOracle()
 
- 	tree := testNewIntSet()
 
- 	r := rand.New(rand.NewSource(0))
 
- 	for i := 0; i < 10000; i++ {
 
- 		op := r.Int31n(100)
 
- 		if op < 50 {
 
- 			key := r.Int31n(numKeys)
 
- 			o.Insert(int(key))
 
- 			boolInsert(tree, int(key))
 
- 			compareContentsFull(t, o, tree)
 
- 		} else if op < 90 && o.Len() > 0 {
 
- 			key := o.RandomExistingKey(r)
 
- 			o.Delete(key)
 
- 			if !tree.DeleteWithKey(uint32(key)) {
 
- 				t.Fatal("DeleteExisting", key)
 
- 			}
 
- 			compareContentsFull(t, o, tree)
 
- 		} else if op < 95 {
 
- 			key := int(r.Int31n(numKeys))
 
- 			compareContents(t, o.FindGE(t, key), tree.FindGE(uint32(key)))
 
- 		} else {
 
- 			key := int(r.Int31n(numKeys))
 
- 			compareContents(t, o.FindLE(t, key), tree.FindLE(uint32(key)))
 
- 		}
 
- 	}
 
- }
 
- func TestAllocatorFreeZero(t *testing.T) {
 
- 	alloc := NewAllocator()
 
- 	alloc.malloc()
 
- 	assert.Panics(t, func() { alloc.free(0) })
 
- }
 
- func TestCloneShallow(t *testing.T) {
 
- 	alloc1 := NewAllocator()
 
- 	alloc1.malloc()
 
- 	tree := NewRBTree(alloc1)
 
- 	tree.Insert(Item{7, 7})
 
- 	tree.Insert(Item{8, 8})
 
- 	tree.DeleteWithKey(8)
 
- 	assert.Equal(t, alloc1.storage, []node{{}, {}, {color: black, item: Item{7, 7}}, {}})
 
- 	assert.Equal(t, tree.minNode, uint32(2))
 
- 	assert.Equal(t, tree.maxNode, uint32(2))
 
- 	alloc2 := alloc1.Clone()
 
- 	clone := tree.CloneShallow(alloc2)
 
- 	assert.Equal(t, alloc2.storage, []node{{}, {}, {color: black, item: Item{7, 7}}, {}})
 
- 	assert.Equal(t, clone.minNode, uint32(2))
 
- 	assert.Equal(t, clone.maxNode, uint32(2))
 
- 	assert.Equal(t, alloc2.Size(), 4)
 
- 	tree.Insert(Item{10, 10})
 
- 	alloc3 := alloc1.Clone()
 
- 	clone = tree.CloneShallow(alloc3)
 
- 	assert.Equal(t, alloc3.storage, []node{
 
- 		{}, {},
 
- 		{right: 3, color: black, item: Item{7, 7}},
 
- 		{parent: 2, color: red, item: Item{10, 10}}})
 
- 	assert.Equal(t, clone.minNode, uint32(2))
 
- 	assert.Equal(t, clone.maxNode, uint32(3))
 
- 	assert.Equal(t, alloc3.Size(), 4)
 
- 	assert.Equal(t, alloc2.Size(), 4)
 
- }
 
- func TestCloneDeep(t *testing.T) {
 
- 	alloc1 := NewAllocator()
 
- 	alloc1.malloc()
 
- 	tree := NewRBTree(alloc1)
 
- 	tree.Insert(Item{7, 7})
 
- 	assert.Equal(t, alloc1.storage, []node{{}, {}, {color: black, item: Item{7, 7}}})
 
- 	assert.Equal(t, tree.minNode, uint32(2))
 
- 	assert.Equal(t, tree.maxNode, uint32(2))
 
- 	alloc2 := NewAllocator()
 
- 	clone := tree.CloneDeep(alloc2)
 
- 	assert.Equal(t, alloc2.storage, []node{{}, {color: black, item: Item{7, 7}}})
 
- 	assert.Equal(t, clone.minNode, uint32(1))
 
- 	assert.Equal(t, clone.maxNode, uint32(1))
 
- 	assert.Equal(t, alloc2.Size(), 2)
 
- 	tree.Insert(Item{10, 10})
 
- 	alloc2 = NewAllocator()
 
- 	clone = tree.CloneDeep(alloc2)
 
- 	assert.Equal(t, alloc2.storage, []node{
 
- 		{},
 
- 		{right: 2, color: black, item: Item{7, 7}},
 
- 		{parent: 1, color: red, item: Item{10, 10}}})
 
- 	assert.Equal(t, clone.minNode, uint32(1))
 
- 	assert.Equal(t, clone.maxNode, uint32(2))
 
- 	assert.Equal(t, alloc2.Size(), 3)
 
- }
 
- func TestErase(t *testing.T) {
 
- 	alloc := NewAllocator()
 
- 	tree := NewRBTree(alloc)
 
- 	for i := 0; i < 10; i++ {
 
- 		tree.Insert(Item{uint32(i), uint32(i)})
 
- 	}
 
- 	assert.Equal(t, alloc.Used(), 11)
 
- 	tree.Erase()
 
- 	assert.Equal(t, alloc.Used(), 1)
 
- 	assert.Equal(t, alloc.Size(), 11)
 
- }
 
- func TestAllocatorHibernateBoot(t *testing.T) {
 
- 	alloc := NewAllocator()
 
- 	for i := 0; i < 10000; i++ {
 
- 		n := alloc.malloc()
 
- 		alloc.storage[n].item.Key = uint32(i)
 
- 		alloc.storage[n].item.Value = uint32(i)
 
- 		alloc.storage[n].left = uint32(i)
 
- 		alloc.storage[n].right = uint32(i)
 
- 		alloc.storage[n].parent = uint32(i)
 
- 		alloc.storage[n].color = i%2 == 0
 
- 	}
 
- 	for i := 0; i < 10000; i++ {
 
- 		alloc.gaps[uint32(i)] = true // makes no sense, only to test
 
- 	}
 
- 	alloc.Hibernate()
 
- 	assert.PanicsWithValue(t, "cannot hibernate an already hibernated Allocator", alloc.Hibernate)
 
- 	assert.Nil(t, alloc.storage)
 
- 	assert.Nil(t, alloc.gaps)
 
- 	assert.Equal(t, alloc.Size(), 0)
 
- 	assert.Equal(t, alloc.hibernatedStorageLen, 10001)
 
- 	assert.Equal(t, alloc.hibernatedGapsLen, 10000)
 
- 	assert.PanicsWithValue(t, "hibernated allocators cannot be used", func() { alloc.Used() })
 
- 	assert.PanicsWithValue(t, "hibernated allocators cannot be used", func() { alloc.malloc() })
 
- 	assert.PanicsWithValue(t, "hibernated allocators cannot be used", func() { alloc.free(0) })
 
- 	assert.PanicsWithValue(t, "cannot clone a hibernated allocator", func() { alloc.Clone() })
 
- 	alloc.Boot()
 
- 	assert.Equal(t, alloc.hibernatedStorageLen, 0)
 
- 	assert.Equal(t, alloc.hibernatedGapsLen, 0)
 
- 	for n := 1; n <= 10000; n++ {
 
- 		assert.Equal(t, alloc.storage[n].item.Key, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].item.Value, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].left, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].right, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].parent, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].color, (n-1)%2 == 0)
 
- 		assert.True(t, alloc.gaps[uint32(n-1)])
 
- 	}
 
- }
 
- func TestAllocatorHibernateBootEmpty(t *testing.T) {
 
- 	alloc := NewAllocator()
 
- 	alloc.Hibernate()
 
- 	alloc.Boot()
 
- 	assert.NotNil(t, alloc.gaps)
 
- 	assert.Equal(t, alloc.Size(), 0)
 
- 	assert.Equal(t, alloc.Used(), 0)
 
- }
 
- func TestAllocatorHibernateBootThreshold(t *testing.T) {
 
- 	alloc := NewAllocator()
 
- 	alloc.malloc()
 
- 	alloc.HibernationThreshold = 3
 
- 	assert.Equal(t, 3, alloc.Clone().HibernationThreshold)
 
- 	alloc.Hibernate()
 
- 	assert.Equal(t, alloc.hibernatedStorageLen, 0)
 
- 	alloc.Boot()
 
- 	alloc.malloc()
 
- 	alloc.Hibernate()
 
- 	assert.Equal(t, alloc.hibernatedGapsLen, 0)
 
- 	assert.Equal(t, alloc.hibernatedStorageLen, 3)
 
- 	alloc.Boot()
 
- 	assert.Equal(t, alloc.Size(), 3)
 
- 	assert.Equal(t, alloc.Used(), 3)
 
- 	assert.NotNil(t, alloc.gaps)
 
- }
 
- func TestAllocatorSerializeDeserialize(t *testing.T) {
 
- 	alloc := NewAllocator()
 
- 	for i := 0; i < 10000; i++ {
 
- 		n := alloc.malloc()
 
- 		alloc.storage[n].item.Key = uint32(i)
 
- 		alloc.storage[n].item.Value = uint32(i)
 
- 		alloc.storage[n].left = uint32(i)
 
- 		alloc.storage[n].right = uint32(i)
 
- 		alloc.storage[n].parent = uint32(i)
 
- 		alloc.storage[n].color = i%2 == 0
 
- 	}
 
- 	for i := 0; i < 10000; i++ {
 
- 		alloc.gaps[uint32(i)] = true // makes no sense, only to test
 
- 	}
 
- 	assert.PanicsWithValue(t, "serialization requires the hibernated state",
 
- 		func() { alloc.Serialize("...") })
 
- 	assert.PanicsWithValue(t, "deserialization requires the hibernated state",
 
- 		func() { alloc.Deserialize("...") })
 
- 	alloc.Hibernate()
 
- 	file, err := ioutil.TempFile("", "")
 
- 	assert.Nil(t, err)
 
- 	name := file.Name()
 
- 	defer os.Remove(name)
 
- 	assert.Nil(t, file.Close())
 
- 	assert.NotNil(t, alloc.Serialize("/tmp/xxx/yyy"))
 
- 	assert.Nil(t, alloc.Serialize(name))
 
- 	assert.Nil(t, alloc.storage)
 
- 	assert.Nil(t, alloc.gaps)
 
- 	for _, d := range alloc.hibernatedData {
 
- 		assert.Nil(t, d)
 
- 	}
 
- 	assert.Equal(t, alloc.hibernatedStorageLen, 10001)
 
- 	assert.Equal(t, alloc.hibernatedGapsLen, 10000)
 
- 	assert.PanicsWithValue(t, "cannot boot a serialized Allocator", alloc.Boot)
 
- 	assert.NotNil(t, alloc.Deserialize("/tmp/xxx/yyy"))
 
- 	assert.Nil(t, alloc.Deserialize(name))
 
- 	for _, d := range alloc.hibernatedData {
 
- 		assert.True(t, len(d) > 0)
 
- 	}
 
- 	alloc.Boot()
 
- 	assert.Equal(t, alloc.hibernatedStorageLen, 0)
 
- 	assert.Equal(t, alloc.hibernatedGapsLen, 0)
 
- 	for _, d := range alloc.hibernatedData {
 
- 		assert.Nil(t, d)
 
- 	}
 
- 	for n := 1; n <= 10000; n++ {
 
- 		assert.Equal(t, alloc.storage[n].item.Key, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].item.Value, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].left, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].right, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].parent, uint32(n-1))
 
- 		assert.Equal(t, alloc.storage[n].color, (n-1)%2 == 0)
 
- 		assert.True(t, alloc.gaps[uint32(n-1)])
 
- 	}
 
- 	alloc.Hibernate()
 
- 	assert.Nil(t, os.Truncate(name, 100))
 
- 	assert.NotNil(t, alloc.Deserialize(name))
 
- 	assert.Nil(t, os.Truncate(name, 4))
 
- 	assert.NotNil(t, alloc.Deserialize(name))
 
- 	assert.Nil(t, os.Truncate(name, 0))
 
- 	assert.NotNil(t, alloc.Deserialize(name))
 
- }
 
 
  |