|
Packit |
63bb0d |
package suite
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
import (
|
|
Packit |
63bb0d |
"flag"
|
|
Packit |
63bb0d |
"fmt"
|
|
Packit |
63bb0d |
"os"
|
|
Packit |
63bb0d |
"reflect"
|
|
Packit |
63bb0d |
"regexp"
|
|
Packit |
63bb0d |
"runtime/debug"
|
|
Packit Service |
509fd4 |
"sync"
|
|
Packit |
63bb0d |
"testing"
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
"github.com/stretchr/testify/assert"
|
|
Packit |
63bb0d |
"github.com/stretchr/testify/require"
|
|
Packit |
63bb0d |
)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
var allTestsFilter = func(_, _ string) (bool, error) { return true, nil }
|
|
Packit |
63bb0d |
var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run")
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Suite is a basic testing suite with methods for storing and
|
|
Packit |
63bb0d |
// retrieving the current *testing.T context.
|
|
Packit |
63bb0d |
type Suite struct {
|
|
Packit |
63bb0d |
*assert.Assertions
|
|
Packit |
63bb0d |
require *require.Assertions
|
|
Packit |
63bb0d |
t *testing.T
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// T retrieves the current *testing.T context.
|
|
Packit |
63bb0d |
func (suite *Suite) T() *testing.T {
|
|
Packit |
63bb0d |
return suite.t
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// SetT sets the current *testing.T context.
|
|
Packit |
63bb0d |
func (suite *Suite) SetT(t *testing.T) {
|
|
Packit |
63bb0d |
suite.t = t
|
|
Packit |
63bb0d |
suite.Assertions = assert.New(t)
|
|
Packit |
63bb0d |
suite.require = require.New(t)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Require returns a require context for suite.
|
|
Packit |
63bb0d |
func (suite *Suite) Require() *require.Assertions {
|
|
Packit |
63bb0d |
if suite.require == nil {
|
|
Packit |
63bb0d |
suite.require = require.New(suite.T())
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return suite.require
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Assert returns an assert context for suite. Normally, you can call
|
|
Packit |
63bb0d |
// `suite.NoError(expected, actual)`, but for situations where the embedded
|
|
Packit |
63bb0d |
// methods are overridden (for example, you might want to override
|
|
Packit |
63bb0d |
// assert.Assertions with require.Assertions), this method is provided so you
|
|
Packit |
63bb0d |
// can call `suite.Assert().NoError()`.
|
|
Packit |
63bb0d |
func (suite *Suite) Assert() *assert.Assertions {
|
|
Packit |
63bb0d |
if suite.Assertions == nil {
|
|
Packit |
63bb0d |
suite.Assertions = assert.New(suite.T())
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return suite.Assertions
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func failOnPanic(t *testing.T) {
|
|
Packit |
63bb0d |
r := recover()
|
|
Packit |
63bb0d |
if r != nil {
|
|
Packit |
63bb0d |
t.Errorf("test panicked: %v\n%s", r, debug.Stack())
|
|
Packit |
63bb0d |
t.FailNow()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Run provides suite functionality around golang subtests. It should be
|
|
Packit |
63bb0d |
// called in place of t.Run(name, func(t *testing.T)) in test suite code.
|
|
Packit |
63bb0d |
// The passed-in func will be executed as a subtest with a fresh instance of t.
|
|
Packit |
63bb0d |
// Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName.
|
|
Packit |
63bb0d |
func (suite *Suite) Run(name string, subtest func()) bool {
|
|
Packit |
63bb0d |
oldT := suite.T()
|
|
Packit |
63bb0d |
defer suite.SetT(oldT)
|
|
Packit |
63bb0d |
return oldT.Run(name, func(t *testing.T) {
|
|
Packit |
63bb0d |
suite.SetT(t)
|
|
Packit |
63bb0d |
subtest()
|
|
Packit |
63bb0d |
})
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Run takes a testing suite and runs all of the tests attached
|
|
Packit |
63bb0d |
// to it.
|
|
Packit |
63bb0d |
func Run(t *testing.T, suite TestingSuite) {
|
|
Packit Service |
509fd4 |
testsSync := &sync.WaitGroup{}
|
|
Packit |
63bb0d |
suite.SetT(t)
|
|
Packit |
63bb0d |
defer failOnPanic(t)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
suiteSetupDone := false
|
|
Packit Service |
509fd4 |
|
|
Packit |
63bb0d |
methodFinder := reflect.TypeOf(suite)
|
|
Packit |
63bb0d |
tests := []testing.InternalTest{}
|
|
Packit |
63bb0d |
for index := 0; index < methodFinder.NumMethod(); index++ {
|
|
Packit |
63bb0d |
method := methodFinder.Method(index)
|
|
Packit |
63bb0d |
ok, err := methodFilter(method.Name)
|
|
Packit |
63bb0d |
if err != nil {
|
|
Packit |
63bb0d |
fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err)
|
|
Packit |
63bb0d |
os.Exit(1)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if !ok {
|
|
Packit |
63bb0d |
continue
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if !suiteSetupDone {
|
|
Packit |
63bb0d |
if setupAllSuite, ok := suite.(SetupAllSuite); ok {
|
|
Packit |
63bb0d |
setupAllSuite.SetupSuite()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
defer func() {
|
|
Packit |
63bb0d |
if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
|
|
Packit Service |
509fd4 |
testsSync.Wait()
|
|
Packit |
63bb0d |
tearDownAllSuite.TearDownSuite()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}()
|
|
Packit |
63bb0d |
suiteSetupDone = true
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
test := testing.InternalTest{
|
|
Packit |
63bb0d |
Name: method.Name,
|
|
Packit |
63bb0d |
F: func(t *testing.T) {
|
|
Packit Service |
509fd4 |
defer testsSync.Done()
|
|
Packit |
63bb0d |
parentT := suite.T()
|
|
Packit |
63bb0d |
suite.SetT(t)
|
|
Packit |
63bb0d |
defer failOnPanic(t)
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
if setupTestSuite, ok := suite.(SetupTestSuite); ok {
|
|
Packit |
63bb0d |
setupTestSuite.SetupTest()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if beforeTestSuite, ok := suite.(BeforeTest); ok {
|
|
Packit |
63bb0d |
beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
defer func() {
|
|
Packit |
63bb0d |
if afterTestSuite, ok := suite.(AfterTest); ok {
|
|
Packit |
63bb0d |
afterTestSuite.AfterTest(methodFinder.Elem().Name(), method.Name)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
|
|
Packit |
63bb0d |
tearDownTestSuite.TearDownTest()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
suite.SetT(parentT)
|
|
Packit |
63bb0d |
}()
|
|
Packit |
63bb0d |
method.Func.Call([]reflect.Value{reflect.ValueOf(suite)})
|
|
Packit |
63bb0d |
},
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
tests = append(tests, test)
|
|
Packit Service |
509fd4 |
testsSync.Add(1)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
runTests(t, tests)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
func runTests(t testing.TB, tests []testing.InternalTest) {
|
|
Packit |
63bb0d |
r, ok := t.(runner)
|
|
Packit |
63bb0d |
if !ok { // backwards compatibility with Go 1.6 and below
|
|
Packit |
63bb0d |
if !testing.RunTests(allTestsFilter, tests) {
|
|
Packit |
63bb0d |
t.Fail()
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
for _, test := range tests {
|
|
Packit |
63bb0d |
r.Run(test.Name, test.F)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
// Filtering method according to set regular expression
|
|
Packit |
63bb0d |
// specified command-line argument -m
|
|
Packit |
63bb0d |
func methodFilter(name string) (bool, error) {
|
|
Packit |
63bb0d |
if ok, _ := regexp.MatchString("^Test", name); !ok {
|
|
Packit |
63bb0d |
return false, nil
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
return regexp.MatchString(*matchMethod, name)
|
|
Packit |
63bb0d |
}
|
|
Packit |
63bb0d |
|
|
Packit |
63bb0d |
type runner interface {
|
|
Packit |
63bb0d |
Run(name string, f func(t *testing.T)) bool
|
|
Packit |
63bb0d |
}
|