diff --git a/suite/options.go b/suite/options.go new file mode 100644 index 000000000..d4f1ac944 --- /dev/null +++ b/suite/options.go @@ -0,0 +1,24 @@ +package suite + +type runOptions struct { + testFilter func(testName string) (bool, error) +} + +// RunOption sets optional run parameter to specific value. +type RunOption func(*runOptions) + +// WithTestFilter replaces default filter function which passed via -m flag to custom function. +func WithTestFilter(testFilter func(testName string) (bool, error)) RunOption { + return func(opts *runOptions) { + opts.testFilter = testFilter + } +} + +// WithIgnoreMatch ignores -m flag. +func WithIgnoreMatch() RunOption { + return func(opts *runOptions) { + opts.testFilter = func(testName string) (bool, error) { + return true, nil + } + } +} diff --git a/suite/suite.go b/suite/suite.go index b9b5d1c56..87326c931 100644 --- a/suite/suite.go +++ b/suite/suite.go @@ -16,6 +16,7 @@ import ( var allTestsFilter = func(_, _ string) (bool, error) { return true, nil } var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") +var matchTestRegex = regexp.MustCompile("^Test") // Suite is a basic testing suite with methods for storing and // retrieving the current *testing.T context. @@ -80,13 +81,23 @@ func (suite *Suite) Run(name string, subtest func()) bool { // Run takes a testing suite and runs all of the tests attached // to it. -func Run(t *testing.T, suite TestingSuite) { +func Run(t *testing.T, suite TestingSuite, opts ...RunOption) { defer failOnPanic(t) suite.SetT(t) var suiteSetupDone bool + var runOpts = &runOptions{ + testFilter: func(testName string) (bool, error) { + return regexp.MatchString(*matchMethod, testName) + }, + } + + for _, opt := range opts { + opt(runOpts) + } + var stats *SuiteInformation if _, ok := suite.(WithStats); ok { stats = newSuiteInformation() @@ -99,9 +110,13 @@ func Run(t *testing.T, suite TestingSuite) { for i := 0; i < methodFinder.NumMethod(); i++ { method := methodFinder.Method(i) - ok, err := methodFilter(method.Name) + if !matchTestRegex.MatchString(method.Name) { + continue + } + + ok, err := runOpts.testFilter(method.Name) if err != nil { - fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) + fmt.Fprintf(os.Stderr, "testify: an error during apply filter: %v", err.Error()) os.Exit(1) } @@ -176,15 +191,6 @@ func Run(t *testing.T, suite TestingSuite) { runTests(t, tests) } -// Filtering method according to set regular expression -// specified command-line argument -m -func methodFilter(name string) (bool, error) { - if ok, _ := regexp.MatchString("^Test", name); !ok { - return false, nil - } - return regexp.MatchString(*matchMethod, name) -} - func runTests(t testing.TB, tests []testing.InternalTest) { if len(tests) == 0 { t.Log("warning: no tests to run") diff --git a/suite/suite_test.go b/suite/suite_test.go index 963a25258..97fefae1e 100644 --- a/suite/suite_test.go +++ b/suite/suite_test.go @@ -587,3 +587,33 @@ func (s *FailfastSuite) Test_B_Passes() { s.call("Test B Passes") s.Require().True(true) } + +type childSuite struct { + Suite + done bool +} + +func (s *childSuite) TestChild() { + s.done = true +} + +type parentSuite struct { + Suite +} + +func (p *parentSuite) Test1() { + var child = new(childSuite) + Run(p.T(), child, WithIgnoreMatch()) + p.Require().True(child.done) +} + +func (p *parentSuite) Test2() { + p.Require().FailNow("this test should be ingored due to passed -testify.m flag") +} + +func TestSuiteRunsSuite(t *testing.T) { + matchMethod = new(string) + *matchMethod = "Test1" + var s parentSuite + Run(t, &s) +}