1// These tests check that the foundations of gocheck are working properly.
2// They already assume that fundamental failing is working already, though,
3// since this was tested in bootstrap_test.go. Even then, some care may
4// still have to be taken when using external functions, since they should
5// of course not rely on functionality tested here.
6
7package check_test
8
9import (
10	"fmt"
11	"gopkg.in/check.v1"
12	"log"
13	"os"
14	"regexp"
15	"strings"
16)
17
18// -----------------------------------------------------------------------
19// Foundation test suite.
20
21type FoundationS struct{}
22
23var foundationS = check.Suite(&FoundationS{})
24
25func (s *FoundationS) TestCountSuite(c *check.C) {
26	suitesRun += 1
27}
28
29func (s *FoundationS) TestErrorf(c *check.C) {
30	// Do not use checkState() here.  It depends on Errorf() working.
31	expectedLog := fmt.Sprintf("foundation_test.go:%d:\n"+
32		"    c.Errorf(\"Error %%v!\", \"message\")\n"+
33		"... Error: Error message!\n\n",
34		getMyLine()+1)
35	c.Errorf("Error %v!", "message")
36	failed := c.Failed()
37	c.Succeed()
38	if log := c.GetTestLog(); log != expectedLog {
39		c.Logf("Errorf() logged %#v rather than %#v", log, expectedLog)
40		c.Fail()
41	}
42	if !failed {
43		c.Logf("Errorf() didn't put the test in a failed state")
44		c.Fail()
45	}
46}
47
48func (s *FoundationS) TestError(c *check.C) {
49	expectedLog := fmt.Sprintf("foundation_test.go:%d:\n"+
50		"    c\\.Error\\(\"Error \", \"message!\"\\)\n"+
51		"\\.\\.\\. Error: Error message!\n\n",
52		getMyLine()+1)
53	c.Error("Error ", "message!")
54	checkState(c, nil,
55		&expectedState{
56			name:   "Error(`Error `, `message!`)",
57			failed: true,
58			log:    expectedLog,
59		})
60}
61
62func (s *FoundationS) TestFailNow(c *check.C) {
63	defer (func() {
64		if !c.Failed() {
65			c.Error("FailNow() didn't fail the test")
66		} else {
67			c.Succeed()
68			if c.GetTestLog() != "" {
69				c.Error("Something got logged:\n" + c.GetTestLog())
70			}
71		}
72	})()
73
74	c.FailNow()
75	c.Log("FailNow() didn't stop the test")
76}
77
78func (s *FoundationS) TestSucceedNow(c *check.C) {
79	defer (func() {
80		if c.Failed() {
81			c.Error("SucceedNow() didn't succeed the test")
82		}
83		if c.GetTestLog() != "" {
84			c.Error("Something got logged:\n" + c.GetTestLog())
85		}
86	})()
87
88	c.Fail()
89	c.SucceedNow()
90	c.Log("SucceedNow() didn't stop the test")
91}
92
93func (s *FoundationS) TestFailureHeader(c *check.C) {
94	output := String{}
95	failHelper := FailHelper{}
96	check.Run(&failHelper, &check.RunConf{Output: &output})
97	header := fmt.Sprintf(""+
98		"\n-----------------------------------"+
99		"-----------------------------------\n"+
100		"FAIL: check_test.go:%d: FailHelper.TestLogAndFail\n",
101		failHelper.testLine)
102	if strings.Index(output.value, header) == -1 {
103		c.Errorf(""+
104			"Failure didn't print a proper header.\n"+
105			"... Got:\n%s... Expected something with:\n%s",
106			output.value, header)
107	}
108}
109
110func (s *FoundationS) TestFatal(c *check.C) {
111	var line int
112	defer (func() {
113		if !c.Failed() {
114			c.Error("Fatal() didn't fail the test")
115		} else {
116			c.Succeed()
117			expected := fmt.Sprintf("foundation_test.go:%d:\n"+
118				"    c.Fatal(\"Die \", \"now!\")\n"+
119				"... Error: Die now!\n\n",
120				line)
121			if c.GetTestLog() != expected {
122				c.Error("Incorrect log:", c.GetTestLog())
123			}
124		}
125	})()
126
127	line = getMyLine() + 1
128	c.Fatal("Die ", "now!")
129	c.Log("Fatal() didn't stop the test")
130}
131
132func (s *FoundationS) TestFatalf(c *check.C) {
133	var line int
134	defer (func() {
135		if !c.Failed() {
136			c.Error("Fatalf() didn't fail the test")
137		} else {
138			c.Succeed()
139			expected := fmt.Sprintf("foundation_test.go:%d:\n"+
140				"    c.Fatalf(\"Die %%s!\", \"now\")\n"+
141				"... Error: Die now!\n\n",
142				line)
143			if c.GetTestLog() != expected {
144				c.Error("Incorrect log:", c.GetTestLog())
145			}
146		}
147	})()
148
149	line = getMyLine() + 1
150	c.Fatalf("Die %s!", "now")
151	c.Log("Fatalf() didn't stop the test")
152}
153
154func (s *FoundationS) TestCallerLoggingInsideTest(c *check.C) {
155	log := fmt.Sprintf(""+
156		"foundation_test.go:%d:\n"+
157		"    result := c.Check\\(10, check.Equals, 20\\)\n"+
158		"\\.\\.\\. obtained int = 10\n"+
159		"\\.\\.\\. expected int = 20\n\n",
160		getMyLine()+1)
161	result := c.Check(10, check.Equals, 20)
162	checkState(c, result,
163		&expectedState{
164			name:   "Check(10, Equals, 20)",
165			result: false,
166			failed: true,
167			log:    log,
168		})
169}
170
171func (s *FoundationS) TestCallerLoggingInDifferentFile(c *check.C) {
172	result, line := checkEqualWrapper(c, 10, 20)
173	testLine := getMyLine() - 1
174	log := fmt.Sprintf(""+
175		"foundation_test.go:%d:\n"+
176		"    result, line := checkEqualWrapper\\(c, 10, 20\\)\n"+
177		"check_test.go:%d:\n"+
178		"    return c.Check\\(obtained, check.Equals, expected\\), getMyLine\\(\\)\n"+
179		"\\.\\.\\. obtained int = 10\n"+
180		"\\.\\.\\. expected int = 20\n\n",
181		testLine, line)
182	checkState(c, result,
183		&expectedState{
184			name:   "Check(10, Equals, 20)",
185			result: false,
186			failed: true,
187			log:    log,
188		})
189}
190
191// -----------------------------------------------------------------------
192// ExpectFailure() inverts the logic of failure.
193
194type ExpectFailureSucceedHelper struct{}
195
196func (s *ExpectFailureSucceedHelper) TestSucceed(c *check.C) {
197	c.ExpectFailure("It booms!")
198	c.Error("Boom!")
199}
200
201type ExpectFailureFailHelper struct{}
202
203func (s *ExpectFailureFailHelper) TestFail(c *check.C) {
204	c.ExpectFailure("Bug #XYZ")
205}
206
207func (s *FoundationS) TestExpectFailureFail(c *check.C) {
208	helper := ExpectFailureFailHelper{}
209	output := String{}
210	result := check.Run(&helper, &check.RunConf{Output: &output})
211
212	expected := "" +
213		"^\n-+\n" +
214		"FAIL: foundation_test\\.go:[0-9]+:" +
215		" ExpectFailureFailHelper\\.TestFail\n\n" +
216		"\\.\\.\\. Error: Test succeeded, but was expected to fail\n" +
217		"\\.\\.\\. Reason: Bug #XYZ\n$"
218
219	matched, err := regexp.MatchString(expected, output.value)
220	if err != nil {
221		c.Error("Bad expression: ", expected)
222	} else if !matched {
223		c.Error("ExpectFailure() didn't log properly:\n", output.value)
224	}
225
226	c.Assert(result.ExpectedFailures, check.Equals, 0)
227}
228
229func (s *FoundationS) TestExpectFailureSucceed(c *check.C) {
230	helper := ExpectFailureSucceedHelper{}
231	output := String{}
232	result := check.Run(&helper, &check.RunConf{Output: &output})
233
234	c.Assert(output.value, check.Equals, "")
235	c.Assert(result.ExpectedFailures, check.Equals, 1)
236}
237
238func (s *FoundationS) TestExpectFailureSucceedVerbose(c *check.C) {
239	helper := ExpectFailureSucceedHelper{}
240	output := String{}
241	result := check.Run(&helper, &check.RunConf{Output: &output, Verbose: true})
242
243	expected := "" +
244		"FAIL EXPECTED: foundation_test\\.go:[0-9]+:" +
245		" ExpectFailureSucceedHelper\\.TestSucceed \\(It booms!\\)\t *[.0-9]+s\n"
246
247	matched, err := regexp.MatchString(expected, output.value)
248	if err != nil {
249		c.Error("Bad expression: ", expected)
250	} else if !matched {
251		c.Error("ExpectFailure() didn't log properly:\n", output.value)
252	}
253
254	c.Assert(result.ExpectedFailures, check.Equals, 1)
255}
256
257// -----------------------------------------------------------------------
258// Skip() allows stopping a test without positive/negative results.
259
260type SkipTestHelper struct{}
261
262func (s *SkipTestHelper) TestFail(c *check.C) {
263	c.Skip("Wrong platform or whatever")
264	c.Error("Boom!")
265}
266
267func (s *FoundationS) TestSkip(c *check.C) {
268	helper := SkipTestHelper{}
269	output := String{}
270	check.Run(&helper, &check.RunConf{Output: &output})
271
272	if output.value != "" {
273		c.Error("Skip() logged something:\n", output.value)
274	}
275}
276
277func (s *FoundationS) TestSkipVerbose(c *check.C) {
278	helper := SkipTestHelper{}
279	output := String{}
280	check.Run(&helper, &check.RunConf{Output: &output, Verbose: true})
281
282	expected := "SKIP: foundation_test\\.go:[0-9]+: SkipTestHelper\\.TestFail" +
283		" \\(Wrong platform or whatever\\)"
284	matched, err := regexp.MatchString(expected, output.value)
285	if err != nil {
286		c.Error("Bad expression: ", expected)
287	} else if !matched {
288		c.Error("Skip() didn't log properly:\n", output.value)
289	}
290}
291
292// -----------------------------------------------------------------------
293// Check minimum *log.Logger interface provided by *check.C.
294
295type minLogger interface {
296	Output(calldepth int, s string) error
297}
298
299func (s *BootstrapS) TestMinLogger(c *check.C) {
300	var logger minLogger
301	logger = log.New(os.Stderr, "", 0)
302	logger = c
303	logger.Output(0, "Hello there")
304	expected := `\[LOG\] [0-9]+:[0-9][0-9]\.[0-9][0-9][0-9] +Hello there\n`
305	output := c.GetTestLog()
306	c.Assert(output, check.Matches, expected)
307}
308
309// -----------------------------------------------------------------------
310// Ensure that suites with embedded types are working fine, including the
311// the workaround for issue 906.
312
313type EmbeddedInternalS struct {
314	called bool
315}
316
317type EmbeddedS struct {
318	EmbeddedInternalS
319}
320
321var embeddedS = check.Suite(&EmbeddedS{})
322
323func (s *EmbeddedS) TestCountSuite(c *check.C) {
324	suitesRun += 1
325}
326
327func (s *EmbeddedInternalS) TestMethod(c *check.C) {
328	c.Error("TestMethod() of the embedded type was called!?")
329}
330
331func (s *EmbeddedS) TestMethod(c *check.C) {
332	// http://code.google.com/p/go/issues/detail?id=906
333	c.Check(s.called, check.Equals, false) // Go issue 906 is affecting the runner?
334	s.called = true
335}
336