forked from gotestyourself/gotest.tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a suite package for compat with testify
- Loading branch information
Showing
3 changed files
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell | ||
|
||
Please consider promoting this project if you find it useful. | ||
|
||
Permission is hereby granted, free of charge, to any person | ||
obtaining a copy of this software and associated documentation | ||
files (the "Software"), to deal in the Software without restriction, | ||
including without limitation the rights to use, copy, modify, merge, | ||
publish, distribute, sublicense, and/or sell copies of the Software, | ||
and to permit persons to whom the Software is furnished to do so, | ||
subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included | ||
in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT | ||
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE | ||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,205 @@ | ||
/*Package suite provides compatibility with testify/suite. | ||
Suites can be used to group tests together, and to perform common setup and | ||
teardown for each test in the suite. | ||
TODO: example | ||
Regular expression to select test suites specified command-line | ||
argument "-run". Regular expression to select the methods | ||
of test suites specified command-line argument "-m". | ||
Suite object has assertion methods. | ||
*/ | ||
package suite | ||
|
||
import ( | ||
"flag" | ||
"reflect" | ||
"regexp" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/gotestyourself/gotestyourself/assert" | ||
) | ||
|
||
var methodPattern = ®expValue{} | ||
|
||
func init() { | ||
flag.Var(methodPattern, "test.m", "only run tests that match the regexp") | ||
} | ||
|
||
// TestingSuite used is the interface for a test suite | ||
type TestingSuite interface { | ||
T() *testing.T | ||
SetT(*testing.T) | ||
} | ||
|
||
type setupSuite interface { | ||
SetupSuite() | ||
} | ||
|
||
type setupTest interface { | ||
SetupTest() | ||
} | ||
|
||
type teardownSuite interface { | ||
TearDownSuite() | ||
} | ||
|
||
type teardownTest interface { | ||
TearDownTest() | ||
} | ||
|
||
type beforeTest interface { | ||
BeforeTest(suiteName, testName string) | ||
} | ||
|
||
type afterTest interface { | ||
AfterTest(suiteName, testName string) | ||
} | ||
|
||
type helperT interface { | ||
Helper() | ||
} | ||
|
||
// Suite is an implementation of TestingSuite which can be embedded in a test | ||
// suite. | ||
type Suite struct { | ||
t *testing.T | ||
} | ||
|
||
// T retrieves the current *testing.T context. | ||
func (suite *Suite) T() *testing.T { | ||
return suite.t | ||
} | ||
|
||
// SetT sets the current *testing.T context. | ||
func (suite *Suite) SetT(t *testing.T) { | ||
suite.t = t | ||
} | ||
|
||
// Assert performs a comparison, marks the test as having failed if the comparison | ||
// returns false, and stops execution immediately. | ||
// | ||
// This is equivalent to assert.Assert(t, comparison). | ||
func (suite *Suite) Assert(comparison assert.BoolOrComparison, msgAndArgs ...interface{}) { | ||
if ht, ok := testing.TB(suite.t).(helperT); ok { | ||
ht.Helper() | ||
} | ||
// TODO: will print `comparison` instead of caller ast when used with bool | ||
assert.Assert(suite.t, comparison, msgAndArgs...) | ||
} | ||
|
||
// Check performs a comparison and marks the test as having failed if the comparison | ||
// returns false. Returns the result of the comparison. | ||
func (suite *Suite) Check(comparison assert.BoolOrComparison, msgAndArgs ...interface{}) bool { | ||
if ht, ok := testing.TB(suite.t).(helperT); ok { | ||
ht.Helper() | ||
} | ||
// TODO: will print `comparison` instead of caller ast when used with bool | ||
return assert.Check(suite.t, comparison, msgAndArgs...) | ||
} | ||
|
||
// Run all the tests in a testing suite | ||
func Run(t *testing.T, suite TestingSuite) { | ||
suite.SetT(t) | ||
|
||
if s, ok := suite.(setupSuite); ok { | ||
s.SetupSuite() | ||
} | ||
defer func() { | ||
if s, ok := suite.(teardownSuite); ok { | ||
s.TearDownSuite() | ||
} | ||
}() | ||
|
||
suiteType := reflect.TypeOf(suite) | ||
tests := []testing.InternalTest{} | ||
for index := 0; index < suiteType.NumMethod(); index++ { | ||
method := suiteType.Method(index) | ||
if !isTestMethod(method.Name) { | ||
continue | ||
} | ||
test := testing.InternalTest{ | ||
Name: method.Name, | ||
F: newTestFunc(suite, method), | ||
} | ||
tests = append(tests, test) | ||
} | ||
runTests(t, tests) | ||
} | ||
|
||
func newTestFunc(suite TestingSuite, method reflect.Method) func(*testing.T) { | ||
suiteType := reflect.TypeOf(suite) | ||
return func(t *testing.T) { | ||
parentT := suite.T() | ||
suite.SetT(t) | ||
if s, ok := suite.(setupTest); ok { | ||
s.SetupTest() | ||
} | ||
if s, ok := suite.(beforeTest); ok { | ||
s.BeforeTest(suiteType.Elem().Name(), method.Name) | ||
} | ||
defer func() { | ||
if s, ok := suite.(afterTest); ok { | ||
s.AfterTest(suiteType.Elem().Name(), method.Name) | ||
} | ||
if s, ok := suite.(teardownTest); ok { | ||
s.TearDownTest() | ||
} | ||
suite.SetT(parentT) | ||
}() | ||
method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) | ||
} | ||
} | ||
|
||
type runner interface { | ||
Run(name string, f func(t *testing.T)) bool | ||
} | ||
|
||
func runTests(t testing.TB, tests []testing.InternalTest) { | ||
r, ok := t.(runner) | ||
if !ok { // backwards compatibility with Go 1.6 and below | ||
allTestsFilter := func(_, _ string) (bool, error) { return true, nil } | ||
if !testing.RunTests(allTestsFilter, tests) { | ||
t.Fail() | ||
} | ||
return | ||
} | ||
|
||
for _, test := range tests { | ||
r.Run(test.Name, test.F) | ||
} | ||
} | ||
|
||
// TODO: should also check the next character after Test is uppercase | ||
func isTestMethod(name string) bool { | ||
if !strings.HasPrefix(name, "Test") { | ||
return false | ||
} | ||
return methodPattern.Match(name) | ||
} | ||
|
||
type regexpValue struct { | ||
re *regexp.Regexp | ||
} | ||
|
||
func (v *regexpValue) String() string { | ||
if v.re == nil { | ||
return "" | ||
} | ||
return v.re.String() | ||
} | ||
|
||
func (v *regexpValue) Set(value string) error { | ||
re, err := regexp.Compile(value) | ||
v.re = re | ||
return err | ||
} | ||
|
||
func (v *regexpValue) Match(value string) bool { | ||
if v.re == nil { | ||
return true | ||
} | ||
return v.re.MatchString(value) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package suite | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/gotestyourself/gotestyourself/assert" | ||
is "github.com/gotestyourself/gotestyourself/assert/cmp" | ||
) | ||
|
||
type fakeSuite struct { | ||
Suite | ||
|
||
suiteT *testing.T | ||
counter int | ||
|
||
beforeTestCalls []string | ||
testCalls []string | ||
afterTestCalls []string | ||
} | ||
|
||
func (s *fakeSuite) assertAndIncrement(expected int) { | ||
if ht, ok := testing.TB(s.t).(helperT); ok { | ||
ht.Helper() | ||
} | ||
s.Assert(is.Equal(s.counter, expected)) | ||
s.counter++ | ||
} | ||
|
||
func (s *fakeSuite) baseCount() int { | ||
return len(s.afterTestCalls) * 4 | ||
} | ||
|
||
func (s *fakeSuite) SetupSuite() { | ||
s.assertAndIncrement(0) | ||
s.Assert(is.Equal(s.suiteT, s.T())) | ||
} | ||
|
||
func (s *fakeSuite) SetupTest() { | ||
s.assertAndIncrement(s.baseCount() + 1) | ||
s.Assert(s.suiteT != s.T()) | ||
} | ||
|
||
func (s *fakeSuite) BeforeTest(suiteName, testName string) { | ||
s.assertAndIncrement(s.baseCount() + 2) | ||
s.Assert(is.Equal(suiteName, "fakeSuite")) | ||
s.beforeTestCalls = append(s.beforeTestCalls, testName) | ||
s.Assert(s.suiteT != s.T()) | ||
} | ||
|
||
func (s *fakeSuite) AfterTest(suiteName, testName string) { | ||
s.assertAndIncrement(s.baseCount() + 3) | ||
s.Assert(is.Equal(suiteName, "fakeSuite")) | ||
s.afterTestCalls = append(s.afterTestCalls, testName) | ||
s.Assert(s.suiteT != s.T()) | ||
} | ||
|
||
func (s *fakeSuite) TearDownTest() { | ||
s.assertAndIncrement(s.baseCount()) | ||
s.Assert(s.suiteT != s.T()) | ||
} | ||
|
||
func (s *fakeSuite) TearDownSuite() { | ||
s.assertAndIncrement(s.baseCount() + 1) | ||
s.Assert(is.Equal(s.suiteT, s.T())) | ||
} | ||
|
||
func (s *fakeSuite) TestOne() { | ||
s.testCalls = append(s.testCalls, "TestOne") | ||
s.Assert(s.suiteT != s.T()) | ||
} | ||
|
||
func (s *fakeSuite) TestTwo() { | ||
s.testCalls = append(s.testCalls, "TestTwo") | ||
} | ||
|
||
func (s *fakeSuite) TestSkip() { | ||
s.testCalls = append(s.testCalls, "TestSkip") | ||
s.T().Skip() | ||
} | ||
|
||
func (s *fakeSuite) NonATestMethod() { | ||
} | ||
|
||
func TestRunSuite(t *testing.T) { | ||
fakeSuite := new(fakeSuite) | ||
fakeSuite.suiteT = t | ||
Run(t, fakeSuite) | ||
|
||
expectedCount := 14 // setupSuite=1 + teardownSuite=1 + (numTests=3 * numFixtures=4) | ||
assert.Equal(t, fakeSuite.counter, expectedCount) | ||
|
||
expected := []string{"TestOne", "TestSkip", "TestTwo"} | ||
assert.Assert(t, is.Compare(expected, fakeSuite.testCalls)) | ||
assert.Assert(t, is.Compare(expected, fakeSuite.afterTestCalls)) | ||
assert.Assert(t, is.Compare(expected, fakeSuite.beforeTestCalls)) | ||
} |