-
Notifications
You must be signed in to change notification settings - Fork 0
/
asserts.go
219 lines (190 loc) · 7.23 KB
/
asserts.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// -----------------------------------------------------------------------------
// asserts for more convinient testing
//
// Copyright (C) 2024 Frank Mueller / Oldenburg / Germany / World
// -----------------------------------------------------------------------------
package asserts // import "tideland.dev/go/assert"
import (
"errors"
"regexp"
"strings"
"time"
"golang.org/x/exp/constraints"
)
// It's used to print additional information during testing.
// The location and function name are added automatically.
func Logf(t Tester, format string, args ...interface{}) {
logf(t, format, args...)
}
// Failf is used to fail a test with a formatted message.
func Failf(t Tester, format string, args ...interface{}) {
failf(t, "fail", format, args...)
}
// True checks if the given condition is true.
func True(t Tester, condition bool) {
if !condition {
failf(t, "true", "condition is false")
}
}
// False checks if the given condition is false. It's the opposite of True.
func False(t Tester, condition bool) {
if condition {
failf(t, "false", "condition is true")
}
}
// Nil checks if the given value is nil.
func Nil(t Tester, value any) {
if value != nil {
failf(t, "nil", "value is not nil")
}
}
// NotNil checks if the given value is not nil. It's the opposite of Nil.
func NotNil(t Tester, value any) {
if value == nil {
failf(t, "not nil", "value is nil")
}
}
// Equal checks if the given values are equal.
// It uses the == operator for comparable types and supports time.Duration.
func Equal[T comparable](t Tester, expected, actual T) {
if expected != actual {
failf(t, "equal", "expected is '%v', actual is '%v'", expected, actual)
}
}
// Different checks if the given values are different.
// It uses the != operator for comparable types and supports time.Duration.
func Different[T comparable](t Tester, expected, actual T) {
if expected == actual {
failf(t, "different", "expected is '%v', actual is '%v'", expected, actual)
}
}
// Less checks if the actual value is less than the expected one.
// Supports integers, floats, and time.Duration.
func Less[T constraints.Integer | constraints.Float](t Tester, expected, actual T) {
if actual >= expected {
failf(t, "less", "actual '%v' is more than '%v'", actual, expected)
}
}
// More checks if the actual value is more than the expected one.
// Supports integers, floats, and time.Duration.
func More[T constraints.Integer | constraints.Float](t Tester, expected, actual T) {
if actual <= expected {
failf(t, "more", "actual '%v' is less than expected '%v'", actual, expected)
}
}
// AboutEqual checks if the given values are equal within a delta. Possible
// values are integers, floats, and time.Duration.
func AboutEqual[T constraints.Integer | constraints.Float](t Tester, expected, actual, delta T) {
if expected < actual-delta || expected > actual+delta {
failf(t, "about equal", "expected is '%v' +/- '%v', actual is '%v'", expected, delta, actual)
}
}
// Before checks if the actual time is before the expected time.
func Before(t Tester, expected, actual time.Time) {
if !actual.Before(expected) {
failf(t, "time before", "actual time '%v' is not before expected time '%v'", actual, expected)
}
}
// After checks if the actual time is after the expected time.
func After(t Tester, expected, actual time.Time) {
if !actual.After(expected) {
failf(t, "time after", "actual time '%v' is not after expected time '%v'", actual, expected)
}
}
// Between checks if the actual time is between the expected start and end times.
func Between(t Tester, start, end, actual time.Time) {
if actual.Before(start) || actual.After(end) {
failf(t, "time between", "actual time '%v' is not between start time '%v' and end time '%v'", actual, start, end)
}
}
// Duration calculates the duration of a function execution. If the function returns an error,
// the test fails. The returned duration can be used as expected duration in further tests.
func Duration(t Tester, fn func() error) time.Duration {
start := time.Now()
err := fn()
if err != nil {
failf(t, "measure duration", "function returned an error: '%v'", err)
}
return time.Since(start)
}
// Shorter checks if the actual duration is shorter than the expected duration.
func Shorter(t Tester, expected, actual time.Duration) {
if actual >= expected {
failf(t, "earlier", "actual duration '%v' is not shorter than expected duration '%v'", actual, expected)
}
}
// Longer checks if the actual duration is longer than the expected duration.
func Longer(t Tester, expected, actual time.Duration) {
if actual <= expected {
failf(t, "later", "actual duration '%v' is not longer than expected duration '%v'", actual, expected)
}
}
// DurationAboutEqual checks if the given durations are equal within a delta.
func DurationAboutEqual(t Tester, expected, actual, delta time.Duration) {
if expected < actual-delta || expected > actual+delta {
failf(t, "duration about equal", "expected duration is '%v' +/- '%v', actual duration is '%v'", expected, delta, actual)
}
}
// InRange checks if the given value is within lower and upper bounds. Possible
// values are integers, floats, and time.Duration.
func InRange[T constraints.Integer | constraints.Float](t Tester, expected, lower, upper T) {
if lower > upper {
lower, upper = upper, lower
}
if expected <= lower || expected >= upper {
failf(t, "range", "value is '%v', not in range '%v' to '%v'", expected, lower, upper)
}
}
// OutOfRange checks if the given value is outside lower and upper bounds. It's the
// opposite of InRange.
func OutOfRange[T constraints.Integer | constraints.Float](t Tester, expected, lower, upper T) {
if lower > upper {
lower, upper = upper, lower
}
if expected >= lower && expected <= upper {
failf(t, "out of range", "value is '%v', not out of range '%v' to '%v'", expected, lower, upper)
}
}
// Error checks if the given error is not nil.
func Error(t Tester, err error) {
if err == nil {
failf(t, "error", "error is nil")
}
}
// NoError checks if the given error is nil.
// It's the opposite of Error.
func NoError(t Tester, err error) {
if err != nil {
failf(t, "no error", "expected no error, got '%v'", err)
}
}
// IsError checks if the given error is not nil and of the expected type.
// It uses the errors.Is() function.
func IsError(t Tester, expected, actual error) {
if !errors.Is(expected, actual) {
failf(t, "is error", "expected is '%v', actual is '%v'", expected, actual)
}
}
// ErrorContains checks if the given error is not nil and its message
// contains the expected substring.
func ErrorContains(t Tester, err error, contains string) {
if err == nil {
failf(t, "error contains", "error is nil")
}
if !strings.Contains(err.Error(), contains) {
failf(t, "error contains", "error does not contain '%s'", contains)
}
}
// ErrorMatches checks if the given error is not nil and its message
// matches the expected regular expression.
func ErrorMatches(t Tester, err error, pattern string) {
if err == nil {
failf(t, "error matches", "error is nil")
}
if !regexp.MustCompile(pattern).MatchString(err.Error()) {
failf(t, "error matches", "error does not match '%s'", pattern)
}
}
// -----------------------------------------------------------------------------
// end of file
// -----------------------------------------------------------------------------