ring_test.go 3.79 KB
Newer Older
Robert Griesemer's avatar
Robert Griesemer committed
1 2 3 4 5 6 7
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ring

import (
8 9
	"fmt"
	"testing"
Robert Griesemer's avatar
Robert Griesemer committed
10 11 12 13 14
)

// For debugging - keep around.
func dump(r *Ring) {
	if r == nil {
15 16
		fmt.Println("empty")
		return
Robert Griesemer's avatar
Robert Griesemer committed
17
	}
18
	i, n := 0, r.Len()
Robert Griesemer's avatar
Robert Griesemer committed
19
	for p := r; i < n; p = p.next {
20 21
		fmt.Printf("%4d: %p = {<- %p | %p ->}\n", i, p, p.prev, p.next)
		i++
Robert Griesemer's avatar
Robert Griesemer committed
22
	}
23
	fmt.Println()
Robert Griesemer's avatar
Robert Griesemer committed
24 25 26 27
}

func verify(t *testing.T, r *Ring, N int, sum int) {
	// Len
28
	n := r.Len()
Robert Griesemer's avatar
Robert Griesemer committed
29
	if n != N {
30
		t.Errorf("r.Len() == %d; expected %d", n, N)
Robert Griesemer's avatar
Robert Griesemer committed
31 32
	}

33
	// iteration
34 35
	n = 0
	s := 0
36
	r.Do(func(p interface{}) {
37
		n++
38
		if p != nil {
39
			s += p.(int)
Robert Griesemer's avatar
Robert Griesemer committed
40
		}
41
	})
Robert Griesemer's avatar
Robert Griesemer committed
42
	if n != N {
43
		t.Errorf("number of forward iterations == %d; expected %d", n, N)
Robert Griesemer's avatar
Robert Griesemer committed
44 45
	}
	if sum >= 0 && s != sum {
46
		t.Errorf("forward ring sum = %d; expected %d", s, sum)
Robert Griesemer's avatar
Robert Griesemer committed
47 48 49
	}

	if r == nil {
50
		return
Robert Griesemer's avatar
Robert Griesemer committed
51 52 53 54
	}

	// connections
	if r.next != nil {
55
		var p *Ring // previous element
Robert Griesemer's avatar
Robert Griesemer committed
56 57
		for q := r; p == nil || q != r; q = q.next {
			if p != nil && p != q.prev {
58
				t.Errorf("prev = %p, expected q.prev = %p\n", p, q.prev)
Robert Griesemer's avatar
Robert Griesemer committed
59
			}
60
			p = q
Robert Griesemer's avatar
Robert Griesemer committed
61 62
		}
		if p != r.prev {
63
			t.Errorf("prev = %p, expected r.prev = %p\n", p, r.prev)
Robert Griesemer's avatar
Robert Griesemer committed
64 65 66 67 68
		}
	}

	// Next, Prev
	if r.Next() != r.next {
69
		t.Errorf("r.Next() != r.next")
Robert Griesemer's avatar
Robert Griesemer committed
70 71
	}
	if r.Prev() != r.prev {
72
		t.Errorf("r.Prev() != r.prev")
Robert Griesemer's avatar
Robert Griesemer committed
73
	}
74

Robert Griesemer's avatar
Robert Griesemer committed
75 76
	// Move
	if r.Move(0) != r {
77
		t.Errorf("r.Move(0) != r")
Robert Griesemer's avatar
Robert Griesemer committed
78 79
	}
	if r.Move(N) != r {
80
		t.Errorf("r.Move(%d) != r", N)
Robert Griesemer's avatar
Robert Griesemer committed
81 82
	}
	if r.Move(-N) != r {
83
		t.Errorf("r.Move(%d) != r", -N)
Robert Griesemer's avatar
Robert Griesemer committed
84 85
	}
	for i := 0; i < 10; i++ {
86 87
		ni := N + i
		mi := ni % N
Robert Griesemer's avatar
Robert Griesemer committed
88
		if r.Move(ni) != r.Move(mi) {
89
			t.Errorf("r.Move(%d) != r.Move(%d)", ni, mi)
Robert Griesemer's avatar
Robert Griesemer committed
90 91
		}
		if r.Move(-ni) != r.Move(-mi) {
92
			t.Errorf("r.Move(%d) != r.Move(%d)", -ni, -mi)
Robert Griesemer's avatar
Robert Griesemer committed
93 94 95 96 97 98
		}
	}
}

func TestCornerCases(t *testing.T) {
	var (
99 100
		r0 *Ring
		r1 Ring
Robert Griesemer's avatar
Robert Griesemer committed
101 102
	)
	// Basics
103 104
	verify(t, r0, 0, 0)
	verify(t, &r1, 1, 0)
Robert Griesemer's avatar
Robert Griesemer committed
105
	// Insert
106 107 108
	r1.Link(r0)
	verify(t, r0, 0, 0)
	verify(t, &r1, 1, 0)
Robert Griesemer's avatar
Robert Griesemer committed
109
	// Insert
110 111 112
	r1.Link(r0)
	verify(t, r0, 0, 0)
	verify(t, &r1, 1, 0)
Robert Griesemer's avatar
Robert Griesemer committed
113
	// Unlink
114 115
	r1.Unlink(0)
	verify(t, &r1, 1, 0)
Robert Griesemer's avatar
Robert Griesemer committed
116 117 118
}

