-
Notifications
You must be signed in to change notification settings - Fork 25
/
example_statemachine_test.go
83 lines (70 loc) · 1.73 KB
/
example_statemachine_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Copyright 2019 Gregory Petrosyan <[email protected]>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
package rapid_test
import (
"testing"
"pgregory.net/rapid"
)
// Queue implements integer queue with a fixed maximum size.
type Queue struct {
buf []int
in int
out int
}
func NewQueue(n int) *Queue {
return &Queue{
buf: make([]int, n+1),
}
}
// Precondition: Size() > 0.
func (q *Queue) Get() int {
i := q.buf[q.out]
q.out = (q.out + 1) % len(q.buf)
return i
}
// Precondition: Size() < n.
func (q *Queue) Put(i int) {
q.buf[q.in] = i
q.in = (q.in + 1) % len(q.buf)
}
func (q *Queue) Size() int {
return (q.in - q.out) % len(q.buf)
}
func testQueue(t *rapid.T) {
n := rapid.IntRange(1, 1000).Draw(t, "n") // maximum queue size
q := NewQueue(n) // queue being tested
var state []int // model of the queue
t.Repeat(map[string]func(*rapid.T){
"get": func(t *rapid.T) {
if q.Size() == 0 {
t.Skip("queue empty")
}
i := q.Get()
if i != state[0] {
t.Fatalf("got invalid value: %v vs expected %v", i, state[0])
}
state = state[1:]
},
"put": func(t *rapid.T) {
if q.Size() == n {
t.Skip("queue full")
}
i := rapid.Int().Draw(t, "i")
q.Put(i)
state = append(state, i)
},
"": func(t *rapid.T) {
if q.Size() != len(state) {
t.Fatalf("queue size mismatch: %v vs expected %v", q.Size(), len(state))
}
},
})
}
// Rename to TestQueue(t *testing.T) to make an actual (failing) test.
func ExampleT_Repeat_queue() {
var t *testing.T
rapid.Check(t, testQueue)
}