153 lines
3.1 KiB
Go
153 lines
3.1 KiB
Go
// Copyright 2015, Hu Keping. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package rbtree
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDeleteReturnValue(t *testing.T) {
|
|
rbt := New()
|
|
|
|
rbt.Insert(String("go"))
|
|
rbt.Insert(String("lang"))
|
|
|
|
if rbt.Len() != 2 {
|
|
t.Errorf("tree.Len() = %d, expect %d", rbt.Len(), 2)
|
|
}
|
|
|
|
// go should be in the rbtree
|
|
deletedGo := rbt.Delete(String("go"))
|
|
if deletedGo != String("go") {
|
|
t.Errorf("expect %v, got %v", "go", deletedGo)
|
|
}
|
|
|
|
// C should not be in the rbtree
|
|
deletedC := rbt.Delete(String("C"))
|
|
if deletedC != nil {
|
|
t.Errorf("expect %v, got %v", nil, deletedC)
|
|
}
|
|
}
|
|
|
|
func TestMin(t *testing.T) {
|
|
rbt := New()
|
|
|
|
m := 0
|
|
n := 1000
|
|
for m < n {
|
|
rbt.Insert(Int(m))
|
|
m++
|
|
}
|
|
if rbt.Len() != uint(n) {
|
|
t.Errorf("tree.Len() = %d, expect %d", rbt.Len(), n)
|
|
}
|
|
|
|
for m >= 0 {
|
|
rbt.Delete(rbt.Min())
|
|
m--
|
|
}
|
|
|
|
if rbt.Len() != 0 {
|
|
t.Errorf("tree.Len() = %d, expect %d", rbt.Len(), 0)
|
|
}
|
|
}
|
|
|
|
//
|
|
// This test will first add 1000 numbers into a tree and then delete some
|
|
// from it.
|
|
//
|
|
// All the adding and deleting are in goroutine so that the delete action
|
|
// will not always succeed for example `delete(400)` but `add(400)` has not
|
|
// been executed yet.
|
|
//
|
|
// Finally, we'll add back all the deleted nodes to see if there is
|
|
// anything wrong.
|
|
//
|
|
func TestWithGoroutine(t *testing.T) {
|
|
var Cache struct {
|
|
rbt *Rbtree
|
|
locker *sync.Mutex
|
|
}
|
|
|
|
var DeletedArray struct {
|
|
array []Item
|
|
locker *sync.Mutex
|
|
}
|
|
|
|
// Init the rbtree and the locker for later use
|
|
Cache.rbt = New()
|
|
Cache.locker = new(sync.Mutex)
|
|
|
|
// Init the locker for later use
|
|
DeletedArray.locker = new(sync.Mutex)
|
|
|
|
i, m := 0, 0
|
|
j, n := 1000, 1000
|
|
|
|
var expected []Item
|
|
|
|
// This loop will add intergers [m~n) to the rbtree.
|
|
for m < n {
|
|
expected = append(expected, Int(m))
|
|
|
|
go func(x Int) {
|
|
Cache.locker.Lock()
|
|
Cache.rbt.Insert(x)
|
|
Cache.locker.Unlock()
|
|
}(Int(m))
|
|
m++
|
|
}
|
|
|
|
// This loop will try to delete the even integers in [m~n),
|
|
// Be noticed that the delete will not always succeeds since we are
|
|
// in the goroutines.
|
|
// We will record which ones have been removed.
|
|
for i < j {
|
|
if i%2 == 0 {
|
|
go func(x Int) {
|
|
Cache.locker.Lock()
|
|
value := Cache.rbt.Delete(x)
|
|
Cache.locker.Unlock()
|
|
|
|
DeletedArray.locker.Lock()
|
|
DeletedArray.array = append(DeletedArray.array, value)
|
|
DeletedArray.locker.Unlock()
|
|
}(Int(i))
|
|
}
|
|
i++
|
|
}
|
|
|
|
// Let's give a little time to those goroutines to finish their job.
|
|
time.Sleep(time.Second * 1)
|
|
|
|
// Add deleted Items back
|
|
cnt := 0
|
|
DeletedArray.locker.Lock()
|
|
for _, v := range DeletedArray.array {
|
|
if v != nil {
|
|
Cache.locker.Lock()
|
|
Cache.rbt.Insert(v)
|
|
Cache.locker.Unlock()
|
|
cnt++
|
|
}
|
|
}
|
|
DeletedArray.locker.Unlock()
|
|
fmt.Printf("In TestWithGoroutine(), we have deleted [%v] nodes.\n", cnt)
|
|
|
|
var ret []Item
|
|
Cache.rbt.Ascend(Cache.rbt.Min(), func(item Item) bool {
|
|
ret = append(ret, item)
|
|
return true
|
|
})
|
|
|
|
if !reflect.DeepEqual(ret, expected) {
|
|
t.Errorf("expected %v but got %v", expected, ret)
|
|
}
|
|
}
|