- Use a bytes.Buffer for the log now.
- Anything logged within SetUpTest() will show up in a failed test
output as well.
diff --git a/fixture_test.go b/fixture_test.go
index ffc3110..0c8a0d2 100644
--- a/fixture_test.go
+++ b/fixture_test.go
@@ -424,3 +424,38 @@
"\\.+ Expected \\(bool\\): true\n\n")
c.Assert(helper.completed, Equals, false)
}
+
+
+// -----------------------------------------------------------------------
+// Verify that logging within SetUpTest() persists within the test log itself.
+
+type FixtureLogHelper struct {
+ c *C
+}
+
+func (s *FixtureLogHelper) SetUpTest(c *C) {
+ s.c = c
+ c.Log("1")
+}
+
+func (s *FixtureLogHelper) Test(c *C) {
+ c.Log("2")
+ s.c.Log("3")
+ c.Log("4")
+ c.Fail()
+}
+
+func (s *FixtureLogHelper) TearDownTest(c *C) {
+ s.c.Log("5")
+}
+
+func (s *FixtureS) TestFixtureLogging(c *C) {
+ helper := FixtureLogHelper{}
+ output := String{}
+ Run(&helper, &RunConf{Output: &output})
+ c.Assert(output.value, Matches,
+ "\n---+\n" +
+ "FAIL: fixture_test\\.go:[0-9]+: " +
+ "FixtureLogHelper\\.Test\n\n" +
+ "1\n2\n3\n4\n5\n")
+}
diff --git a/gocheck.go b/gocheck.go
index 60bc1bc..a54fd14 100644
--- a/gocheck.go
+++ b/gocheck.go
@@ -6,6 +6,7 @@
"strings"
"strconv"
"regexp"
+ "bytes"
"path"
"sync"
"rand"
@@ -41,14 +42,19 @@
method *reflect.FuncValue
kind funcKind
status funcStatus
- logv string
+ logb *bytes.Buffer
done chan *C
expectedFailure *string
tempDir *tempDir
}
-func newC(method *reflect.FuncValue, kind funcKind, tempDir *tempDir) *C {
- return &C{method:method, kind:kind, tempDir:tempDir, done:make(chan *C, 1)}
+func newC(method *reflect.FuncValue, kind funcKind, logb *bytes.Buffer,
+ tempDir *tempDir) *C {
+ if logb == nil {
+ logb = bytes.NewBuffer(nil)
+ }
+ return &C{method:method, kind:kind, logb:logb,
+ tempDir:tempDir, done:make(chan *C, 1)}
}
func (c *C) stopNow() {
@@ -113,15 +119,17 @@
// Low-level logging functions.
func (c *C) log(args ...interface{}) {
- c.logv += fmt.Sprint(args...) + "\n"
+ c.logb.WriteString(fmt.Sprint(args...))
+ c.logb.WriteByte('\n')
}
func (c *C) logf(format string, args ...interface{}) {
- c.logv += fmt.Sprintf(format, args...) + "\n"
+ c.logb.WriteString(fmt.Sprintf(format, args...))
+ c.logb.WriteByte('\n')
}
func (c *C) logNewLine() {
- c.logv += "\n"
+ c.logb.WriteByte('\n')
}
type hasString interface {
@@ -378,7 +386,7 @@
"%s: %s: %s\n\n",
label, niceFuncPath(pc), niceFuncName(pc))
io.WriteString(tracker.writer, header)
- io.WriteString(tracker.writer, c.logv)
+ c.logb.WriteTo(tracker.writer)
}
@@ -496,7 +504,8 @@
if runner.tracker.result.RunError == nil && len(runner.tests) > 0 {
runner.tracker.start()
if runner.checkFixtureArgs() {
- if runner.runFixture(runner.setUpSuite) {
+ c := runner.runFixture(runner.setUpSuite, nil)
+ if c == nil || c.status == succeededSt {
for i := 0; i != len(runner.tests); i++ {
c := runner.runTest(runner.tests[i])
if c.status == fixturePanickedSt {
@@ -507,7 +516,7 @@
} else {
runner.missTests(runner.tests)
}
- runner.runFixture(runner.tearDownSuite)
+ runner.runFixture(runner.tearDownSuite, nil)
} else {
runner.missTests(runner.tests)
}
@@ -521,8 +530,9 @@
// Create a call object with the given suite method, and fork a
// goroutine with the provided dispatcher for running it.
func (runner *suiteRunner) forkCall(method *reflect.FuncValue, kind funcKind,
+ logb *bytes.Buffer,
dispatcher func(c *C)) *C {
- c := newC(method, kind, runner.tempDir)
+ c := newC(method, kind, logb, runner.tempDir)
runner.tracker.waitForCall(c)
go (func() {
defer runner.callDone(c)
@@ -533,8 +543,9 @@
// Same as forkCall(), but wait for call to finish before returning.
func (runner *suiteRunner) runFunc(method *reflect.FuncValue, kind funcKind,
+ logb *bytes.Buffer,
dispatcher func(c *C)) *C {
- c := runner.forkCall(method, kind, dispatcher)
+ c := runner.forkCall(method, kind, logb, dispatcher)
<-c.done
return c
}
@@ -561,23 +572,27 @@
// goroutine like all suite methods, but this method will not return
// while the fixture goroutine is not done, because the fixture must be
// run in a desired order.
-func (runner *suiteRunner) runFixture(method *reflect.FuncValue) bool {
+func (runner *suiteRunner) runFixture(method *reflect.FuncValue,
+ logb *bytes.Buffer) *C {
if method != nil {
- c := runner.runFunc(method, fixtureKd, func(c *C) {
+ c := runner.runFunc(method, fixtureKd, logb, func(c *C) {
c.method.Call([]reflect.Value{reflect.NewValue(c)})
})
- return (c.status == succeededSt)
+ return c
}
- return true
+ return nil
}
// Run the fixture method with runFixture(), but panic with a fixturePanic{}
// in case the fixture method panics. This makes it easier to track the
// fixture panic together with other call panics within forkTest().
-func (runner *suiteRunner) runFixtureWithPanic(method *reflect.FuncValue) {
- if !runner.runFixture(method) {
+func (runner *suiteRunner) runFixtureWithPanic(method *reflect.FuncValue,
+ logb *bytes.Buffer) *C {
+ c := runner.runFixture(method, logb)
+ if c != nil && c.status != succeededSt {
panic(&fixturePanic{method})
}
+ return c
}
type fixturePanic struct {
@@ -587,9 +602,10 @@
// Run the suite test method, together with the test-specific fixture,
// asynchronously.
func (runner *suiteRunner) forkTest(method *reflect.FuncValue) *C {
- return runner.forkCall(method, testKd, func(c *C) {
- defer runner.runFixtureWithPanic(runner.tearDownTest)
- runner.runFixtureWithPanic(runner.setUpTest)
+ return runner.forkCall(method, testKd, nil, func(c *C) {
+ defer runner.runFixtureWithPanic(runner.tearDownTest, nil)
+ // Whatever is logged in SetUpTest persists in the test log itself.
+ runner.runFixtureWithPanic(runner.setUpTest, c.logb)
methodType := c.method.Type().(*reflect.FuncType)
if methodType.In(1) == reflect.Typeof(c) && methodType.NumIn() == 2 {
c.method.Call([]reflect.Value{reflect.NewValue(c)})
@@ -613,7 +629,7 @@
// enables homogeneous handling of tracking, including nice verbose output.
func (runner *suiteRunner) missTests(methods []*reflect.FuncValue) {
for _, method := range methods {
- runner.runFunc(method, testKd, func(c *C) {
+ runner.runFunc(method, testKd, nil, func(c *C) {
c.status = missedSt
})
}
@@ -632,7 +648,7 @@
fvType := fv.Type().(*reflect.FuncType)
if fvType.In(1) != argType || fvType.NumIn() != 2 {
succeeded = false
- runner.runFunc(fv, fixtureKd, func(c *C) {
+ runner.runFunc(fv, fixtureKd, nil, func(c *C) {
c.logArgPanic(fv, "*gocheck.C")
c.status = panickedSt
})
diff --git a/helpers.go b/helpers.go
index 73d20f5..be76484 100644
--- a/helpers.go
+++ b/helpers.go
@@ -63,7 +63,7 @@
// Return the current test error output.
func (c *C) GetTestLog() string {
- return c.logv
+ return c.logb.String()
}
// Log some information into the test error output. The provided arguments