1package suite
2
3import (
4	"errors"
5	"io/ioutil"
6	"os"
7	"testing"
8	"time"
9
10	"github.com/stretchr/testify/assert"
11	"github.com/stretchr/testify/require"
12)
13
14// SuiteRequireTwice is intended to test the usage of suite.Require in two
15// different tests
16type SuiteRequireTwice struct{ Suite }
17
18// TestSuiteRequireTwice checks for regressions of issue #149 where
19// suite.requirements was not initialised in suite.SetT()
20// A regression would result on these tests panicking rather than failing.
21func TestSuiteRequireTwice(t *testing.T) {
22	ok := testing.RunTests(
23		allTestsFilter,
24		[]testing.InternalTest{{
25			Name: "TestSuiteRequireTwice",
26			F: func(t *testing.T) {
27				suite := new(SuiteRequireTwice)
28				Run(t, suite)
29			},
30		}},
31	)
32	assert.Equal(t, false, ok)
33}
34
35func (s *SuiteRequireTwice) TestRequireOne() {
36	r := s.Require()
37	r.Equal(1, 2)
38}
39
40func (s *SuiteRequireTwice) TestRequireTwo() {
41	r := s.Require()
42	r.Equal(1, 2)
43}
44
45type panickingSuite struct {
46	Suite
47	panicInSetupSuite    bool
48	panicInSetupTest     bool
49	panicInBeforeTest    bool
50	panicInTest          bool
51	panicInAfterTest     bool
52	panicInTearDownTest  bool
53	panicInTearDownSuite bool
54}
55
56func (s *panickingSuite) SetupSuite() {
57	if s.panicInSetupSuite {
58		panic("oops in setup suite")
59	}
60}
61
62func (s *panickingSuite) SetupTest() {
63	if s.panicInSetupTest {
64		panic("oops in setup test")
65	}
66}
67
68func (s *panickingSuite) BeforeTest(_, _ string) {
69	if s.panicInBeforeTest {
70		panic("oops in before test")
71	}
72}
73
74func (s *panickingSuite) Test() {
75	if s.panicInTest {
76		panic("oops in test")
77	}
78}
79
80func (s *panickingSuite) AfterTest(_, _ string) {
81	if s.panicInAfterTest {
82		panic("oops in after test")
83	}
84}
85
86func (s *panickingSuite) TearDownTest() {
87	if s.panicInTearDownTest {
88		panic("oops in tear down test")
89	}
90}
91
92func (s *panickingSuite) TearDownSuite() {
93	if s.panicInTearDownSuite {
94		panic("oops in tear down suite")
95	}
96}
97
98func TestSuiteRecoverPanic(t *testing.T) {
99	ok := true
100	panickingTests := []testing.InternalTest{
101		{
102			Name: "TestPanicInSetupSuite",
103			F:    func(t *testing.T) { Run(t, &panickingSuite{panicInSetupSuite: true}) },
104		},
105		{
106			Name: "TestPanicInSetupTest",
107			F:    func(t *testing.T) { Run(t, &panickingSuite{panicInSetupTest: true}) },
108		},
109		{
110			Name: "TestPanicInBeforeTest",
111			F:    func(t *testing.T) { Run(t, &panickingSuite{panicInBeforeTest: true}) },
112		},
113		{
114			Name: "TestPanicInTest",
115			F:    func(t *testing.T) { Run(t, &panickingSuite{panicInTest: true}) },
116		},
117		{
118			Name: "TestPanicInAfterTest",
119			F:    func(t *testing.T) { Run(t, &panickingSuite{panicInAfterTest: true}) },
120		},
121		{
122			Name: "TestPanicInTearDownTest",
123			F:    func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownTest: true}) },
124		},
125		{
126			Name: "TestPanicInTearDownSuite",
127			F:    func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownSuite: true}) },
128		},
129	}
130
131	require.NotPanics(t, func() {
132		ok = testing.RunTests(allTestsFilter, panickingTests)
133	})
134
135	assert.False(t, ok)
136}
137
138// This suite is intended to store values to make sure that only
139// testing-suite-related methods are run.  It's also a fully
140// functional example of a testing suite, using setup/teardown methods
141// and a helper method that is ignored by testify.  To make this look
142// more like a real world example, all tests in the suite perform some
143// type of assertion.
144type SuiteTester struct {
145	// Include our basic suite logic.
146	Suite
147
148	// Keep counts of how many times each method is run.
149	SetupSuiteRunCount    int
150	TearDownSuiteRunCount int
151	SetupTestRunCount     int
152	TearDownTestRunCount  int
153	TestOneRunCount       int
154	TestTwoRunCount       int
155	TestSubtestRunCount   int
156	NonTestMethodRunCount int
157
158	SuiteNameBefore []string
159	TestNameBefore  []string
160
161	SuiteNameAfter []string
162	TestNameAfter  []string
163
164	TimeBefore []time.Time
165	TimeAfter  []time.Time
166}
167
168// The SetupSuite method will be run by testify once, at the very
169// start of the testing suite, before any tests are run.
170func (suite *SuiteTester) SetupSuite() {
171	suite.SetupSuiteRunCount++
172}
173
174func (suite *SuiteTester) BeforeTest(suiteName, testName string) {
175	suite.SuiteNameBefore = append(suite.SuiteNameBefore, suiteName)
176	suite.TestNameBefore = append(suite.TestNameBefore, testName)
177	suite.TimeBefore = append(suite.TimeBefore, time.Now())
178}
179
180func (suite *SuiteTester) AfterTest(suiteName, testName string) {
181	suite.SuiteNameAfter = append(suite.SuiteNameAfter, suiteName)
182	suite.TestNameAfter = append(suite.TestNameAfter, testName)
183	suite.TimeAfter = append(suite.TimeAfter, time.Now())
184}
185
186// The TearDownSuite method will be run by testify once, at the very
187// end of the testing suite, after all tests have been run.
188func (suite *SuiteTester) TearDownSuite() {
189	suite.TearDownSuiteRunCount++
190}
191
192// The SetupTest method will be run before every test in the suite.
193func (suite *SuiteTester) SetupTest() {
194	suite.SetupTestRunCount++
195}
196
197// The TearDownTest method will be run after every test in the suite.
198func (suite *SuiteTester) TearDownTest() {
199	suite.TearDownTestRunCount++
200}
201
202// Every method in a testing suite that begins with "Test" will be run
203// as a test.  TestOne is an example of a test.  For the purposes of
204// this example, we've included assertions in the tests, since most
205// tests will issue assertions.
206func (suite *SuiteTester) TestOne() {
207	beforeCount := suite.TestOneRunCount
208	suite.TestOneRunCount++
209	assert.Equal(suite.T(), suite.TestOneRunCount, beforeCount+1)
210	suite.Equal(suite.TestOneRunCount, beforeCount+1)
211}
212
213// TestTwo is another example of a test.
214func (suite *SuiteTester) TestTwo() {
215	beforeCount := suite.TestTwoRunCount
216	suite.TestTwoRunCount++
217	assert.NotEqual(suite.T(), suite.TestTwoRunCount, beforeCount)
218	suite.NotEqual(suite.TestTwoRunCount, beforeCount)
219}
220
221func (suite *SuiteTester) TestSkip() {
222	suite.T().Skip()
223}
224
225// NonTestMethod does not begin with "Test", so it will not be run by
226// testify as a test in the suite.  This is useful for creating helper
227// methods for your tests.
228func (suite *SuiteTester) NonTestMethod() {
229	suite.NonTestMethodRunCount++
230}
231
232func (suite *SuiteTester) TestSubtest() {
233	suite.TestSubtestRunCount++
234
235	for _, t := range []struct {
236		testName string
237	}{
238		{"first"},
239		{"second"},
240	} {
241		suiteT := suite.T()
242		suite.Run(t.testName, func() {
243			// We should get a different *testing.T for subtests, so that
244			// go test recognizes them as proper subtests for output formatting
245			// and running individual subtests
246			subTestT := suite.T()
247			suite.NotEqual(subTestT, suiteT)
248		})
249		suite.Equal(suiteT, suite.T())
250	}
251}
252
253type SuiteSkipTester struct {
254	// Include our basic suite logic.
255	Suite
256
257	// Keep counts of how many times each method is run.
258	SetupSuiteRunCount    int
259	TearDownSuiteRunCount int
260}
261
262func (suite *SuiteSkipTester) SetupSuite() {
263	suite.SetupSuiteRunCount++
264	suite.T().Skip()
265}
266
267func (suite *SuiteSkipTester) TestNothing() {
268	// SetupSuite is only called when at least one test satisfies
269	// test filter. For this suite to be set up (and then tore down)
270	// it is necessary to add at least one test method.
271}
272
273func (suite *SuiteSkipTester) TearDownSuite() {
274	suite.TearDownSuiteRunCount++
275}
276
277// TestRunSuite will be run by the 'go test' command, so within it, we
278// can run our suite using the Run(*testing.T, TestingSuite) function.
279func TestRunSuite(t *testing.T) {
280	suiteTester := new(SuiteTester)
281	Run(t, suiteTester)
282
283	// Normally, the test would end here.  The following are simply
284	// some assertions to ensure that the Run function is working as
285	// intended - they are not part of the example.
286
287	// The suite was only run once, so the SetupSuite and TearDownSuite
288	// methods should have each been run only once.
289	assert.Equal(t, suiteTester.SetupSuiteRunCount, 1)
290	assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1)
291
292	assert.Equal(t, len(suiteTester.SuiteNameAfter), 4)
293	assert.Equal(t, len(suiteTester.SuiteNameBefore), 4)
294	assert.Equal(t, len(suiteTester.TestNameAfter), 4)
295	assert.Equal(t, len(suiteTester.TestNameBefore), 4)
296
297	assert.Contains(t, suiteTester.TestNameAfter, "TestOne")
298	assert.Contains(t, suiteTester.TestNameAfter, "TestTwo")
299	assert.Contains(t, suiteTester.TestNameAfter, "TestSkip")
300	assert.Contains(t, suiteTester.TestNameAfter, "TestSubtest")
301
302	assert.Contains(t, suiteTester.TestNameBefore, "TestOne")
303	assert.Contains(t, suiteTester.TestNameBefore, "TestTwo")
304	assert.Contains(t, suiteTester.TestNameBefore, "TestSkip")
305	assert.Contains(t, suiteTester.TestNameBefore, "TestSubtest")
306
307	for _, suiteName := range suiteTester.SuiteNameAfter {
308		assert.Equal(t, "SuiteTester", suiteName)
309	}
310
311	for _, suiteName := range suiteTester.SuiteNameBefore {
312		assert.Equal(t, "SuiteTester", suiteName)
313	}
314
315	for _, when := range suiteTester.TimeAfter {
316		assert.False(t, when.IsZero())
317	}
318
319	for _, when := range suiteTester.TimeBefore {
320		assert.False(t, when.IsZero())
321	}
322
323	// There are four test methods (TestOne, TestTwo, TestSkip, and TestSubtest), so
324	// the SetupTest and TearDownTest methods (which should be run once for
325	// each test) should have been run four times.
326	assert.Equal(t, suiteTester.SetupTestRunCount, 4)
327	assert.Equal(t, suiteTester.TearDownTestRunCount, 4)
328
329	// Each test should have been run once.
330	assert.Equal(t, suiteTester.TestOneRunCount, 1)
331	assert.Equal(t, suiteTester.TestTwoRunCount, 1)
332	assert.Equal(t, suiteTester.TestSubtestRunCount, 1)
333
334	// Methods that don't match the test method identifier shouldn't
335	// have been run at all.
336	assert.Equal(t, suiteTester.NonTestMethodRunCount, 0)
337
338	suiteSkipTester := new(SuiteSkipTester)
339	Run(t, suiteSkipTester)
340
341	// The suite was only run once, so the SetupSuite and TearDownSuite
342	// methods should have each been run only once, even though SetupSuite
343	// called Skip()
344	assert.Equal(t, suiteSkipTester.SetupSuiteRunCount, 1)
345	assert.Equal(t, suiteSkipTester.TearDownSuiteRunCount, 1)
346
347}
348
349// This suite has no Test... methods. It's setup and teardown must be skipped.
350type SuiteSetupSkipTester struct {
351	Suite
352
353	setUp bool
354	toreDown bool
355}
356
357func (s *SuiteSetupSkipTester) SetupSuite() {
358	s.setUp = true
359}
360
361func (s *SuiteSetupSkipTester) NonTestMethod() {
362
363}
364
365func (s *SuiteSetupSkipTester) TearDownSuite() {
366	s.toreDown = true
367}
368
369func TestSkippingSuiteSetup(t *testing.T) {
370	suiteTester := new(SuiteSetupSkipTester)
371	Run(t, suiteTester)
372	assert.False(t, suiteTester.setUp)
373	assert.False(t, suiteTester.toreDown)
374}
375
376func TestSuiteGetters(t *testing.T) {
377	suite := new(SuiteTester)
378	suite.SetT(t)
379	assert.NotNil(t, suite.Assert())
380	assert.Equal(t, suite.Assertions, suite.Assert())
381	assert.NotNil(t, suite.Require())
382	assert.Equal(t, suite.require, suite.Require())
383}
384
385type SuiteLoggingTester struct {
386	Suite
387}
388
389func (s *SuiteLoggingTester) TestLoggingPass() {
390	s.T().Log("TESTLOGPASS")
391}
392
393func (s *SuiteLoggingTester) TestLoggingFail() {
394	s.T().Log("TESTLOGFAIL")
395	assert.NotNil(s.T(), nil) // expected to fail
396}
397
398type StdoutCapture struct {
399	oldStdout *os.File
400	readPipe  *os.File
401}
402
403func (sc *StdoutCapture) StartCapture() {
404	sc.oldStdout = os.Stdout
405	sc.readPipe, os.Stdout, _ = os.Pipe()
406}
407
408func (sc *StdoutCapture) StopCapture() (string, error) {
409	if sc.oldStdout == nil || sc.readPipe == nil {
410		return "", errors.New("StartCapture not called before StopCapture")
411	}
412	os.Stdout.Close()
413	os.Stdout = sc.oldStdout
414	bytes, err := ioutil.ReadAll(sc.readPipe)
415	if err != nil {
416		return "", err
417	}
418	return string(bytes), nil
419}
420
421func TestSuiteLogging(t *testing.T) {
422	suiteLoggingTester := new(SuiteLoggingTester)
423	capture := StdoutCapture{}
424	internalTest := testing.InternalTest{
425		Name: "SomeTest",
426		F: func(subT *testing.T) {
427			Run(subT, suiteLoggingTester)
428		},
429	}
430	capture.StartCapture()
431	testing.RunTests(allTestsFilter, []testing.InternalTest{internalTest})
432	output, err := capture.StopCapture()
433	require.NoError(t, err, "Got an error trying to capture stdout and stderr!")
434	require.NotEmpty(t, output, "output content must not be empty")
435
436	// Failed tests' output is always printed
437	assert.Contains(t, output, "TESTLOGFAIL")
438
439	if testing.Verbose() {
440		// In verbose mode, output from successful tests is also printed
441		assert.Contains(t, output, "TESTLOGPASS")
442	} else {
443		assert.NotContains(t, output, "TESTLOGPASS")
444	}
445}
446