func makeN(n int) *Ring {
119
	r := New(n)
Robert Griesemer's avatar
Robert Griesemer committed
120
	for i := 1; i <= n; i++ {
121 122
		r.Value = i
		r = r.Next()
Robert Griesemer's avatar
Robert Griesemer committed
123
	}
124
	return r
Robert Griesemer's avatar
Robert Griesemer committed
125 126
}

127
func sumN(n int) int { return (n*n + n) / 2 }
Robert Griesemer's avatar
Robert Griesemer committed
128 129 130

func TestNew(t *testing.T) {
	for i := 0; i < 10; i++ {
131 132
		r := New(i)
		verify(t, r, i, -1)
Robert Griesemer's avatar
Robert Griesemer committed
133 134
	}
	for i := 0; i < 10; i++ {
135 136
		r := makeN(i)
		verify(t, r, i, sumN(i))
Robert Griesemer's avatar
Robert Griesemer committed
137 138 139 140
	}
}

func TestLink1(t *testing.T) {
141 142 143 144
	r1a := makeN(1)
	var r1b Ring
	r2a := r1a.Link(&r1b)
	verify(t, r2a, 2, 1)
Robert Griesemer's avatar
Robert Griesemer committed
145
	if r2a != r1a {
146
		t.Errorf("a) 2-element link failed")
Robert Griesemer's avatar
Robert Griesemer committed
147 148
	}

149 150
	r2b := r2a.Link(r2a.Next())
	verify(t, r2b, 2, 1)
Robert Griesemer's avatar
Robert Griesemer committed
151
	if r2b != r2a.Next() {
152
		t.Errorf("b) 2-element link failed")
Robert Griesemer's avatar
Robert Griesemer committed
153 154
	}

155 156 157
	r1c := r2b.Link(r2b)
	verify(t, r1c, 1, 1)
	verify(t, r2b, 1, 0)
Robert Griesemer's avatar
Robert Griesemer committed
158 159 160
}

func TestLink2(t *testing.T) {
161 162 163 164
	var r0 *Ring
	r1a := &Ring{Value: 42}
	r1b := &Ring{Value: 77}
	r10 := makeN(10)
Robert Griesemer's avatar
Robert Griesemer committed
165

166 167
	r1a.Link(r0)
	verify(t, r1a, 1, 42)
Robert Griesemer's avatar
Robert Griesemer committed
168

169 170
	r1a.Link(r1b)
	verify(t, r1a, 2, 42+77)
Robert Griesemer's avatar
Robert Griesemer committed
171

172 173
	r10.Link(r0)
	verify(t, r10, 10, sumN(10))
Robert Griesemer's avatar
Robert Griesemer committed
174

175 176
	r10.Link(r1a)
	verify(t, r10, 12, sumN(10)+42+77)
Robert Griesemer's avatar
Robert Griesemer committed
177 178 179
}

func TestLink3(t *testing.T) {
180 181
	var r Ring
	n := 1
Robert Griesemer's avatar
Robert Griesemer committed
182
	for i := 1; i < 100; i++ {
183 184
		n += i
		verify(t, r.Link(New(i)), n, -1)
Robert Griesemer's avatar
Robert Griesemer committed
185 186 187 188
	}
}

func TestUnlink(t *testing.T) {
189 190
	r10 := makeN(10)
	s10 := r10.Move(6)
Robert Griesemer's avatar
Robert Griesemer committed
191

192
	sum10 := sumN(10)
Robert Griesemer's avatar
Robert Griesemer committed
193

194 195
	verify(t, r10, 10, sum10)
	verify(t, s10, 10, sum10)
Robert Griesemer's avatar
Robert Griesemer committed
196

197 198
	r0 := r10.Unlink(0)
	verify(t, r0, 0, 0)
Robert Griesemer's avatar
Robert Griesemer committed
199

200 201 202
	r1 := r10.Unlink(1)
	verify(t, r1, 1, 2)
	verify(t, r10, 9, sum10-2)
Robert Griesemer's avatar
Robert Griesemer committed
203

204 205 206
	r9 := r10.Unlink(9)
	verify(t, r9, 9, sum10-2)
	verify(t, r10, 9, sum10-2)
Robert Griesemer's avatar
Robert Griesemer committed
207 208 209 210
}

func TestLinkUnlink(t *testing.T) {
	for i := 1; i < 4; i++ {
211
		ri := New(i)
Robert Griesemer's avatar
Robert Griesemer committed
212
		for j := 0; j < i; j++ {
213 214 215 216 217
			rj := ri.Unlink(j)
			verify(t, rj, j, -1)
			verify(t, ri, i-j, -1)
			ri.Link(rj)
			verify(t, ri, i, -1)
Robert Griesemer's avatar
Robert Griesemer committed
218 219 220
		}
	}
}
221 222 223 224 225 226 227 228

// Test that calling Move() on an empty Ring initializes it.
func TestMoveEmptyRing(t *testing.T) {
	var r Ring

	r.Move(1)
	verify(t, &r, 1, 0)
}