blob: fe4ca516924f41d1c634fcd0766e5cfea14fa33b [file] [log] [blame]
package gocheck
import (
"fmt"
"strings"
"time"
)
// -----------------------------------------------------------------------
// Basic succeeding/failing logic.
// Return true if the currently running test has already failed.
func (c *C) Failed() bool {
return c.status == failedSt
}
// Mark the currently running test as failed. Something ought to have been
// previously logged so that the developer knows what went wrong. The higher
// level helper functions will fail the test and do the logging properly.
func (c *C) Fail() {
c.status = failedSt
}
// Mark the currently running test as failed, and stop running the test.
// Something ought to have been previously logged so that the developer
// knows what went wrong. The higher level helper functions will fail the
// test and do the logging properly.
func (c *C) FailNow() {
c.Fail()
c.stopNow()
}
// Mark the currently running test as succeeded, undoing any previous
// failures.
func (c *C) Succeed() {
c.status = succeededSt
}
// Mark the currently running test as succeeded, undoing any previous
// failures, and stop running the test.
func (c *C) SucceedNow() {
c.Succeed()
c.stopNow()
}
// Expect the currently running test to fail, for the given reason. If the
// test does not fail, an error will be reported to raise the attention to
// this fact. The reason string is just a summary of why the given test is
// supposed to fail. This method is useful to temporarily disable tests
// which cover well known problems until a better time to fix the problem
// is found, without forgetting about the fact that a failure still exists.
func (c *C) ExpectFailure(reason string) {
if reason == "" {
panic("Missing reason why the test is expected to fail")
}
c.mustFail = true
c.reason = reason
}
// Skip the running test, for the given reason. If used within SetUpTest,
// the individual test being set up will be skipped, and in SetUpSuite it
// will cause the whole suite to be skipped.
func (c *C) Skip(reason string) {
if reason == "" {
panic("Missing reason why the test is being skipped")
}
c.reason = reason
c.status = skippedSt
c.stopNow()
}
// -----------------------------------------------------------------------
// Basic logging.
// Return the current test error output.
func (c *C) GetTestLog() string {
return c.logb.String()
}
// Log some information into the test error output. The provided arguments
// will be assembled together into a string using fmt.Sprint().
func (c *C) Log(args ...interface{}) {
c.log(args...)
}
// Log some information into the test error output. The provided arguments
// will be assembled together into a string using fmt.Sprintf().
func (c *C) Logf(format string, args ...interface{}) {
c.logf(format, args...)
}
// Output enables *C to be used as a logger in functions that require only
// the minimum interface of *log.Logger.
func (c *C) Output(calldepth int, s string) error {
ns := time.Now().Sub(time.Time{}).Nanoseconds()
t := float64(ns%100e9) / 1e9
c.Logf("[LOG] %.05f %s", t, s)
return nil
}
// Log an error into the test error output, and mark the test as failed.
// The provided arguments will be assembled together into a string using
// fmt.Sprint().
func (c *C) Error(args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...)))
c.logNewLine()
c.Fail()
}
// Log an error into the test error output, and mark the test as failed.
// The provided arguments will be assembled together into a string using
// fmt.Sprintf().
func (c *C) Errorf(format string, args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprintf("Error: "+format, args...))
c.logNewLine()
c.Fail()
}
// Log an error into the test error output, mark the test as failed, and
// stop the test execution. The provided arguments will be assembled
// together into a string using fmt.Sprint().
func (c *C) Fatal(args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprint("Error: ", fmt.Sprint(args...)))
c.logNewLine()
c.FailNow()
}
// Log an error into the test error output, mark the test as failed, and
// stop the test execution. The provided arguments will be assembled
// together into a string using fmt.Sprintf().
func (c *C) Fatalf(format string, args ...interface{}) {
c.logCaller(1)
c.logString(fmt.Sprint("Error: ", fmt.Sprintf(format, args...)))
c.logNewLine()
c.FailNow()
}
// -----------------------------------------------------------------------
// Generic checks and assertions based on checkers.
// Verify if the first value matches with the expected value. What
// matching means is defined by the provided checker. In case they do not
// match, an error will be logged, the test will be marked as failed, and
// the test execution will continue. Some checkers may not need the expected
// argument (e.g. IsNil). In either case, any extra arguments provided to
// the function will be logged next to the reported problem when the
// matching fails. This is a handy way to provide problem-specific hints.
func (c *C) Check(obtained interface{}, checker Checker, args ...interface{}) bool {
return c.internalCheck("Check", obtained, checker, args...)
}
// Ensure that the first value matches with the expected value. What
// matching means is defined by the provided checker. In case they do not
// match, an error will be logged, the test will be marked as failed, and
// the test execution will stop. Some checkers may not need the expected
// argument (e.g. IsNil). In either case, any extra arguments provided to
// the function will be logged next to the reported problem when the
// matching fails. This is a handy way to provide problem-specific hints.
func (c *C) Assert(obtained interface{}, checker Checker, args ...interface{}) {
if !c.internalCheck("Assert", obtained, checker, args...) {
c.stopNow()
}
}
func (c *C) internalCheck(funcName string, obtained interface{}, checker Checker, args ...interface{}) bool {
if checker == nil {
c.logCaller(2)
c.logString(fmt.Sprintf("%s(obtained, nil!?, ...):", funcName))
c.logString("Oops.. you've provided a nil checker!")
c.logNewLine()
c.Fail()
return false
}
// If the last argument is a bug info, extract it out.
var comment CommentInterface
if len(args) > 0 {
if c, ok := args[len(args)-1].(CommentInterface); ok {
comment = c
args = args[:len(args)-1]
}
}
params := append([]interface{}{obtained}, args...)
info := checker.Info()
if len(params) != len(info.Params) {
names := append([]string{info.Params[0], info.Name}, info.Params[1:]...)
c.logCaller(2)
c.logString(fmt.Sprintf("%s(%s):", funcName, strings.Join(names, ", ")))
c.logString(fmt.Sprintf("Wrong number of parameters for %s: want %d, got %d", info.Name, len(names), len(params)+1))
c.logNewLine()
c.Fail()
return false
}
// Copy since it may be mutated by Check.
names := append([]string{}, info.Params...)
// Do the actual check.
result, error := checker.Check(params, names)
if !result || error != "" {
c.logCaller(2)
for i := 0; i != len(params); i++ {
c.logValue(names[i], params[i])
}
if comment != nil {
c.logString(comment.CheckCommentString())
}
if error != "" {
c.logString(error)
}
c.logNewLine()
c.Fail()
return false
}
return true
}