1// Package suite is a simplified version of testify's suite package which has unnecessary dependencies.
2// Please remove this package whenever possible.
3package suite
4
5import (
6	"flag"
7	"reflect"
8	"runtime/debug"
9	"strings"
10	"testing"
11)
12
13// TimeoutFlag is the flag to set a per-test timeout when running tests. Defaults to `-timeout`.
14var TimeoutFlag = flag.Duration("timeout", 0, "DO NOT USE")
15
16var typTestingT = reflect.TypeOf(new(testing.T))
17
18// Run takes a testing suite and runs all of the tests attached to it.
19func Run(t *testing.T, suite interface{}) {
20	defer failOnPanic(t)
21
22	suiteSetupDone := false
23
24	defer func() {
25		if suiteSetupDone {
26			if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
27				tearDownAllSuite.TearDownSuite(t)
28			}
29		}
30	}()
31
32	methodFinder := reflect.TypeOf(suite)
33	for index := 0; index < methodFinder.NumMethod(); index++ {
34		method := methodFinder.Method(index)
35		if !methodFilter(method.Name, method.Type) {
36			continue
37		}
38		t.Run(method.Name, func(t *testing.T) {
39			defer failOnPanic(t)
40
41			if !suiteSetupDone {
42				if setupAllSuite, ok := suite.(SetupAllSuite); ok {
43					setupAllSuite.SetUpSuite(t)
44				}
45				suiteSetupDone = true
46			}
47
48			if setupTestSuite, ok := suite.(SetupTestSuite); ok {
49				setupTestSuite.SetUpTest(t)
50			}
51			defer func() {
52				if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
53					tearDownTestSuite.TearDownTest(t)
54				}
55			}()
56
57			method.Func.Call([]reflect.Value{reflect.ValueOf(suite), reflect.ValueOf(t)})
58		})
59	}
60}
61
62func failOnPanic(t *testing.T) {
63	r := recover()
64	if r != nil {
65		t.Errorf("test suite panicked: %v\n%s", r, debug.Stack())
66		t.FailNow()
67	}
68}
69
70func methodFilter(name string, typ reflect.Type) bool {
71	return strings.HasPrefix(name, "Test") && typ.NumIn() == 2 && typ.In(1) == typTestingT // 2 params: method receiver and *testing.T
72}
73