| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 | package rbtreeimport (	"fmt"	"io/ioutil"	"math/rand"	"os"	"sort"	"testing"	"github.com/stretchr/testify/assert")// Create a tree storing a set of integersfunc 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 arraytype 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 sortingfunc (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))}
 |