260 lines
6.3 KiB
Go
260 lines
6.3 KiB
Go
package gtreap
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
)
|
|
|
|
func stringCompare(a, b interface{}) int {
|
|
return bytes.Compare([]byte(a.(string)), []byte(b.(string)))
|
|
}
|
|
|
|
func TestTreap(t *testing.T) {
|
|
x := NewTreap(stringCompare)
|
|
if x == nil {
|
|
t.Errorf("expected NewTreap to work")
|
|
}
|
|
|
|
tests := []struct {
|
|
op string
|
|
val string
|
|
pri int
|
|
exp string
|
|
}{
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"ups", "a", 100, ""},
|
|
{"get", "a", -1, "a"},
|
|
{"ups", "b", 200, ""},
|
|
{"get", "a", -1, "a"},
|
|
{"get", "b", -1, "b"},
|
|
{"ups", "c", 300, ""},
|
|
{"get", "a", -1, "a"},
|
|
{"get", "b", -1, "b"},
|
|
{"get", "c", -1, "c"},
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"ups", "a", 400, ""},
|
|
{"get", "a", -1, "a"},
|
|
{"get", "b", -1, "b"},
|
|
{"get", "c", -1, "c"},
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"del", "a", -1, ""},
|
|
{"get", "a", -1, "NIL"},
|
|
{"get", "b", -1, "b"},
|
|
{"get", "c", -1, "c"},
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"ups", "a", 10, ""},
|
|
{"get", "a", -1, "a"},
|
|
{"get", "b", -1, "b"},
|
|
{"get", "c", -1, "c"},
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"del", "a", -1, ""},
|
|
{"del", "b", -1, ""},
|
|
{"del", "c", -1, ""},
|
|
{"get", "a", -1, "NIL"},
|
|
{"get", "b", -1, "NIL"},
|
|
{"get", "c", -1, "NIL"},
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"del", "a", -1, ""},
|
|
{"del", "b", -1, ""},
|
|
{"del", "c", -1, ""},
|
|
{"get", "a", -1, "NIL"},
|
|
{"get", "b", -1, "NIL"},
|
|
{"get", "c", -1, "NIL"},
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"ups", "a", 10, ""},
|
|
{"get", "a", -1, "a"},
|
|
{"get", "b", -1, "NIL"},
|
|
{"get", "c", -1, "NIL"},
|
|
{"get", "not-there", -1, "NIL"},
|
|
{"ups", "b", 1000, "b"},
|
|
{"del", "b", -1, ""}, // cover join that is nil
|
|
{"ups", "b", 20, "b"},
|
|
{"ups", "c", 12, "c"},
|
|
{"del", "b", -1, ""}, // cover join second return
|
|
{"ups", "a", 5, "a"}, // cover upsert existing with lower priority
|
|
}
|
|
|
|
for testIdx, test := range tests {
|
|
switch test.op {
|
|
case "get":
|
|
i := x.Get(test.val)
|
|
if i != test.exp && !(i == nil && test.exp == "NIL") {
|
|
t.Errorf("test: %v, on Get, expected: %v, got: %v", testIdx, test.exp, i)
|
|
}
|
|
case "ups":
|
|
x = x.Upsert(test.val, test.pri)
|
|
case "del":
|
|
x = x.Delete(test.val)
|
|
}
|
|
}
|
|
}
|
|
|
|
func load(x *Treap, arr []string) *Treap {
|
|
for i, s := range arr {
|
|
x = x.Upsert(s, i)
|
|
}
|
|
return x
|
|
}
|
|
|
|
func visitExpect(t *testing.T, x *Treap, start string, arr []string) {
|
|
n := 0
|
|
x.VisitAscend(start, func(i Item) bool {
|
|
if i.(string) != arr[n] {
|
|
t.Errorf("expected visit item: %v, saw: %v", arr[n], i)
|
|
}
|
|
n++
|
|
return true
|
|
})
|
|
if n != len(arr) {
|
|
t.Errorf("expected # visit callbacks: %v, saw: %v", len(arr), n)
|
|
}
|
|
}
|
|
|
|
func TestVisit(t *testing.T) {
|
|
x := NewTreap(stringCompare)
|
|
visitExpect(t, x, "a", []string{})
|
|
|
|
x = load(x, []string{"e", "d", "c", "c", "a", "b", "a"})
|
|
|
|
visitX := func() {
|
|
visitExpect(t, x, "a", []string{"a", "b", "c", "d", "e"})
|
|
visitExpect(t, x, "a1", []string{"b", "c", "d", "e"})
|
|
visitExpect(t, x, "b", []string{"b", "c", "d", "e"})
|
|
visitExpect(t, x, "b1", []string{"c", "d", "e"})
|
|
visitExpect(t, x, "c", []string{"c", "d", "e"})
|
|
visitExpect(t, x, "c1", []string{"d", "e"})
|
|
visitExpect(t, x, "d", []string{"d", "e"})
|
|
visitExpect(t, x, "d1", []string{"e"})
|
|
visitExpect(t, x, "e", []string{"e"})
|
|
visitExpect(t, x, "f", []string{})
|
|
}
|
|
visitX()
|
|
|
|
var y *Treap
|
|
y = x.Upsert("f", 1)
|
|
y = y.Delete("a")
|
|
y = y.Upsert("cc", 2)
|
|
y = y.Delete("c")
|
|
|
|
visitExpect(t, y, "a", []string{"b", "cc", "d", "e", "f"})
|
|
visitExpect(t, y, "a1", []string{"b", "cc", "d", "e", "f"})
|
|
visitExpect(t, y, "b", []string{"b", "cc", "d", "e", "f"})
|
|
visitExpect(t, y, "b1", []string{"cc", "d", "e", "f"})
|
|
visitExpect(t, y, "c", []string{"cc", "d", "e", "f"})
|
|
visitExpect(t, y, "c1", []string{"cc", "d", "e", "f"})
|
|
visitExpect(t, y, "d", []string{"d", "e", "f"})
|
|
visitExpect(t, y, "d1", []string{"e", "f"})
|
|
visitExpect(t, y, "e", []string{"e", "f"})
|
|
visitExpect(t, y, "f", []string{"f"})
|
|
visitExpect(t, y, "z", []string{})
|
|
|
|
// an uninitialized treap
|
|
z := NewTreap(stringCompare)
|
|
|
|
// a treap to force left traversal of min
|
|
lmt := NewTreap(stringCompare)
|
|
lmt = lmt.Upsert("b", 2)
|
|
lmt = lmt.Upsert("a", 1)
|
|
|
|
// The x treap should be unchanged.
|
|
visitX()
|
|
|
|
if x.Min() != "a" {
|
|
t.Errorf("expected min of a")
|
|
}
|
|
if x.Max() != "e" {
|
|
t.Errorf("expected max of d")
|
|
}
|
|
if y.Min() != "b" {
|
|
t.Errorf("expected min of b")
|
|
}
|
|
if y.Max() != "f" {
|
|
t.Errorf("expected max of f")
|
|
}
|
|
if z.Min() != nil {
|
|
t.Errorf("expected min of nil")
|
|
}
|
|
if z.Max() != nil {
|
|
t.Error("expected max of nil")
|
|
}
|
|
if lmt.Min() != "a" {
|
|
t.Errorf("expected min of a")
|
|
}
|
|
if lmt.Max() != "b" {
|
|
t.Errorf("expeced max of b")
|
|
}
|
|
}
|
|
|
|
func visitExpectEndAtC(t *testing.T, x *Treap, start string, arr []string) {
|
|
n := 0
|
|
x.VisitAscend(start, func(i Item) bool {
|
|
if stringCompare(i, "c") > 0 {
|
|
return false
|
|
}
|
|
if i.(string) != arr[n] {
|
|
t.Errorf("expected visit item: %v, saw: %v", arr[n], i)
|
|
}
|
|
n++
|
|
return true
|
|
})
|
|
if n != len(arr) {
|
|
t.Errorf("expected # visit callbacks: %v, saw: %v", len(arr), n)
|
|
}
|
|
}
|
|
|
|
func TestVisitEndEarly(t *testing.T) {
|
|
x := NewTreap(stringCompare)
|
|
visitExpectEndAtC(t, x, "a", []string{})
|
|
|
|
x = load(x, []string{"e", "d", "c", "c", "a", "b", "a", "e"})
|
|
|
|
visitX := func() {
|
|
visitExpectEndAtC(t, x, "a", []string{"a", "b", "c"})
|
|
visitExpectEndAtC(t, x, "a1", []string{"b", "c"})
|
|
visitExpectEndAtC(t, x, "b", []string{"b", "c"})
|
|
visitExpectEndAtC(t, x, "b1", []string{"c"})
|
|
visitExpectEndAtC(t, x, "c", []string{"c"})
|
|
visitExpectEndAtC(t, x, "c1", []string{})
|
|
visitExpectEndAtC(t, x, "d", []string{})
|
|
visitExpectEndAtC(t, x, "d1", []string{})
|
|
visitExpectEndAtC(t, x, "e", []string{})
|
|
visitExpectEndAtC(t, x, "f", []string{})
|
|
}
|
|
visitX()
|
|
}
|
|
|
|
func TestPriorityAfterUpsert(t *testing.T) {
|
|
// See https://github.com/steveyen/gtreap/issues/3 found by icexin.
|
|
|
|
var check func(n *node, level int, expectedPriority map[string]int)
|
|
check = func(n *node, level int, expectedPriority map[string]int) {
|
|
if n == nil {
|
|
return
|
|
}
|
|
if n.priority != expectedPriority[n.item.(string)] {
|
|
t.Errorf("wrong priority")
|
|
}
|
|
check(n.left, level+1, expectedPriority)
|
|
check(n.right, level+1, expectedPriority)
|
|
}
|
|
|
|
s := NewTreap(stringCompare)
|
|
s = s.Upsert("m", 20)
|
|
s = s.Upsert("l", 18)
|
|
s = s.Upsert("n", 19)
|
|
|
|
check(s.root, 0, map[string]int{
|
|
"m": 20,
|
|
"l": 18,
|
|
"n": 19,
|
|
})
|
|
|
|
s = s.Upsert("m", 4)
|
|
|
|
check(s.root, 0, map[string]int{
|
|
"m": 20,
|
|
"l": 18,
|
|
"n": 19,
|
|
})
|
|
}
|