-
Notifications
You must be signed in to change notification settings - Fork 0
/
contract_test.go
137 lines (110 loc) · 3 KB
/
contract_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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package contract
import (
"fmt"
"testing"
)
//
// Package Types
//
type state struct {
name string
value int
obj interface{}
}
//
// Package Functions
//
func check(t *testing.T, want Exception) {
got := recover()
if got != want {
t.Errorf("expected [%v] but got [%v]", want, got)
}
}
func testPanic(t *testing.T, exec func(bool, string), want Exception, msg string) {
defer check(t, want)
obj := new(interface{})
obj = nil
exec(obj != nil, msg)
t.Errorf("%v panic should have been triggered", want)
}
func testNoPanic(t *testing.T, exec func(bool, string), msg string) {
defer checkNoPanic(t)
obj := new(interface{})
exec(obj != nil, msg)
}
func checkNoPanic(t *testing.T) {
got := recover()
if got != nil {
t.Errorf("expected no panic but got [%v]", got)
}
}
func checkInvariantPanic(t *testing.T, s *state, want Exception) {
defer check(t, want)
s.invariant()
}
//
// Tests
//
func TestContractSucceeds(t *testing.T) {
tests := []struct {
exec func(bool, string)
msg string
}{
{Requires, "object must be provided"},
{Ensures, "object must have been created"},
{Assert, "object must have been set"},
{Invariant, "object must have been set"},
}
for _, test := range tests {
testNoPanic(t, test.exec, test.msg)
}
}
func TestContractFails(t *testing.T) {
tests := []struct {
exec func(bool, string)
want Exception
msg string
}{
{Requires, create(requires, fmt.Sprintf(requiresMsg, "object must be provided")), "object must be provided"},
{Ensures, create(ensures, fmt.Sprintf(ensuresMsg, "object must have been created")), "object must have been created"},
{Assert, create(assert, fmt.Sprintf(assertMsg, "object must have been set")), "object must have been set"},
{Invariant, create(invariant, fmt.Sprintf(invariantMsg, "object must have been set")), "object must have been set"},
{func(cond bool, msg string) { Fail(msg) }, create(fail, fmt.Sprintf(failMsg, "path must not have been executed")), "path must not have been executed"},
}
for _, test := range tests {
testPanic(t, test.exec, test.want, test.msg)
}
}
func TestInvariantSucceeds(t *testing.T) {
defer checkNoPanic(t)
tests := []*state{
&state{name: "name1", value: 3, obj: "a"},
&state{name: "name2", value: 3, obj: new(interface{})},
}
for _, test := range tests {
test.invariant()
}
}
func TestInvariantFails(t *testing.T) {
tests := []struct {
s *state
msg string
}{
{nil, "state must be provided"},
{&state{name: "", value: 3, obj: "a"}, "name must be set"},
{&state{name: "name1", value: -1, obj: new(interface{})}, "value must be positive"},
{&state{name: "name2", value: 1, obj: nil}, "obj must be set"},
}
for _, test := range tests {
checkInvariantPanic(t, test.s, create(invariant, fmt.Sprintf(invariantMsg, test.msg)))
}
}
/*
Invariant
*/
func (s *state) invariant() {
Invariant(s != nil, "state must be provided")
Invariant(!IsEmpty(s.name), "name must be set")
Invariant(s.value >= 0, "value must be positive")
Invariant(s.obj != nil, "obj must be set")
}