You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
8.5 KiB
218 lines
8.5 KiB
// Package convey contains all of the public-facing entry points to this project.
|
|
// This means that it should never be required of the user to import any other
|
|
// packages from this project as they serve internal purposes.
|
|
package convey
|
|
|
|
import "github.com/smartystreets/goconvey/convey/reporting"
|
|
|
|
////////////////////////////////// suite //////////////////////////////////
|
|
|
|
// C is the Convey context which you can optionally obtain in your action
|
|
// by calling Convey like:
|
|
//
|
|
// Convey(..., func(c C) {
|
|
// ...
|
|
// })
|
|
//
|
|
// See the documentation on Convey for more details.
|
|
//
|
|
// All methods in this context behave identically to the global functions of the
|
|
// same name in this package.
|
|
type C interface {
|
|
Convey(items ...interface{})
|
|
SkipConvey(items ...interface{})
|
|
FocusConvey(items ...interface{})
|
|
|
|
So(actual interface{}, assert assertion, expected ...interface{})
|
|
SkipSo(stuff ...interface{})
|
|
|
|
Reset(action func())
|
|
|
|
Println(items ...interface{}) (int, error)
|
|
Print(items ...interface{}) (int, error)
|
|
Printf(format string, items ...interface{}) (int, error)
|
|
}
|
|
|
|
// Convey is the method intended for use when declaring the scopes of
|
|
// a specification. Each scope has a description and a func() which may contain
|
|
// other calls to Convey(), Reset() or Should-style assertions. Convey calls can
|
|
// be nested as far as you see fit.
|
|
//
|
|
// IMPORTANT NOTE: The top-level Convey() within a Test method
|
|
// must conform to the following signature:
|
|
//
|
|
// Convey(description string, t *testing.T, action func())
|
|
//
|
|
// All other calls should look like this (no need to pass in *testing.T):
|
|
//
|
|
// Convey(description string, action func())
|
|
//
|
|
// Don't worry, goconvey will panic if you get it wrong so you can fix it.
|
|
//
|
|
// Additionally, you may explicitly obtain access to the Convey context by doing:
|
|
//
|
|
// Convey(description string, action func(c C))
|
|
//
|
|
// You may need to do this if you want to pass the context through to a
|
|
// goroutine, or to close over the context in a handler to a library which
|
|
// calls your handler in a goroutine (httptest comes to mind).
|
|
//
|
|
// All Convey()-blocks also accept an optional parameter of FailureMode which sets
|
|
// how goconvey should treat failures for So()-assertions in the block and
|
|
// nested blocks. See the constants in this file for the available options.
|
|
//
|
|
// By default it will inherit from its parent block and the top-level blocks
|
|
// default to the FailureHalts setting.
|
|
//
|
|
// This parameter is inserted before the block itself:
|
|
//
|
|
// Convey(description string, t *testing.T, mode FailureMode, action func())
|
|
// Convey(description string, mode FailureMode, action func())
|
|
//
|
|
// See the examples package for, well, examples.
|
|
func Convey(items ...interface{}) {
|
|
if ctx := getCurrentContext(); ctx == nil {
|
|
rootConvey(items...)
|
|
} else {
|
|
ctx.Convey(items...)
|
|
}
|
|
}
|
|
|
|
// SkipConvey is analagous to Convey except that the scope is not executed
|
|
// (which means that child scopes defined within this scope are not run either).
|
|
// The reporter will be notified that this step was skipped.
|
|
func SkipConvey(items ...interface{}) {
|
|
Convey(append(items, skipConvey)...)
|
|
}
|
|
|
|
// FocusConvey is has the inverse effect of SkipConvey. If the top-level
|
|
// Convey is changed to `FocusConvey`, only nested scopes that are defined
|
|
// with FocusConvey will be run. The rest will be ignored completely. This
|
|
// is handy when debugging a large suite that runs a misbehaving function
|
|
// repeatedly as you can disable all but one of that function
|
|
// without swaths of `SkipConvey` calls, just a targeted chain of calls
|
|
// to FocusConvey.
|
|
func FocusConvey(items ...interface{}) {
|
|
Convey(append(items, focusConvey)...)
|
|
}
|
|
|
|
// Reset registers a cleanup function to be run after each Convey()
|
|
// in the same scope. See the examples package for a simple use case.
|
|
func Reset(action func()) {
|
|
mustGetCurrentContext().Reset(action)
|
|
}
|
|
|
|
/////////////////////////////////// Assertions ///////////////////////////////////
|
|
|
|
// assertion is an alias for a function with a signature that the convey.So()
|
|
// method can handle. Any future or custom assertions should conform to this
|
|
// method signature. The return value should be an empty string if the assertion
|
|
// passes and a well-formed failure message if not.
|
|
type assertion func(actual interface{}, expected ...interface{}) string
|
|
|
|
const assertionSuccess = ""
|
|
|
|
// So is the means by which assertions are made against the system under test.
|
|
// The majority of exported names in the assertions package begin with the word
|
|
// 'Should' and describe how the first argument (actual) should compare with any
|
|
// of the final (expected) arguments. How many final arguments are accepted
|
|
// depends on the particular assertion that is passed in as the assert argument.
|
|
// See the examples package for use cases and the assertions package for
|
|
// documentation on specific assertion methods. A failing assertion will
|
|
// cause t.Fail() to be invoked--you should never call this method (or other
|
|
// failure-inducing methods) in your test code. Leave that to GoConvey.
|
|
func So(actual interface{}, assert assertion, expected ...interface{}) {
|
|
mustGetCurrentContext().So(actual, assert, expected...)
|
|
}
|
|
|
|
// SkipSo is analagous to So except that the assertion that would have been passed
|
|
// to So is not executed and the reporter is notified that the assertion was skipped.
|
|
func SkipSo(stuff ...interface{}) {
|
|
mustGetCurrentContext().SkipSo()
|
|
}
|
|
|
|
// FailureMode is a type which determines how the So() blocks should fail
|
|
// if their assertion fails. See constants further down for acceptable values
|
|
type FailureMode string
|
|
|
|
const (
|
|
|
|
// FailureContinues is a failure mode which prevents failing
|
|
// So()-assertions from halting Convey-block execution, instead
|
|
// allowing the test to continue past failing So()-assertions.
|
|
FailureContinues FailureMode = "continue"
|
|
|
|
// FailureHalts is the default setting for a top-level Convey()-block
|
|
// and will cause all failing So()-assertions to halt further execution
|
|
// in that test-arm and continue on to the next arm.
|
|
FailureHalts FailureMode = "halt"
|
|
|
|
// FailureInherits is the default setting for failure-mode, it will
|
|
// default to the failure-mode of the parent block. You should never
|
|
// need to specify this mode in your tests..
|
|
FailureInherits FailureMode = "inherits"
|
|
)
|
|
|
|
func (f FailureMode) combine(other FailureMode) FailureMode {
|
|
if other == FailureInherits {
|
|
return f
|
|
}
|
|
return other
|
|
}
|
|
|
|
var defaultFailureMode FailureMode = FailureHalts
|
|
|
|
// SetDefaultFailureMode allows you to specify the default failure mode
|
|
// for all Convey blocks. It is meant to be used in an init function to
|
|
// allow the default mode to be changdd across all tests for an entire packgae
|
|
// but it can be used anywhere.
|
|
func SetDefaultFailureMode(mode FailureMode) {
|
|
if mode == FailureContinues || mode == FailureHalts {
|
|
defaultFailureMode = mode
|
|
} else {
|
|
panic("You may only use the constants named 'FailureContinues' and 'FailureHalts' as default failure modes.")
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////// Print functions ////////////////////////////////////
|
|
|
|
// Print is analogous to fmt.Print (and it even calls fmt.Print). It ensures that
|
|
// output is aligned with the corresponding scopes in the web UI.
|
|
func Print(items ...interface{}) (written int, err error) {
|
|
return mustGetCurrentContext().Print(items...)
|
|
}
|
|
|
|
// Print is analogous to fmt.Println (and it even calls fmt.Println). It ensures that
|
|
// output is aligned with the corresponding scopes in the web UI.
|
|
func Println(items ...interface{}) (written int, err error) {
|
|
return mustGetCurrentContext().Println(items...)
|
|
}
|
|
|
|
// Print is analogous to fmt.Printf (and it even calls fmt.Printf). It ensures that
|
|
// output is aligned with the corresponding scopes in the web UI.
|
|
func Printf(format string, items ...interface{}) (written int, err error) {
|
|
return mustGetCurrentContext().Printf(format, items...)
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// SuppressConsoleStatistics prevents automatic printing of console statistics.
|
|
// Calling PrintConsoleStatistics explicitly will force printing of statistics.
|
|
func SuppressConsoleStatistics() {
|
|
reporting.SuppressConsoleStatistics()
|
|
}
|
|
|
|
// ConsoleStatistics may be called at any time to print assertion statistics.
|
|
// Generally, the best place to do this would be in a TestMain function,
|
|
// after all tests have been run. Something like this:
|
|
//
|
|
// func TestMain(m *testing.M) {
|
|
// convey.SuppressConsoleStatistics()
|
|
// result := m.Run()
|
|
// convey.PrintConsoleStatistics()
|
|
// os.Exit(result)
|
|
// }
|
|
//
|
|
func PrintConsoleStatistics() {
|
|
reporting.PrintConsoleStatistics()
|
|
}
|
|
|