1// These tests verify the inner workings of the helper methods associated
2// with check.T.
3
4package check_test
5
6import (
7	"gopkg.in/check.v1"
8	"os"
9	"reflect"
10	"runtime"
11	"sync"
12)
13
14var helpersS = check.Suite(&HelpersS{})
15
16type HelpersS struct{}
17
18func (s *HelpersS) TestCountSuite(c *check.C) {
19	suitesRun += 1
20}
21
22// -----------------------------------------------------------------------
23// Fake checker and bug info to verify the behavior of Assert() and Check().
24
25type MyChecker struct {
26	info   *check.CheckerInfo
27	params []interface{}
28	names  []string
29	result bool
30	error  string
31}
32
33func (checker *MyChecker) Info() *check.CheckerInfo {
34	if checker.info == nil {
35		return &check.CheckerInfo{Name: "MyChecker", Params: []string{"myobtained", "myexpected"}}
36	}
37	return checker.info
38}
39
40func (checker *MyChecker) Check(params []interface{}, names []string) (bool, string) {
41	rparams := checker.params
42	rnames := checker.names
43	checker.params = append([]interface{}{}, params...)
44	checker.names = append([]string{}, names...)
45	if rparams != nil {
46		copy(params, rparams)
47	}
48	if rnames != nil {
49		copy(names, rnames)
50	}
51	return checker.result, checker.error
52}
53
54type myCommentType string
55
56func (c myCommentType) CheckCommentString() string {
57	return string(c)
58}
59
60func myComment(s string) myCommentType {
61	return myCommentType(s)
62}
63
64// -----------------------------------------------------------------------
65// Ensure a real checker actually works fine.
66
67func (s *HelpersS) TestCheckerInterface(c *check.C) {
68	testHelperSuccess(c, "Check(1, Equals, 1)", true, func() interface{} {
69		return c.Check(1, check.Equals, 1)
70	})
71}
72
73// -----------------------------------------------------------------------
74// Tests for Check(), mostly the same as for Assert() following these.
75
76func (s *HelpersS) TestCheckSucceedWithExpected(c *check.C) {
77	checker := &MyChecker{result: true}
78	testHelperSuccess(c, "Check(1, checker, 2)", true, func() interface{} {
79		return c.Check(1, checker, 2)
80	})
81	if !reflect.DeepEqual(checker.params, []interface{}{1, 2}) {
82		c.Fatalf("Bad params for check: %#v", checker.params)
83	}
84}
85
86func (s *HelpersS) TestCheckSucceedWithoutExpected(c *check.C) {
87	checker := &MyChecker{result: true, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
88	testHelperSuccess(c, "Check(1, checker)", true, func() interface{} {
89		return c.Check(1, checker)
90	})
91	if !reflect.DeepEqual(checker.params, []interface{}{1}) {
92		c.Fatalf("Bad params for check: %#v", checker.params)
93	}
94}
95
96func (s *HelpersS) TestCheckFailWithExpected(c *check.C) {
97	checker := &MyChecker{result: false}
98	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
99		"    return c\\.Check\\(1, checker, 2\\)\n" +
100		"\\.+ myobtained int = 1\n" +
101		"\\.+ myexpected int = 2\n\n"
102	testHelperFailure(c, "Check(1, checker, 2)", false, false, log,
103		func() interface{} {
104			return c.Check(1, checker, 2)
105		})
106}
107
108func (s *HelpersS) TestCheckFailWithExpectedAndComment(c *check.C) {
109	checker := &MyChecker{result: false}
110	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
111		"    return c\\.Check\\(1, checker, 2, myComment\\(\"Hello world!\"\\)\\)\n" +
112		"\\.+ myobtained int = 1\n" +
113		"\\.+ myexpected int = 2\n" +
114		"\\.+ Hello world!\n\n"
115	testHelperFailure(c, "Check(1, checker, 2, msg)", false, false, log,
116		func() interface{} {
117			return c.Check(1, checker, 2, myComment("Hello world!"))
118		})
119}
120
121func (s *HelpersS) TestCheckFailWithExpectedAndStaticComment(c *check.C) {
122	checker := &MyChecker{result: false}
123	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
124		"    // Nice leading comment\\.\n" +
125		"    return c\\.Check\\(1, checker, 2\\) // Hello there\n" +
126		"\\.+ myobtained int = 1\n" +
127		"\\.+ myexpected int = 2\n\n"
128	testHelperFailure(c, "Check(1, checker, 2, msg)", false, false, log,
129		func() interface{} {
130			// Nice leading comment.
131			return c.Check(1, checker, 2) // Hello there
132		})
133}
134
135func (s *HelpersS) TestCheckFailWithoutExpected(c *check.C) {
136	checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
137	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
138		"    return c\\.Check\\(1, checker\\)\n" +
139		"\\.+ myvalue int = 1\n\n"
140	testHelperFailure(c, "Check(1, checker)", false, false, log,
141		func() interface{} {
142			return c.Check(1, checker)
143		})
144}
145
146func (s *HelpersS) TestCheckFailWithoutExpectedAndMessage(c *check.C) {
147	checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
148	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
149		"    return c\\.Check\\(1, checker, myComment\\(\"Hello world!\"\\)\\)\n" +
150		"\\.+ myvalue int = 1\n" +
151		"\\.+ Hello world!\n\n"
152	testHelperFailure(c, "Check(1, checker, msg)", false, false, log,
153		func() interface{} {
154			return c.Check(1, checker, myComment("Hello world!"))
155		})
156}
157
158func (s *HelpersS) TestCheckWithMissingExpected(c *check.C) {
159	checker := &MyChecker{result: true}
160	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
161		"    return c\\.Check\\(1, checker\\)\n" +
162		"\\.+ Check\\(myobtained, MyChecker, myexpected\\):\n" +
163		"\\.+ Wrong number of parameters for MyChecker: " +
164		"want 3, got 2\n\n"
165	testHelperFailure(c, "Check(1, checker, !?)", false, false, log,
166		func() interface{} {
167			return c.Check(1, checker)
168		})
169}
170
171func (s *HelpersS) TestCheckWithTooManyExpected(c *check.C) {
172	checker := &MyChecker{result: true}
173	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
174		"    return c\\.Check\\(1, checker, 2, 3\\)\n" +
175		"\\.+ Check\\(myobtained, MyChecker, myexpected\\):\n" +
176		"\\.+ Wrong number of parameters for MyChecker: " +
177		"want 3, got 4\n\n"
178	testHelperFailure(c, "Check(1, checker, 2, 3)", false, false, log,
179		func() interface{} {
180			return c.Check(1, checker, 2, 3)
181		})
182}
183
184func (s *HelpersS) TestCheckWithError(c *check.C) {
185	checker := &MyChecker{result: false, error: "Some not so cool data provided!"}
186	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
187		"    return c\\.Check\\(1, checker, 2\\)\n" +
188		"\\.+ myobtained int = 1\n" +
189		"\\.+ myexpected int = 2\n" +
190		"\\.+ Some not so cool data provided!\n\n"
191	testHelperFailure(c, "Check(1, checker, 2)", false, false, log,
192		func() interface{} {
193			return c.Check(1, checker, 2)
194		})
195}
196
197func (s *HelpersS) TestCheckWithNilChecker(c *check.C) {
198	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
199		"    return c\\.Check\\(1, nil\\)\n" +
200		"\\.+ Check\\(obtained, nil!\\?, \\.\\.\\.\\):\n" +
201		"\\.+ Oops\\.\\. you've provided a nil checker!\n\n"
202	testHelperFailure(c, "Check(obtained, nil)", false, false, log,
203		func() interface{} {
204			return c.Check(1, nil)
205		})
206}
207
208func (s *HelpersS) TestCheckWithParamsAndNamesMutation(c *check.C) {
209	checker := &MyChecker{result: false, params: []interface{}{3, 4}, names: []string{"newobtained", "newexpected"}}
210	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
211		"    return c\\.Check\\(1, checker, 2\\)\n" +
212		"\\.+ newobtained int = 3\n" +
213		"\\.+ newexpected int = 4\n\n"
214	testHelperFailure(c, "Check(1, checker, 2) with mutation", false, false, log,
215		func() interface{} {
216			return c.Check(1, checker, 2)
217		})
218}
219
220// -----------------------------------------------------------------------
221// Tests for Assert(), mostly the same as for Check() above.
222
223func (s *HelpersS) TestAssertSucceedWithExpected(c *check.C) {
224	checker := &MyChecker{result: true}
225	testHelperSuccess(c, "Assert(1, checker, 2)", nil, func() interface{} {
226		c.Assert(1, checker, 2)
227		return nil
228	})
229	if !reflect.DeepEqual(checker.params, []interface{}{1, 2}) {
230		c.Fatalf("Bad params for check: %#v", checker.params)
231	}
232}
233
234func (s *HelpersS) TestAssertSucceedWithoutExpected(c *check.C) {
235	checker := &MyChecker{result: true, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
236	testHelperSuccess(c, "Assert(1, checker)", nil, func() interface{} {
237		c.Assert(1, checker)
238		return nil
239	})
240	if !reflect.DeepEqual(checker.params, []interface{}{1}) {
241		c.Fatalf("Bad params for check: %#v", checker.params)
242	}
243}
244
245func (s *HelpersS) TestAssertFailWithExpected(c *check.C) {
246	checker := &MyChecker{result: false}
247	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
248		"    c\\.Assert\\(1, checker, 2\\)\n" +
249		"\\.+ myobtained int = 1\n" +
250		"\\.+ myexpected int = 2\n\n"
251	testHelperFailure(c, "Assert(1, checker, 2)", nil, true, log,
252		func() interface{} {
253			c.Assert(1, checker, 2)
254			return nil
255		})
256}
257
258func (s *HelpersS) TestAssertFailWithExpectedAndMessage(c *check.C) {
259	checker := &MyChecker{result: false}
260	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
261		"    c\\.Assert\\(1, checker, 2, myComment\\(\"Hello world!\"\\)\\)\n" +
262		"\\.+ myobtained int = 1\n" +
263		"\\.+ myexpected int = 2\n" +
264		"\\.+ Hello world!\n\n"
265	testHelperFailure(c, "Assert(1, checker, 2, msg)", nil, true, log,
266		func() interface{} {
267			c.Assert(1, checker, 2, myComment("Hello world!"))
268			return nil
269		})
270}
271
272func (s *HelpersS) TestAssertFailWithoutExpected(c *check.C) {
273	checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
274	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
275		"    c\\.Assert\\(1, checker\\)\n" +
276		"\\.+ myvalue int = 1\n\n"
277	testHelperFailure(c, "Assert(1, checker)", nil, true, log,
278		func() interface{} {
279			c.Assert(1, checker)
280			return nil
281		})
282}
283
284func (s *HelpersS) TestAssertFailWithoutExpectedAndMessage(c *check.C) {
285	checker := &MyChecker{result: false, info: &check.CheckerInfo{Params: []string{"myvalue"}}}
286	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
287		"    c\\.Assert\\(1, checker, myComment\\(\"Hello world!\"\\)\\)\n" +
288		"\\.+ myvalue int = 1\n" +
289		"\\.+ Hello world!\n\n"
290	testHelperFailure(c, "Assert(1, checker, msg)", nil, true, log,
291		func() interface{} {
292			c.Assert(1, checker, myComment("Hello world!"))
293			return nil
294		})
295}
296
297func (s *HelpersS) TestAssertWithMissingExpected(c *check.C) {
298	checker := &MyChecker{result: true}
299	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
300		"    c\\.Assert\\(1, checker\\)\n" +
301		"\\.+ Assert\\(myobtained, MyChecker, myexpected\\):\n" +
302		"\\.+ Wrong number of parameters for MyChecker: " +
303		"want 3, got 2\n\n"
304	testHelperFailure(c, "Assert(1, checker, !?)", nil, true, log,
305		func() interface{} {
306			c.Assert(1, checker)
307			return nil
308		})
309}
310
311func (s *HelpersS) TestAssertWithError(c *check.C) {
312	checker := &MyChecker{result: false, error: "Some not so cool data provided!"}
313	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
314		"    c\\.Assert\\(1, checker, 2\\)\n" +
315		"\\.+ myobtained int = 1\n" +
316		"\\.+ myexpected int = 2\n" +
317		"\\.+ Some not so cool data provided!\n\n"
318	testHelperFailure(c, "Assert(1, checker, 2)", nil, true, log,
319		func() interface{} {
320			c.Assert(1, checker, 2)
321			return nil
322		})
323}
324
325func (s *HelpersS) TestAssertWithNilChecker(c *check.C) {
326	log := "(?s)helpers_test\\.go:[0-9]+:.*\nhelpers_test\\.go:[0-9]+:\n" +
327		"    c\\.Assert\\(1, nil\\)\n" +
328		"\\.+ Assert\\(obtained, nil!\\?, \\.\\.\\.\\):\n" +
329		"\\.+ Oops\\.\\. you've provided a nil checker!\n\n"
330	testHelperFailure(c, "Assert(obtained, nil)", nil, true, log,
331		func() interface{} {
332			c.Assert(1, nil)
333			return nil
334		})
335}
336
337// -----------------------------------------------------------------------
338// Ensure that values logged work properly in some interesting cases.
339
340func (s *HelpersS) TestValueLoggingWithArrays(c *check.C) {
341	checker := &MyChecker{result: false}
342	log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
343		"    return c\\.Check\\(\\[\\]byte{1, 2}, checker, \\[\\]byte{1, 3}\\)\n" +
344		"\\.+ myobtained \\[\\]uint8 = \\[\\]byte{0x1, 0x2}\n" +
345		"\\.+ myexpected \\[\\]uint8 = \\[\\]byte{0x1, 0x3}\n\n"
346	testHelperFailure(c, "Check([]byte{1}, chk, []byte{3})", false, false, log,
347		func() interface{} {
348			return c.Check([]byte{1, 2}, checker, []byte{1, 3})
349		})
350}
351
352func (s *HelpersS) TestValueLoggingWithMultiLine(c *check.C) {
353	checker := &MyChecker{result: false}
354	log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
355		"    return c\\.Check\\(\"a\\\\nb\\\\n\", checker, \"a\\\\nb\\\\nc\"\\)\n" +
356		"\\.+ myobtained string = \"\" \\+\n" +
357		"\\.+     \"a\\\\n\" \\+\n" +
358		"\\.+     \"b\\\\n\"\n" +
359		"\\.+ myexpected string = \"\" \\+\n" +
360		"\\.+     \"a\\\\n\" \\+\n" +
361		"\\.+     \"b\\\\n\" \\+\n" +
362		"\\.+     \"c\"\n\n"
363	testHelperFailure(c, `Check("a\nb\n", chk, "a\nb\nc")`, false, false, log,
364		func() interface{} {
365			return c.Check("a\nb\n", checker, "a\nb\nc")
366		})
367}
368
369func (s *HelpersS) TestValueLoggingWithMultiLineException(c *check.C) {
370	// If the newline is at the end of the string, don't log as multi-line.
371	checker := &MyChecker{result: false}
372	log := "(?s)helpers_test.go:[0-9]+:.*\nhelpers_test.go:[0-9]+:\n" +
373		"    return c\\.Check\\(\"a b\\\\n\", checker, \"a\\\\nb\"\\)\n" +
374		"\\.+ myobtained string = \"a b\\\\n\"\n" +
375		"\\.+ myexpected string = \"\" \\+\n" +
376		"\\.+     \"a\\\\n\" \\+\n" +
377		"\\.+     \"b\"\n\n"
378	testHelperFailure(c, `Check("a b\n", chk, "a\nb")`, false, false, log,
379		func() interface{} {
380			return c.Check("a b\n", checker, "a\nb")
381		})
382}
383
384// -----------------------------------------------------------------------
385// MakeDir() tests.
386
387type MkDirHelper struct {
388	path1  string
389	path2  string
390	isDir1 bool
391	isDir2 bool
392	isDir3 bool
393	isDir4 bool
394}
395
396func (s *MkDirHelper) SetUpSuite(c *check.C) {
397	s.path1 = c.MkDir()
398	s.isDir1 = isDir(s.path1)
399}
400
401func (s *MkDirHelper) Test(c *check.C) {
402	s.path2 = c.MkDir()
403	s.isDir2 = isDir(s.path2)
404}
405
406func (s *MkDirHelper) TearDownSuite(c *check.C) {
407	s.isDir3 = isDir(s.path1)
408	s.isDir4 = isDir(s.path2)
409}
410
411func (s *HelpersS) TestMkDir(c *check.C) {
412	helper := MkDirHelper{}
413	output := String{}
414	check.Run(&helper, &check.RunConf{Output: &output})
415	c.Assert(output.value, check.Equals, "")
416	c.Check(helper.isDir1, check.Equals, true)
417	c.Check(helper.isDir2, check.Equals, true)
418	c.Check(helper.isDir3, check.Equals, true)
419	c.Check(helper.isDir4, check.Equals, true)
420	c.Check(helper.path1, check.Not(check.Equals),
421		helper.path2)
422	c.Check(isDir(helper.path1), check.Equals, false)
423	c.Check(isDir(helper.path2), check.Equals, false)
424}
425
426func isDir(path string) bool {
427	if stat, err := os.Stat(path); err == nil {
428		return stat.IsDir()
429	}
430	return false
431}
432
433// Concurrent logging should not corrupt the underling buffer.
434// Use go test -race to detect the race in this test.
435func (s *HelpersS) TestConcurrentLogging(c *check.C) {
436	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))
437	var start, stop sync.WaitGroup
438	start.Add(1)
439	for i, n := 0, runtime.NumCPU()*2; i < n; i++ {
440		stop.Add(1)
441		go func(i int) {
442			start.Wait()
443			for j := 0; j < 30; j++ {
444				c.Logf("Worker %d: line %d", i, j)
445			}
446			stop.Done()
447		}(i)
448	}
449	start.Done()
450	stop.Wait()
451}
452
453// -----------------------------------------------------------------------
454// Test the TestName function
455
456type TestNameHelper struct {
457	name1 string
458	name2 string
459	name3 string
460	name4 string
461	name5 string
462}
463
464func (s *TestNameHelper) SetUpSuite(c *check.C)    { s.name1 = c.TestName() }
465func (s *TestNameHelper) SetUpTest(c *check.C)     { s.name2 = c.TestName() }
466func (s *TestNameHelper) Test(c *check.C)          { s.name3 = c.TestName() }
467func (s *TestNameHelper) TearDownTest(c *check.C)  { s.name4 = c.TestName() }
468func (s *TestNameHelper) TearDownSuite(c *check.C) { s.name5 = c.TestName() }
469
470func (s *HelpersS) TestTestName(c *check.C) {
471	helper := TestNameHelper{}
472	output := String{}
473	check.Run(&helper, &check.RunConf{Output: &output})
474	c.Check(helper.name1, check.Equals, "")
475	c.Check(helper.name2, check.Equals, "TestNameHelper.Test")
476	c.Check(helper.name3, check.Equals, "TestNameHelper.Test")
477	c.Check(helper.name4, check.Equals, "TestNameHelper.Test")
478	c.Check(helper.name5, check.Equals, "")
479}
480
481// -----------------------------------------------------------------------
482// A couple of helper functions to test helper functions. :-)
483
484func testHelperSuccess(c *check.C, name string, expectedResult interface{}, closure func() interface{}) {
485	var result interface{}
486	defer (func() {
487		if err := recover(); err != nil {
488			panic(err)
489		}
490		checkState(c, result,
491			&expectedState{
492				name:   name,
493				result: expectedResult,
494				failed: false,
495				log:    "",
496			})
497	})()
498	result = closure()
499}
500
501func testHelperFailure(c *check.C, name string, expectedResult interface{}, shouldStop bool, log string, closure func() interface{}) {
502	var result interface{}
503	defer (func() {
504		if err := recover(); err != nil {
505			panic(err)
506		}
507		checkState(c, result,
508			&expectedState{
509				name:   name,
510				result: expectedResult,
511				failed: true,
512				log:    log,
513			})
514	})()
515	result = closure()
516	if shouldStop {
517		c.Logf("%s didn't stop when it should", name)
518	}
519}
520