aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/testing/testing.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/testing/testing.go')
-rw-r--r--libgo/go/testing/testing.go105
1 files changed, 93 insertions, 12 deletions
diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go
index 6ab9b79..e05314e 100644
--- a/libgo/go/testing/testing.go
+++ b/libgo/go/testing/testing.go
@@ -99,7 +99,7 @@
// line order:
//
// func ExamplePerm() {
-// for _, value := range Perm(4) {
+// for _, value := range Perm(5) {
// fmt.Println(value)
// }
// // Unordered output: 4
@@ -344,6 +344,7 @@ type common struct {
skipped bool // Test of benchmark has been skipped.
done bool // Test is finished and all subtests have completed.
helpers map[string]struct{} // functions to be skipped when writing file/line info
+ cleanup func() // optional function to be called at the end of the test
chatty bool // A copy of the chatty flag.
finished bool // Test function has completed.
@@ -479,6 +480,9 @@ func (c *common) decorate(s string, skip int) string {
buf := new(strings.Builder)
// Every line is indented at least 4 spaces.
buf.WriteString(" ")
+ if c.chatty {
+ fmt.Fprintf(buf, "%s: ", c.name)
+ }
fmt.Fprintf(buf, "%s:%d: ", file, line)
lines := strings.Split(s, "\n")
if l := len(lines); l > 1 && lines[l-1] == "" {
@@ -540,6 +544,7 @@ func fmtDuration(d time.Duration) string {
// TB is the interface common to T and B.
type TB interface {
+ Cleanup(func())
Error(args ...interface{})
Errorf(format string, args ...interface{})
Fail()
@@ -547,6 +552,7 @@ type TB interface {
Failed() bool
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
+ Helper()
Log(args ...interface{})
Logf(format string, args ...interface{})
Name() string
@@ -554,7 +560,6 @@ type TB interface {
SkipNow()
Skipf(format string, args ...interface{})
Skipped() bool
- Helper()
// A private method to prevent users implementing the
// interface and so future additions to it will not
@@ -662,9 +667,7 @@ func (c *common) log(s string) {
func (c *common) logDepth(s string, depth int) {
c.mu.Lock()
defer c.mu.Unlock()
- if !c.done {
- c.output = append(c.output, c.decorate(s, depth+1)...)
- } else {
+ if c.done {
// This test has already finished. Try and log this message
// with our parent. If we don't have a parent, panic.
for parent := c.parent; parent != nil; parent = parent.parent {
@@ -676,9 +679,21 @@ func (c *common) logDepth(s string, depth int) {
}
}
panic("Log in goroutine after " + c.name + " has completed")
+ } else {
+ if c.chatty {
+ fmt.Print(c.decorate(s, depth+1))
+ return
+ }
+ c.output = append(c.output, c.decorate(s, depth+1)...)
}
}
+// This is needed for gccgo to get the tests to pass, because
+// runtime.Callers doesn't correctly handle skips that land in the
+// middle of a sequence of inlined functions.
+// This shouldn't make any difference for normal use.
+//go:noinline
+
// Log formats its arguments using default formatting, analogous to Println,
// and records the text in the error log. For tests, the text will be printed only if
// the test fails or the -test.v flag is set. For benchmarks, the text is always
@@ -692,30 +707,60 @@ func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
// depend on the value of the -test.v flag.
func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
+// This is needed for gccgo to get the tests to pass, because
+// runtime.Callers doesn't correctly handle skips that land in the
+// middle of a sequence of inlined functions.
+// This shouldn't make any difference for normal use.
+//go:noinline
+
// Error is equivalent to Log followed by Fail.
func (c *common) Error(args ...interface{}) {
c.log(fmt.Sprintln(args...))
c.Fail()
}
+// This is needed for gccgo to get the tests to pass, because
+// runtime.Callers doesn't correctly handle skips that land in the
+// middle of a sequence of inlined functions.
+// This shouldn't make any difference for normal use.
+//go:noinline
+
// Errorf is equivalent to Logf followed by Fail.
func (c *common) Errorf(format string, args ...interface{}) {
c.log(fmt.Sprintf(format, args...))
c.Fail()
}
+// This is needed for gccgo to get the tests to pass, because
+// runtime.Callers doesn't correctly handle skips that land in the
+// middle of a sequence of inlined functions.
+// This shouldn't make any difference for normal use.
+//go:noinline
+
// Fatal is equivalent to Log followed by FailNow.
func (c *common) Fatal(args ...interface{}) {
c.log(fmt.Sprintln(args...))
c.FailNow()
}
+// This is needed for gccgo to get the tests to pass, because
+// runtime.Callers doesn't correctly handle skips that land in the
+// middle of a sequence of inlined functions.
+// This shouldn't make any difference for normal use.
+//go:noinline
+
// Fatalf is equivalent to Logf followed by FailNow.
func (c *common) Fatalf(format string, args ...interface{}) {
c.log(fmt.Sprintf(format, args...))
c.FailNow()
}
+// This is needed for gccgo to get the tests to pass, because
+// runtime.Callers doesn't correctly handle skips that land in the
+// middle of a sequence of inlined functions.
+// This shouldn't make any difference for normal use.
+//go:noinline
+
// Skip is equivalent to Log followed by SkipNow.
func (c *common) Skip(args ...interface{}) {
c.log(fmt.Sprintln(args...))
@@ -767,11 +812,37 @@ func (c *common) Helper() {
c.helpers[callerName(1)] = struct{}{}
}
+// Cleanup registers a function to be called when the test finishes.
+// Cleanup functions will be called in last added, first called
+// order.
+func (c *common) Cleanup(f func()) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ oldCleanup := c.cleanup
+ c.cleanup = func() {
+ if oldCleanup != nil {
+ defer oldCleanup()
+ }
+ f()
+ }
+}
+
+// runCleanup is called at the end of the test.
+func (c *common) runCleanup() {
+ c.mu.Lock()
+ cleanup := c.cleanup
+ c.cleanup = nil
+ c.mu.Unlock()
+ if cleanup != nil {
+ cleanup()
+ }
+}
+
// callerName gives the function name (qualified with a package path)
// for the caller after skip frames (where 0 means the current function).
func callerName(skip int) string {
// Make room for the skip PC.
- var pc [1]uintptr
+ var pc [2]uintptr
n := runtime.Callers(skip+2, pc[:]) // skip + runtime.Callers + callerName
if n == 0 {
panic("testing: zero callers found")
@@ -828,8 +899,8 @@ func (t *T) Parallel() {
t.raceErrors += -race.Errors()
}
-// An internal type but exported because it is cross-package; part of the implementation
-// of the "go test" command.
+// InternalTest is an internal type but exported because it is cross-package;
+// it is part of the implementation of the "go test" command.
type InternalTest struct {
Name string
F func(*T)
@@ -853,7 +924,6 @@ func tRunner(t *T, fn func(t *T)) {
t.Errorf("race detected during execution of test")
}
- t.duration += time.Since(t.start)
// If the test panicked, print any test output before dying.
err := recover()
signal := true
@@ -870,10 +940,20 @@ func tRunner(t *T, fn func(t *T)) {
}
if err != nil {
t.Fail()
- t.report()
+ // Flush the output log up to the root before dying.
+ t.mu.Lock()
+ root := &t.common
+ for ; root.parent != nil; root = root.parent {
+ root.duration += time.Since(root.start)
+ fmt.Fprintf(root.parent.w, "--- FAIL: %s (%s)\n", root.name, fmtDuration(root.duration))
+ root.parent.mu.Lock()
+ io.Copy(root.parent.w, bytes.NewReader(root.output))
+ }
panic(err)
}
+ t.duration += time.Since(t.start)
+
if len(t.sub) > 0 {
// Run parallel subtests.
// Decrease the running count for this test.
@@ -903,6 +983,7 @@ func tRunner(t *T, fn func(t *T)) {
}
t.signal <- signal
}()
+ defer t.runCleanup()
t.start = time.Now()
t.raceErrors = -race.Errors()
@@ -1169,8 +1250,8 @@ func listTests(matchString func(pat, str string) (bool, error), tests []Internal
}
}
-// An internal function but exported because it is cross-package; part of the implementation
-// of the "go test" command.
+// RunTests is an internal function but exported because it is cross-package;
+// it is part of the implementation of the "go test" command.
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
ran, ok := runTests(matchString, tests)
if !ran && !haveExamples {