-
Notifications
You must be signed in to change notification settings - Fork 28
/
doc.go
340 lines (219 loc) · 9.32 KB
/
doc.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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
// Licensed under the MIT license, see LICENSE file for details.
/*
Package quicktest provides a collection of Go helpers for writing tests.
Quicktest helpers can be easily integrated inside regular Go tests, for
instance:
import qt "github.com/frankban/quicktest"
func TestFoo(t *testing.T) {
t.Run("numbers", func(t *testing.T) {
c := qt.New(t)
numbers, err := somepackage.Numbers()
c.Assert(err, qt.IsNil)
c.Assert(numbers, qt.DeepEquals, []int{42, 47})
})
t.Run("bad wolf error", func(t *testing.T) {
c := qt.New(t)
numbers, err := somepackage.Numbers()
c.Assert(err, qt.ErrorMatches, "bad wolf")
})
t.Run("nil", func(t *testing.T) {
c := qt.New(t)
got := somepackage.MaybeNil()
c.Assert(got, qt.IsNil, qt.Commentf("value: %v", somepackage.Value))
})
}
# Assertions
An assertion looks like this, where qt.Equals could be replaced by any
available checker. If the assertion fails, the underlying Fatal method is
called to describe the error and abort the test.
c := qt.New(t)
c.Assert(someValue, qt.Equals, wantValue)
If you don’t want to abort on failure, use Check instead, which calls Error
instead of Fatal:
c.Check(someValue, qt.Equals, wantValue)
For really short tests, the extra line for instantiating *qt.C can be avoided:
qt.Assert(t, someValue, qt.Equals, wantValue)
qt.Check(t, someValue, qt.Equals, wantValue)
The library provides some base checkers like Equals, DeepEquals, Matches,
ErrorMatches, IsNil and others. More can be added by implementing the Checker
interface. Below, we list the checkers implemented by the package in alphabetical
order.
# All
All returns a Checker that uses the given checker to check elements of slice or
array or the values of a map. It succeeds if all elements pass the check.
On failure it prints the error from the first index that failed.
For example:
c.Assert([]int{3, 5, 8}, qt.All(qt.Not(qt.Equals)), 0)
c.Assert([][]string{{"a", "b"}, {"a", "b"}}, qt.All(qt.DeepEquals), []string{"c", "d"})
See also Any and Contains.
# Any
Any returns a Checker that uses the given checker to check elements of a slice
or array or the values from a map. It succeeds if any element passes the check.
For example:
c.Assert([]int{3,5,7,99}, qt.Any(qt.Equals), 7)
c.Assert([][]string{{"a", "b"}, {"c", "d"}}, qt.Any(qt.DeepEquals), []string{"c", "d"})
See also All and Contains.
# CmpEquals
CmpEquals checks equality of two arbitrary values according to the provided
compare options. DeepEquals is more commonly used when no compare options are
required.
Example calls:
c.Assert(list, qt.CmpEquals(cmpopts.SortSlices), []int{42, 47})
c.Assert(got, qt.CmpEquals(), []int{42, 47}) // Same as qt.DeepEquals.
# CodecEquals
CodecEquals returns a checker that checks for codec value equivalence.
func CodecEquals(
marshal func(interface{}) ([]byte, error),
unmarshal func([]byte, interface{}) error,
opts ...cmp.Option,
) Checker
It expects two arguments: a byte slice or a string containing some
codec-marshaled data, and a Go value.
It uses unmarshal to unmarshal the data into an interface{} value.
It marshals the Go value using marshal, then unmarshals the result into
an interface{} value.
It then checks that the two interface{} values are deep-equal to one another,
using CmpEquals(opts) to perform the check.
See JSONEquals for an example of this in use.
# Contains
Contains checks that a map, slice, array or string contains a value. It's the
same as using Any(Equals), except that it has a special case for strings - if
the first argument is a string, the second argument must also be a string and
strings.Contains will be used.
For example:
c.Assert("hello world", qt.Contains, "world")
c.Assert([]int{3,5,7,99}, qt.Contains, 7)
# ContentEquals
ContentEquals is is like DeepEquals but any slices in the compared values will be sorted before being compared.
For example:
c.Assert([]string{"c", "a", "b"}, qt.ContentEquals, []string{"a", "b", "c"})
# DeepEquals
DeepEquals checks that two arbitrary values are deeply equal.
The comparison is done using the github.com/google/go-cmp/cmp package.
When comparing structs, by default no exported fields are allowed.
If a more sophisticated comparison is required, use CmpEquals (see below).
Example call:
c.Assert(got, qt.DeepEquals, []int{42, 47})
# Equals
Equals checks that two values are equal, as compared with Go's == operator.
For instance:
c.Assert(answer, qt.Equals, 42)
Note that the following will fail:
c.Assert((*sometype)(nil), qt.Equals, nil)
Use the IsNil checker below for this kind of nil check.
# ErrorAs
ErrorAs checks that the error is or wraps a specific error type. If so, it
assigns it to the provided pointer. This is analogous to calling errors.As.
For instance:
// Checking for a specific error type
c.Assert(err, qt.ErrorAs, new(*os.PathError))
// Checking fields on a specific error type
var pathError *os.PathError
if c.Check(err, qt.ErrorAs, &pathError) {
c.Assert(pathError.Path, Equals, "some_path")
}
# ErrorIs
ErrorIs checks that the error is or wraps a specific error value. This is
analogous to calling errors.Is.
For instance:
c.Assert(err, qt.ErrorIs, os.ErrNotExist)
# ErrorMatches
ErrorMatches checks that the provided value is an error whose message matches
the provided regular expression.
For instance:
c.Assert(err, qt.ErrorMatches, `bad wolf .*`)
# HasLen
HasLen checks that the provided value has the given length.
For instance:
c.Assert([]int{42, 47}, qt.HasLen, 2)
c.Assert(myMap, qt.HasLen, 42)
# Implements
Implements checks that the provided value implements an interface. The
interface is specified with a pointer to an interface variable.
For instance:
var rc io.ReadCloser
c.Assert(myReader, qt.Implements, &rc)
# IsFalse
IsFalse checks that the provided value is false.
The value must have a boolean underlying type.
For instance:
c.Assert(false, qt.IsFalse)
c.Assert(IsValid(), qt.IsFalse)
# IsNil
IsNil checks that the provided value is nil.
For instance:
c.Assert(got, qt.IsNil)
As a special case, if the value is nil but implements the
error interface, it is still considered to be non-nil.
This means that IsNil will fail on an error value that happens
to have an underlying nil value, because that's
invariably a mistake. See https://golang.org/doc/faq#nil_error.
So it's just fine to check an error like this:
c.Assert(err, qt.IsNil)
# IsNotNil
IsNotNil is a Checker checking that the provided value is not nil.
IsNotNil is the equivalent of qt.Not(qt.IsNil)
For instance:
c.Assert(got, qt.IsNotNil)
# IsTrue
IsTrue checks that the provided value is true.
The value must have a boolean underlying type.
For instance:
c.Assert(true, qt.IsTrue)
c.Assert(myBoolean(false), qt.IsTrue)
# JSONEquals
JSONEquals checks whether a byte slice or string is JSON-equivalent to a Go
value. See CodecEquals for more information.
It uses DeepEquals to do the comparison. If a more sophisticated comparison is
required, use CodecEquals directly.
For instance:
c.Assert(`{"First": 47.11}`, qt.JSONEquals, &MyStruct{First: 47.11})
# Matches
Matches checks that a string or result of calling the String method
(if the value implements fmt.Stringer) matches the provided regular expression.
For instance:
c.Assert("these are the voyages", qt.Matches, `these are .*`)
c.Assert(net.ParseIP("1.2.3.4"), qt.Matches, `1.*`)
# Not
Not returns a Checker negating the given Checker.
For instance:
c.Assert(got, qt.Not(qt.IsNil))
c.Assert(answer, qt.Not(qt.Equals), 42)
# PanicMatches
PanicMatches checks that the provided function panics with a message matching
the provided regular expression.
For instance:
c.Assert(func() {panic("bad wolf ...")}, qt.PanicMatches, `bad wolf .*`)
# Satisfies
Satisfies checks that the provided value, when used as argument of the provided
predicate function, causes the function to return true. The function must be of
type func(T) bool, having got assignable to T.
For instance:
// Check that an error from os.Open satisfies os.IsNotExist.
c.Assert(err, qt.Satisfies, os.IsNotExist)
// Check that a floating point number is a not-a-number.
c.Assert(f, qt.Satisfies, math.IsNaN)
# Deferred Execution
The testing.TB.Cleanup helper provides the ability to defer the execution of
functions that will be run when the test completes. This is often useful for
creating OS-level resources such as temporary directories (see c.Mkdir).
When targeting Go versions that don't have Cleanup (< 1.14), the same can be
achieved using c.Defer. In this case, to trigger the deferred behavior, calling
c.Done is required. For instance, if you create a *C instance at the top level,
you’ll have to add a defer to trigger the cleanups at the end of the test:
defer c.Done()
However, if you use quicktest to create a subtest, Done will be called
automatically at the end of that subtest. For example:
func TestFoo(t *testing.T) {
c := qt.New(t)
c.Run("subtest", func(c *qt.C) {
c.Setenv("HOME", c.Mkdir())
// Here $HOME is set the path to a newly created directory.
// At the end of the test the directory will be removed
// and HOME set back to its original value.
})
}
The c.Patch, c.Setenv, c.Unsetenv and c.Mkdir helpers use t.Cleanup for
cleaning up resources when available, and fall back to Defer otherwise.
*/
package quicktest