New upstream version 1.1.0
Sascha Steinbiss
5 years ago
0 | # Compiled Object files, Static and Dynamic libs (Shared Objects) | |
1 | *.o | |
2 | *.a | |
3 | *.so | |
4 | ||
5 | # Folders | |
6 | _obj | |
7 | _test | |
8 | ||
9 | # Architecture specific extensions/prefixes | |
10 | *.[568vq] | |
11 | [568vq].out | |
12 | ||
13 | *.cgo1.go | |
14 | *.cgo2.c | |
15 | _cgo_defun.c | |
16 | _cgo_gotypes.go | |
17 | _cgo_export.* | |
18 | ||
19 | _testmain.go | |
20 | ||
21 | *.exe | |
22 | *.test | |
23 | *.prof |
0 | language: go | |
1 | ||
2 | sudo: required | |
3 | ||
4 | go: | |
5 | - 1.6.x | |
6 | - 1.7.x | |
7 | - tip | |
8 | ||
9 | env: | |
10 | - GIMME_OS=linux GIMME_ARCH=amd64 | |
11 | - GIMME_OS=darwin GIMME_ARCH=amd64 | |
12 | - GIMME_OS=windows GIMME_ARCH=amd64 | |
13 | ||
14 | install: | |
15 | - go get -d -v ./... | |
16 | ||
17 | script: | |
18 | - go build -v ./... |
0 | MIT License | |
1 | ||
2 | Copyright (c) 2017-2018 Mat Ryer | |
3 | ||
4 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 | of this software and associated documentation files (the "Software"), to deal | |
6 | in the Software without restriction, including without limitation the rights | |
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 | copies of the Software, and to permit persons to whom the Software is | |
9 | furnished to do so, subject to the following conditions: | |
10 | ||
11 | The above copyright notice and this permission notice shall be included in all | |
12 | copies or substantial portions of the Software. | |
13 | ||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
20 | SOFTWARE. |
0 | # is [![GoDoc](https://godoc.org/github.com/matryer/is?status.png)](http://godoc.org/github.com/matryer/is) [![Go Report Card](https://goreportcard.com/badge/github.com/matryer/is)](https://goreportcard.com/report/github.com/matryer/is) [![Build Status](https://travis-ci.org/matryer/is.svg?branch=master)](https://travis-ci.org/matryer/is) | |
1 | Professional lightweight testing mini-framework for Go. | |
2 | ||
3 | * Easy to write and read | |
4 | * [Beautifully simple API](https://godoc.org/github.com/matryer/is) with everything you need: `is.Equal`, `is.True`, `is.NoErr`, and `is.Fail` | |
5 | * Use comments to add descriptions (which show up when tests fail) | |
6 | ||
7 | Failures are very easy to read: | |
8 | ||
9 | ![Examples of failures](https://github.com/matryer/is/raw/master/misc/delicious-failures.png) | |
10 | ||
11 | ### Usage | |
12 | ||
13 | The following code shows a range of useful ways you can use | |
14 | the helper methods: | |
15 | ||
16 | ```go | |
17 | func Test(t *testing.T) { | |
18 | ||
19 | is := is.New(t) | |
20 | ||
21 | signedin, err := isSignedIn(ctx) | |
22 | is.NoErr(err) // isSignedIn error | |
23 | is.Equal(signedin, true) // must be signed in | |
24 | ||
25 | body := readBody(r) | |
26 | is.True(strings.Contains(body, "Hi there")) | |
27 | ||
28 | } | |
29 | ``` | |
30 | ||
31 | ## Color | |
32 | ||
33 | To turn off the colors, run `go test` with the `-nocolor` flag. | |
34 | ||
35 | ``` | |
36 | go test -nocolor | |
37 | ``` |
0 | // Package is provides a lightweight extension to the | |
1 | // standard library's testing capabilities. | |
2 | // | |
3 | // Comments on the assertion lines are used to add | |
4 | // a description. | |
5 | // | |
6 | // The following failing test: | |
7 | // | |
8 | // func Test(t *testing.T) { | |
9 | // is := is.New(t) | |
10 | // a, b := 1, 2 | |
11 | // is.Equal(a, b) // expect to be the same | |
12 | // } | |
13 | // | |
14 | // Will output: | |
15 | // | |
16 | // your_test.go:123: 1 != 2 // expect to be the same | |
17 | // | |
18 | // Usage | |
19 | // | |
20 | // The following code shows a range of useful ways you can use | |
21 | // the helper methods: | |
22 | // | |
23 | // func Test(t *testing.T) { | |
24 | // | |
25 | // // always start tests with this | |
26 | // is := is.New(t) | |
27 | // | |
28 | // signedin, err := isSignedIn(ctx) | |
29 | // is.NoErr(err) // isSignedIn error | |
30 | // is.Equal(signedin, true) // must be signed in | |
31 | // | |
32 | // body := readBody(r) | |
33 | // is.True(strings.Contains(body, "Hi there")) | |
34 | // | |
35 | // } | |
36 | package is | |
37 | ||
38 | import ( | |
39 | "bufio" | |
40 | "bytes" | |
41 | "flag" | |
42 | "fmt" | |
43 | "io" | |
44 | "os" | |
45 | "path/filepath" | |
46 | "reflect" | |
47 | "runtime" | |
48 | "strings" | |
49 | "testing" | |
50 | ) | |
51 | ||
52 | // T reports when failures occur. | |
53 | // testing.T implements this interface. | |
54 | type T interface { | |
55 | // Fail indicates that the test has failed but | |
56 | // allowed execution to continue. | |
57 | // Fail is called in relaxed mode (via NewRelaxed). | |
58 | Fail() | |
59 | // FailNow indicates that the test has failed and | |
60 | // aborts the test. | |
61 | // FailNow is called in strict mode (via New). | |
62 | FailNow() | |
63 | } | |
64 | ||
65 | // I is the test helper harness. | |
66 | type I struct { | |
67 | t T | |
68 | fail func() | |
69 | out io.Writer | |
70 | colorful bool | |
71 | } | |
72 | ||
73 | var isColorful bool | |
74 | ||
75 | func init() { | |
76 | noColor := flag.Bool("nocolor", false, "turns off colors") | |
77 | flag.Parse() | |
78 | isColorful = !*noColor | |
79 | } | |
80 | ||
81 | // New makes a new testing helper using the specified | |
82 | // T through which failures will be reported. | |
83 | // In strict mode, failures call T.FailNow causing the test | |
84 | // to be aborted. See NewRelaxed for alternative behavior. | |
85 | func New(t T) *I { | |
86 | return &I{t, t.FailNow, os.Stdout, isColorful} | |
87 | } | |
88 | ||
89 | // NewRelaxed makes a new testing helper using the specified | |
90 | // T through which failures will be reported. | |
91 | // In relaxed mode, failures call T.Fail allowing | |
92 | // multiple failures per test. | |
93 | func NewRelaxed(t T) *I { | |
94 | return &I{t, t.Fail, os.Stdout, isColorful} | |
95 | } | |
96 | ||
97 | func (is *I) log(args ...interface{}) { | |
98 | s := is.decorate(fmt.Sprint(args...)) | |
99 | fmt.Fprintf(is.out, s) | |
100 | is.fail() | |
101 | } | |
102 | ||
103 | func (is *I) logf(format string, args ...interface{}) { | |
104 | is.log(fmt.Sprintf(format, args...)) | |
105 | } | |
106 | ||
107 | // Fail immediately fails the test. | |
108 | // | |
109 | // func Test(t *testing.T) { | |
110 | // is := is.New(t) | |
111 | // is.Fail() // TODO: write this test | |
112 | // } | |
113 | // | |
114 | // In relaxed mode, execution will continue after a call to | |
115 | // Fail, but that test will still fail. | |
116 | func (is *I) Fail() { | |
117 | is.log("failed") | |
118 | } | |
119 | ||
120 | // True asserts that the expression is true. The expression | |
121 | // code itself will be reported if the assertion fails. | |
122 | // | |
123 | // func Test(t *testing.T) { | |
124 | // is := is.New(t) | |
125 | // val := method() | |
126 | // is.True(val != nil) // val should never be nil | |
127 | // } | |
128 | // | |
129 | // Will output: | |
130 | // | |
131 | // your_test.go:123: not true: val != nil | |
132 | func (is *I) True(expression bool) { | |
133 | if !expression { | |
134 | is.log("not true: $ARGS") | |
135 | } | |
136 | } | |
137 | ||
138 | // Equal asserts that a and b are equal. | |
139 | // | |
140 | // func Test(t *testing.T) { | |
141 | // is := is.New(t) | |
142 | // a := greet("Mat") | |
143 | // is.Equal(a, "Hi Mat") // greeting | |
144 | // } | |
145 | // | |
146 | // Will output: | |
147 | // | |
148 | // your_test.go:123: Hey Mat != Hi Mat // greeting | |
149 | func (is *I) Equal(a, b interface{}) { | |
150 | if !areEqual(a, b) { | |
151 | if isNil(a) || isNil(b) { | |
152 | aLabel := is.valWithType(a) | |
153 | bLabel := is.valWithType(b) | |
154 | if isNil(a) { | |
155 | aLabel = "<nil>" | |
156 | } | |
157 | if isNil(b) { | |
158 | bLabel = "<nil>" | |
159 | } | |
160 | is.logf("%s != %s", aLabel, bLabel) | |
161 | return | |
162 | } | |
163 | if reflect.ValueOf(a).Type() == reflect.ValueOf(b).Type() { | |
164 | is.logf("%v != %v", a, b) | |
165 | return | |
166 | } | |
167 | is.logf("%s != %s", is.valWithType(a), is.valWithType(b)) | |
168 | } | |
169 | } | |
170 | ||
171 | // New is a method wrapper around the New function. | |
172 | // It allows you to write subtests using a fimilar | |
173 | // pattern: | |
174 | // | |
175 | // func Test(t *testing.T) { | |
176 | // is := is.New(t) | |
177 | // t.Run("sub", func(t *testing.T) { | |
178 | // is := is.New(t) | |
179 | // // TODO: test | |
180 | // }) | |
181 | // } | |
182 | func (is *I) New(t *testing.T) *I { | |
183 | return New(t) | |
184 | } | |
185 | ||
186 | // NewRelaxed is a method wrapper aorund the NewRelaxed | |
187 | // method. It allows you to write subtests using a fimilar | |
188 | // pattern: | |
189 | // | |
190 | // func Test(t *testing.T) { | |
191 | // is := is.New(t) | |
192 | // t.Run("sub", func(t *testing.T) { | |
193 | // is := is.New(t) | |
194 | // // TODO: test | |
195 | // }) | |
196 | // } | |
197 | func (is *I) NewRelaxed(t *testing.T) *I { | |
198 | return NewRelaxed(t) | |
199 | } | |
200 | ||
201 | func (is *I) valWithType(v interface{}) string { | |
202 | if is.colorful { | |
203 | return fmt.Sprintf("%[1]s%[3]T(%[2]s%[3]v%[1]s)%[2]s", colorType, colorNormal, v) | |
204 | } | |
205 | return fmt.Sprintf("%[1]T(%[1]v)", v) | |
206 | } | |
207 | ||
208 | // NoErr asserts that err is nil. | |
209 | // | |
210 | // func Test(t *testing.T) { | |
211 | // is := is.New(t) | |
212 | // val, err := getVal() | |
213 | // is.NoErr(err) // getVal error | |
214 | // is.OK(len(val) > 10) // val cannot be short | |
215 | // } | |
216 | // | |
217 | // Will output: | |
218 | // | |
219 | // your_test.go:123: err: not found // getVal error | |
220 | func (is *I) NoErr(err error) { | |
221 | if err != nil { | |
222 | is.logf("err: %s", err.Error()) | |
223 | } | |
224 | } | |
225 | ||
226 | // isNil gets whether the object is nil or not. | |
227 | func isNil(object interface{}) bool { | |
228 | if object == nil { | |
229 | return true | |
230 | } | |
231 | value := reflect.ValueOf(object) | |
232 | kind := value.Kind() | |
233 | if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() { | |
234 | return true | |
235 | } | |
236 | return false | |
237 | } | |
238 | ||
239 | // areEqual gets whether a equals b or not. | |
240 | func areEqual(a, b interface{}) bool { | |
241 | if isNil(a) || isNil(b) { | |
242 | if isNil(a) && !isNil(b) { | |
243 | return false | |
244 | } | |
245 | if !isNil(a) && isNil(b) { | |
246 | return false | |
247 | } | |
248 | return true | |
249 | } | |
250 | if reflect.DeepEqual(a, b) { | |
251 | return true | |
252 | } | |
253 | aValue := reflect.ValueOf(a) | |
254 | bValue := reflect.ValueOf(b) | |
255 | return aValue == bValue | |
256 | } | |
257 | ||
258 | func callerinfo() (path string, line int, ok bool) { | |
259 | for i := 0; ; i++ { | |
260 | _, path, line, ok = runtime.Caller(i) | |
261 | if !ok { | |
262 | return | |
263 | } | |
264 | if strings.HasSuffix(path, "is.go") { | |
265 | continue | |
266 | } | |
267 | return path, line, true | |
268 | } | |
269 | } | |
270 | ||
271 | // loadComment gets the Go comment from the specified line | |
272 | // in the specified file. | |
273 | func loadComment(path string, line int) (string, bool) { | |
274 | f, err := os.Open(path) | |
275 | if err != nil { | |
276 | return "", false | |
277 | } | |
278 | defer f.Close() | |
279 | s := bufio.NewScanner(f) | |
280 | i := 1 | |
281 | for s.Scan() { | |
282 | if i == line { | |
283 | text := s.Text() | |
284 | commentI := strings.Index(text, "//") | |
285 | if commentI == -1 { | |
286 | return "", false // no comment | |
287 | } | |
288 | text = text[commentI+2:] | |
289 | text = strings.TrimSpace(text) | |
290 | return text, true | |
291 | } | |
292 | i++ | |
293 | } | |
294 | return "", false | |
295 | } | |
296 | ||
297 | // loadArguments gets the arguments from the function call | |
298 | // on the specified line of the file. | |
299 | func loadArguments(path string, line int) (string, bool) { | |
300 | f, err := os.Open(path) | |
301 | if err != nil { | |
302 | return "", false | |
303 | } | |
304 | defer f.Close() | |
305 | s := bufio.NewScanner(f) | |
306 | i := 1 | |
307 | for s.Scan() { | |
308 | if i == line { | |
309 | text := s.Text() | |
310 | braceI := strings.Index(text, "(") | |
311 | if braceI == -1 { | |
312 | return "", false | |
313 | } | |
314 | text = text[braceI+1:] | |
315 | cs := bufio.NewScanner(strings.NewReader(text)) | |
316 | cs.Split(bufio.ScanBytes) | |
317 | j := 0 | |
318 | c := 1 | |
319 | for cs.Scan() { | |
320 | switch cs.Text() { | |
321 | case ")": | |
322 | c-- | |
323 | case "(": | |
324 | c++ | |
325 | } | |
326 | if c == 0 { | |
327 | break | |
328 | } | |
329 | j++ | |
330 | } | |
331 | text = text[:j] | |
332 | return text, true | |
333 | } | |
334 | i++ | |
335 | } | |
336 | return "", false | |
337 | } | |
338 | ||
339 | // decorate prefixes the string with the file and line of the call site | |
340 | // and inserts the final newline if needed and indentation tabs for formatting. | |
341 | // this function was copied from the testing framework and modified. | |
342 | func (is *I) decorate(s string) string { | |
343 | path, lineNumber, ok := callerinfo() // decorate + log + public function. | |
344 | file := filepath.Base(path) | |
345 | if ok { | |
346 | // Truncate file name at last file name separator. | |
347 | if index := strings.LastIndex(file, "/"); index >= 0 { | |
348 | file = file[index+1:] | |
349 | } else if index = strings.LastIndex(file, "\\"); index >= 0 { | |
350 | file = file[index+1:] | |
351 | } | |
352 | } else { | |
353 | file = "???" | |
354 | lineNumber = 1 | |
355 | } | |
356 | buf := new(bytes.Buffer) | |
357 | // Every line is indented at least one tab. | |
358 | buf.WriteByte('\t') | |
359 | if is.colorful { | |
360 | buf.WriteString(colorFile) | |
361 | } | |
362 | fmt.Fprintf(buf, "%s:%d: ", file, lineNumber) | |
363 | if is.colorful { | |
364 | buf.WriteString(colorNormal) | |
365 | } | |
366 | lines := strings.Split(s, "\n") | |
367 | if l := len(lines); l > 1 && lines[l-1] == "" { | |
368 | lines = lines[:l-1] | |
369 | } | |
370 | for i, line := range lines { | |
371 | if i > 0 { | |
372 | // Second and subsequent lines are indented an extra tab. | |
373 | buf.WriteString("\n\t\t") | |
374 | } | |
375 | // expand arguments (if $ARGS is present) | |
376 | if strings.Contains(line, "$ARGS") { | |
377 | args, _ := loadArguments(path, lineNumber) | |
378 | line = strings.Replace(line, "$ARGS", args, -1) | |
379 | } | |
380 | buf.WriteString(line) | |
381 | } | |
382 | comment, ok := loadComment(path, lineNumber) | |
383 | if ok { | |
384 | if is.colorful { | |
385 | buf.WriteString(colorComment) | |
386 | } | |
387 | buf.WriteString(" // ") | |
388 | buf.WriteString(comment) | |
389 | if is.colorful { | |
390 | buf.WriteString(colorNormal) | |
391 | } | |
392 | } | |
393 | buf.WriteString("\n") | |
394 | return buf.String() | |
395 | } | |
396 | ||
397 | const ( | |
398 | colorNormal = "\u001b[39m" | |
399 | colorComment = "\u001b[32m" | |
400 | colorFile = "\u001b[90m" | |
401 | colorType = "\u001b[90m" | |
402 | ) |
0 | package is | |
1 | ||
2 | import ( | |
3 | "bytes" | |
4 | "errors" | |
5 | "fmt" | |
6 | "strings" | |
7 | "testing" | |
8 | ) | |
9 | ||
10 | type mockT struct { | |
11 | failed bool | |
12 | } | |
13 | ||
14 | func (m *mockT) FailNow() { | |
15 | m.failed = true | |
16 | } | |
17 | func (m *mockT) Fail() { | |
18 | m.failed = true | |
19 | } | |
20 | ||
21 | var tests = []struct { | |
22 | N string | |
23 | F func(is *I) | |
24 | Fail string | |
25 | }{ | |
26 | // Equal | |
27 | { | |
28 | N: "Equal(1, 1)", | |
29 | F: func(is *I) { | |
30 | is.Equal(1, 1) // 1 doesn't equal 2 | |
31 | }, | |
32 | Fail: ``, | |
33 | }, | |
34 | ||
35 | { | |
36 | N: "Equal(1, 2)", | |
37 | F: func(is *I) { | |
38 | is.Equal(1, 2) // 1 doesn't equal 2 | |
39 | }, | |
40 | Fail: `1 != 2 // 1 doesn't equal 2`, | |
41 | }, | |
42 | { | |
43 | N: "Equal(1, nil)", | |
44 | F: func(is *I) { | |
45 | is.Equal(1, nil) // 1 doesn't equal nil | |
46 | }, | |
47 | Fail: `int(1) != <nil> // 1 doesn't equal nil`, | |
48 | }, | |
49 | { | |
50 | N: "Equal(nil, 2)", | |
51 | F: func(is *I) { | |
52 | is.Equal(nil, 2) // nil doesn't equal 2 | |
53 | }, | |
54 | Fail: `<nil> != int(2) // nil doesn't equal 2`, | |
55 | }, | |
56 | { | |
57 | N: "Equal(false, false)", | |
58 | F: func(is *I) { | |
59 | is.Equal(false, false) // nil doesn't equal 2 | |
60 | }, | |
61 | Fail: ``, | |
62 | }, | |
63 | { | |
64 | N: "Equal(int32(1), int64(1))", | |
65 | F: func(is *I) { | |
66 | is.Equal(int32(1), int64(1)) // nope | |
67 | }, | |
68 | Fail: `int32(1) != int64(1) // nope`, | |
69 | }, | |
70 | { | |
71 | N: "Equal(map1, map2)", | |
72 | F: func(is *I) { | |
73 | m1 := map[string]interface{}{"value": 1} | |
74 | m2 := map[string]interface{}{"value": 2} | |
75 | is.Equal(m1, m2) // maps | |
76 | }, | |
77 | Fail: `map[value:1] != map[value:2] // maps`, | |
78 | }, | |
79 | { | |
80 | N: "Equal(true, map2)", | |
81 | F: func(is *I) { | |
82 | m1 := map[string]interface{}{"value": 1} | |
83 | m2 := map[string]interface{}{"value": 2} | |
84 | is.Equal(m1, m2) // maps | |
85 | }, | |
86 | Fail: `map[value:1] != map[value:2] // maps`, | |
87 | }, | |
88 | { | |
89 | N: "Equal(slice1, slice2)", | |
90 | F: func(is *I) { | |
91 | s1 := []string{"one", "two", "three"} | |
92 | s2 := []string{"one", "two", "three", "four"} | |
93 | is.Equal(s1, s2) // slices | |
94 | }, | |
95 | Fail: `[one two three] != [one two three four] // slices`, | |
96 | }, | |
97 | { | |
98 | N: "Equal(nil, chan)", | |
99 | F: func(is *I) { | |
100 | var a chan string | |
101 | b := make(chan string) | |
102 | is.Equal(a, b) // channels | |
103 | }, | |
104 | Fail: ` // channels`, | |
105 | }, | |
106 | { | |
107 | N: "Equal(nil, slice)", | |
108 | F: func(is *I) { | |
109 | var s1 []string | |
110 | s2 := []string{"one", "two", "three", "four"} | |
111 | is.Equal(s1, s2) // nil slice | |
112 | }, | |
113 | Fail: ` // nil slice`, | |
114 | }, | |
115 | { | |
116 | N: "Equal(nil, nil)", | |
117 | F: func(is *I) { | |
118 | var s1 []string | |
119 | var s2 []string | |
120 | is.Equal(s1, s2) // nil slices | |
121 | }, | |
122 | Fail: ``, | |
123 | }, | |
124 | { | |
125 | N: "Equal(nil, map)", | |
126 | F: func(is *I) { | |
127 | var m1 map[string]string | |
128 | m2 := map[string]string{} | |
129 | is.Equal(m1, m2) // nil map | |
130 | }, | |
131 | Fail: ` // nil map`, | |
132 | }, | |
133 | { | |
134 | N: "Equal(nil, nil)", | |
135 | F: func(is *I) { | |
136 | var m1 map[string]string | |
137 | var m2 map[string]string | |
138 | is.Equal(m1, m2) // nil maps | |
139 | }, | |
140 | Fail: ``, | |
141 | }, | |
142 | ||
143 | // Fail | |
144 | { | |
145 | N: "Fail()", | |
146 | F: func(is *I) { | |
147 | is.Fail() // something went wrong | |
148 | }, | |
149 | Fail: "failed // something went wrong", | |
150 | }, | |
151 | ||
152 | // NoErr | |
153 | { | |
154 | N: "NoErr(nil)", | |
155 | F: func(is *I) { | |
156 | var err error | |
157 | is.NoErr(err) // method shouldn't return error | |
158 | }, | |
159 | Fail: "", | |
160 | }, | |
161 | { | |
162 | N: "NoErr(error)", | |
163 | F: func(is *I) { | |
164 | err := errors.New("nope") | |
165 | is.NoErr(err) // method shouldn't return error | |
166 | }, | |
167 | Fail: "err: nope // method shouldn't return error", | |
168 | }, | |
169 | ||
170 | // OK | |
171 | { | |
172 | N: "True(1 == 2)", | |
173 | F: func(is *I) { | |
174 | is.True(1 == 2) | |
175 | }, | |
176 | Fail: "not true: 1 == 2", | |
177 | }, | |
178 | } | |
179 | ||
180 | func TestFailures(t *testing.T) { | |
181 | colorful, notColorful := true, false | |
182 | testFailures(t, colorful) | |
183 | testFailures(t, notColorful) | |
184 | } | |
185 | ||
186 | func testFailures(t *testing.T, colorful bool) { | |
187 | for _, test := range tests { | |
188 | tt := &mockT{} | |
189 | is := New(tt) | |
190 | var buf bytes.Buffer | |
191 | is.out = &buf | |
192 | is.colorful = colorful | |
193 | test.F(is) | |
194 | if len(test.Fail) == 0 && tt.failed { | |
195 | t.Errorf("shouldn't fail: %s", test.N) | |
196 | continue | |
197 | } | |
198 | if len(test.Fail) > 0 && !tt.failed { | |
199 | t.Errorf("didn't fail: %s", test.N) | |
200 | } | |
201 | if colorful { | |
202 | // if colorful, we won't check the messages | |
203 | // this test is run twice, one without colorful | |
204 | // statements. | |
205 | // see TestFailures | |
206 | fmt.Print(buf.String()) | |
207 | continue | |
208 | } | |
209 | output := buf.String() | |
210 | output = strings.TrimSpace(output) | |
211 | if !strings.HasSuffix(output, test.Fail) { | |
212 | t.Errorf("expected `%s` to end with `%s`", output, test.Fail) | |
213 | } | |
214 | } | |
215 | } | |
216 | ||
217 | func TestRelaxed(t *testing.T) { | |
218 | tt := &mockT{} | |
219 | is := NewRelaxed(tt) | |
220 | var buf bytes.Buffer | |
221 | is.out = &buf | |
222 | is.colorful = false | |
223 | is.NoErr(errors.New("oops")) | |
224 | is.True(1 == 2) | |
225 | actual := buf.String() | |
226 | if !strings.Contains(actual, `oops`) { | |
227 | t.Errorf("missing: oops") | |
228 | } | |
229 | if !strings.Contains(actual, `1 == 2`) { | |
230 | t.Errorf("missing: 1 == 2") | |
231 | } | |
232 | if !tt.failed { | |
233 | t.Errorf("didn't fail") | |
234 | } | |
235 | } | |
236 | ||
237 | func TestLoadComment(t *testing.T) { | |
238 | comment, ok := loadComment("./testdata/example_test.go", 14) | |
239 | if !ok { | |
240 | t.Errorf("loadComment: not ok") | |
241 | } | |
242 | if comment != `this comment will be extracted` { | |
243 | t.Errorf("loadComment: bad comment %s", comment) | |
244 | } | |
245 | } | |
246 | ||
247 | func TestLoadArguments(t *testing.T) { | |
248 | arguments, ok := loadArguments("./testdata/example_test.go", 23) | |
249 | if !ok { | |
250 | t.Errorf("loadArguments: not ok") | |
251 | } | |
252 | if arguments != `a == getB()` { | |
253 | t.Errorf("loadArguments: bad arguments %s", arguments) | |
254 | } | |
255 | ||
256 | arguments, ok = loadArguments("./testdata/example_test.go", 32) | |
257 | if !ok { | |
258 | t.Errorf("loadArguments: not ok") | |
259 | } | |
260 | if arguments != `a == getB()` { | |
261 | t.Errorf("loadArguments: bad arguments %s", arguments) | |
262 | } | |
263 | ||
264 | arguments, _ = loadArguments("./testdata/example_test.go", 28) | |
265 | if len(arguments) > 0 { | |
266 | t.Errorf("should be no arguments: %s", arguments) | |
267 | } | |
268 | } | |
269 | ||
270 | // TestSubtests ensures subtests work as expected. | |
271 | // https://github.com/matryer/is/issues/1 | |
272 | func TestSubtests(t *testing.T) { | |
273 | t.Run("sub1", func(t *testing.T) { | |
274 | is := New(t) | |
275 | is.Equal(1+1, 2) | |
276 | }) | |
277 | } |
Binary diff not shown
0 | package example | |
1 | ||
2 | // CAUTION: DO NOT EDIT | |
3 | // Tests in this project rely on specific lines numbers | |
4 | // throughout this file. | |
5 | ||
6 | import ( | |
7 | "testing" | |
8 | ||
9 | "github.com/matryer/is" | |
10 | ) | |
11 | ||
12 | func TestSomething(t *testing.T) { | |
13 | // this comment will be extracted | |
14 | } | |
15 | ||
16 | func TestSomethingElse(t *testing.T) { | |
17 | is := is.New(t) | |
18 | a, b := 1, 2 | |
19 | getB := func() int { | |
20 | return b | |
21 | } | |
22 | is.True(a == getB()) // should be the same | |
23 | } | |
24 | ||
25 | func TestSomethingElseTpp(t *testing.T) { | |
26 | is := is.New(t) | |
27 | a, b := 1, 2 | |
28 | getB := func() int { | |
29 | return b | |
30 | } | |
31 | is.True(a == getB()) | |
32 | } |