From 2c39ca08cd6bb94b31ac6e15b0da33b345b62170 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 10 Nov 2011 11:59:50 -0800 Subject: [PATCH] testing: add file:line stamps to messages. A single-line error looks like this: --- FAIL: foo_test.TestFoo (0.00 seconds) foo_test.go:123: Foo(8) = "10" want "100" A multi-line error looks like this: --- FAIL: foo_test.TestFoo (0.00 seconds) foo_test.go:456: Foo(88) = "100" want "1000" R=rsc, bradfitz CC=golang-dev https://golang.org/cl/5376057 --- src/pkg/testing/testing.go | 41 ++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go index 5869642c7e..32c3fc3ad5 100644 --- a/src/pkg/testing/testing.go +++ b/src/pkg/testing/testing.go @@ -75,8 +75,25 @@ func Short() bool { return *short } -// Insert final newline if needed and tabs after internal newlines. -func tabify(s string) string { +// decorate inserts the a final newline if needed and indentation tabs for formatting. +// If addFileLine is true, it also prefixes the string with the file and line of the call site. +func decorate(s string, addFileLine bool) string { + if addFileLine { + _, file, line, ok := runtime.Caller(3) // decorate + log + public function. + if ok { + // Truncate file name at last file name separator. + if index := strings.LastIndex(file, "/"); index >= 0 { + file = file[index+1:] + } else if index = strings.LastIndex(file, "\\"); index >= 0 { + file = file[index+1:] + } + } else { + file = "???" + line = 1 + } + s = fmt.Sprintf("%s:%d: %s", file, line, s) + } + s = "\t" + s // Every line is indented at least one tab. n := len(s) if n > 0 && s[n-1] != '\n' { s += "\n" @@ -84,7 +101,8 @@ func tabify(s string) string { } for i := 0; i < n-1; i++ { // -1 to avoid final newline if s[i] == '\n' { - return s[0:i+1] + "\t" + tabify(s[i+1:n]) + // Second and subsequent lines are indented an extra tab. + return s[0:i+1] + "\t" + decorate(s[i+1:n], false) } } return s @@ -116,37 +134,38 @@ func (t *T) FailNow() { runtime.Goexit() } +// log generates the output. It's always at the same stack depth. +func (t *T) log(s string) { t.errors += decorate(s, true) } + // Log formats its arguments using default formatting, analogous to Print(), // and records the text in the error log. -func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) } +func (t *T) Log(args ...interface{}) { t.log(fmt.Sprintln(args...)) } // Logf formats its arguments according to the format, analogous to Printf(), // and records the text in the error log. -func (t *T) Logf(format string, args ...interface{}) { - t.errors += "\t" + tabify(fmt.Sprintf(format, args...)) -} +func (t *T) Logf(format string, args ...interface{}) { t.log(fmt.Sprintf(format, args...)) } // Error is equivalent to Log() followed by Fail(). func (t *T) Error(args ...interface{}) { - t.Log(args...) + t.log(fmt.Sprintln(args...)) t.Fail() } // Errorf is equivalent to Logf() followed by Fail(). func (t *T) Errorf(format string, args ...interface{}) { - t.Logf(format, args...) + t.log(fmt.Sprintf(format, args...)) t.Fail() } // Fatal is equivalent to Log() followed by FailNow(). func (t *T) Fatal(args ...interface{}) { - t.Log(args...) + t.log(fmt.Sprintln(args...)) t.FailNow() } // Fatalf is equivalent to Logf() followed by FailNow(). func (t *T) Fatalf(format string, args ...interface{}) { - t.Logf(format, args...) + t.log(fmt.Sprintf(format, args...)) t.FailNow() } -- 2.48.1