blob: a5fb5393328b0f0dc37266e85a0e2e36da415522 [file] [log] [blame]
/*
Gocheck - A rich testing framework for Go
Copyright (c) 2010, Gustavo Niemeyer <gustavo@niemeyer.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// This file contains just a few generic helpers which are used by the
// other test files.
//
// Tests are distributed the following way:
//
// gochecker_test.go: This file. Just generic helpers.
// bootstrap_test.go: Tests breaking the chicken and egg problem of
// testing a testing framework with itself.
// foundation_test.go: Tests ensuring that the basics are working.
// fixture_test.go: Tests for the fixture logic (SetUp*/TearDown*).
// helpers_test.go: Tests for helper methods in *gocheck.T.
package gocheck_test
import (
"gocheck"
gocheck_local "gocheck/local"
"testing"
"runtime"
"regexp"
"flag"
"fmt"
"os"
)
// We count the number of suites run at least to get a vague hint that the
// test suite is behaving as it should. Otherwise a bug introduced at the
// very core of the system could go unperceived.
const suitesRunExpected = 6
var suitesRun int = 0
func Test(t *testing.T) {
gocheck.TestingT(t)
if suitesRun != suitesRunExpected &&
flag.Lookup("f").Value.String() == "" {
critical(fmt.Sprintf("Expected %d suites to run rather than %d",
suitesRunExpected, suitesRun))
}
}
// -----------------------------------------------------------------------
// Helper functions.
// Break down badly. This is used in test cases which can't yet assume
// that the fundamental bits are working.
func critical(error string) {
fmt.Fprintln(os.Stderr, "CRITICAL: " + error)
os.Exit(1)
}
// Return the file line where it's called.
func getMyLine() int {
if _, _, line, ok := runtime.Caller(1); ok {
return line
}
return -1
}
// -----------------------------------------------------------------------
// Helper type implementing a basic io.Writer for testing output.
// Type implementing the io.Writer interface for analyzing output.
type String struct {
value string
}
// The only function required by the io.Writer interface. Will append
// written data to the String.value string.
func (s *String) Write(p []byte) (n int, err os.Error) {
s.value += string(p)
return len(p), nil
}
// Trivial wrapper to test errors happening on a different file
// than the test itself.
func checkEqualWrapper(c *gocheck.C,
expected interface{},
obtained interface{}) (result bool, line int) {
return c.Check(expected, gocheck_local.Equals, obtained), getMyLine()
}
// -----------------------------------------------------------------------
// Helper suite for testing basic fail behavior.
type FailHelper struct {
testLine int
}
func (s *FailHelper) TestLogAndFail(c *gocheck.C) {
s.testLine = getMyLine()-1
c.Log("Expected failure!")
c.Fail()
}
// -----------------------------------------------------------------------
// Helper suite for testing basic success behavior.
type SuccessHelper struct{}
func (s *SuccessHelper) TestLogAndSucceed(c *gocheck.C) {
c.Log("Expected success!")
}
// -----------------------------------------------------------------------
// Helper suite for testing ordering and behavior of fixture.
type FixtureHelper struct {
calls [64]string
n int
panicOn string
}
func (s *FixtureHelper) trace(name string) {
s.calls[s.n] = name
s.n += 1
if name == s.panicOn {
panic(name)
}
}
func (s *FixtureHelper) SetUpSuite(c *gocheck.C) {
s.trace("SetUpSuite")
}
func (s *FixtureHelper) TearDownSuite(c *gocheck.C) {
s.trace("TearDownSuite")
}
func (s *FixtureHelper) SetUpTest(c *gocheck.C) {
s.trace("SetUpTest")
}
func (s *FixtureHelper) TearDownTest(c *gocheck.C) {
s.trace("TearDownTest")
}
func (s *FixtureHelper) Test1(c *gocheck.C) {
s.trace("Test1")
}
func (s *FixtureHelper) Test2(c *gocheck.C) {
s.trace("Test2")
}
// -----------------------------------------------------------------------
// Helper which checks the state of the test and ensures that it matches
// the given expectations. Depends on c.Errorf() working, so shouldn't
// be used to test this one function.
type expectedState struct {
name string
result interface{}
failed bool
log string
}
// Verify the state of the test. Note that since this also verifies if
// the test is supposed to be in a failed state, no other checks should
// be done in addition to what is being tested.
func checkState(c *gocheck.C, result interface{}, expected *expectedState) {
failed := c.Failed()
c.Succeed()
log := c.GetTestLog()
matched, matchError := regexp.MatchString("^" + expected.log + "$", log)
if matchError != nil {
c.Errorf("Error in matching expression used in testing %s",
expected.name)
} else if !matched {
c.Errorf("%s logged %#v which doesn't match %#v",
expected.name, log, expected.log)
}
if result != expected.result {
c.Errorf("%s returned %#v rather than %#v",
expected.name, result, expected.result)
}
if failed != expected.failed {
if failed {
c.Errorf("%s has failed when it shouldn't", expected.name)
} else {
c.Errorf("%s has not failed when it should", expected.name)
}
}
}