Skip to content

Commit 59f309a

Browse files
suntalabritishrum
suntala
andcommitted
Add a new output writer and use it in t.Log
Co-authored-by: Aleks Fazlieva <[email protected]>
1 parent 608acff commit 59f309a

File tree

1 file changed

+97
-53
lines changed

1 file changed

+97
-53
lines changed

src/testing/testing.go

+97-53
Original file line numberDiff line numberDiff line change
@@ -797,44 +797,6 @@ func (c *common) frameSkip(skip int) runtime.Frame {
797797
return firstFrame
798798
}
799799

800-
// decorate prefixes the string with the file and line of the call site
801-
// and inserts the final newline if needed and indentation spaces for formatting.
802-
// This function must be called with c.mu held.
803-
func (c *common) decorate(s string, skip int) string {
804-
frame := c.frameSkip(skip)
805-
file := frame.File
806-
line := frame.Line
807-
if file != "" {
808-
if *fullPath {
809-
// If relative path, truncate file name at last file name separator.
810-
} else if index := strings.LastIndexAny(file, `/\`); index >= 0 {
811-
file = file[index+1:]
812-
}
813-
} else {
814-
file = "???"
815-
}
816-
if line == 0 {
817-
line = 1
818-
}
819-
buf := new(strings.Builder)
820-
// Every line is indented at least 4 spaces.
821-
buf.WriteString(" ")
822-
fmt.Fprintf(buf, "%s:%d: ", file, line)
823-
lines := strings.Split(s, "\n")
824-
if l := len(lines); l > 1 && lines[l-1] == "" {
825-
lines = lines[:l-1]
826-
}
827-
for i, line := range lines {
828-
if i > 0 {
829-
// Second and subsequent lines are indented an additional 4 spaces.
830-
buf.WriteString("\n ")
831-
}
832-
buf.WriteString(line)
833-
}
834-
buf.WriteByte('\n')
835-
return buf.String()
836-
}
837-
838800
// flushToParent writes c.output to the parent after first writing the header
839801
// with the given format and arguments.
840802
func (c *common) flushToParent(testName, format string, args ...any) {
@@ -1041,40 +1003,122 @@ func (c *common) FailNow() {
10411003
runtime.Goexit()
10421004
}
10431005

1044-
// log generates the output. It's always at the same stack depth.
1006+
// log generates the output. It is always at the same stack depth. It inserts
1007+
// the final newline if necessary.
10451008
func (c *common) log(s string) {
1046-
c.logDepth(s, 3) // logDepth + log + public function
1009+
if l := len(s); l > 0 && (string(s[l-1]) != "\n") {
1010+
s += "\n"
1011+
}
1012+
cs := c.getCallSite(3) // getCallSite + log + public function
1013+
c.newOutputWriter(cs).Write([]byte(s))
10471014
}
10481015

1049-
// logDepth generates the output at an arbitrary stack depth.
1050-
func (c *common) logDepth(s string, depth int) {
1016+
// getCallSite retrieves and formats the file and line of the call site.
1017+
func (c *common) getCallSite(skip int) string {
10511018
c.mu.Lock()
10521019
defer c.mu.Unlock()
1053-
if c.done {
1020+
1021+
frame := c.frameSkip(skip)
1022+
file := frame.File
1023+
line := frame.Line
1024+
if file != "" {
1025+
if *fullPath {
1026+
// If relative path, truncate file name at last file name separator.
1027+
} else if index := strings.LastIndexAny(file, `/\`); index >= 0 {
1028+
file = file[index+1:]
1029+
}
1030+
} else {
1031+
file = "???"
1032+
}
1033+
if line == 0 {
1034+
line = 1
1035+
}
1036+
1037+
return fmt.Sprintf("%s:%d: ", file, line)
1038+
}
1039+
1040+
// newOutputWriter initialises a new outputWriter with the provided call site.
1041+
func (c *common) newOutputWriter(cs string) io.Writer {
1042+
b := make([]byte, 0)
1043+
return &outputWriter{c, b, cs}
1044+
}
1045+
1046+
// outputWriter buffers, formats and writes input.
1047+
type outputWriter struct {
1048+
c *common
1049+
b []byte // Stores incomplete input between writes.
1050+
cs string // Call site.
1051+
}
1052+
1053+
// Write generates the output. It prefixes the string with the file and line of
1054+
// the call site if provided. It inserts indentation spaces for formatting. It
1055+
// stores input for later if it is not terminated by a newline.
1056+
func (o *outputWriter) Write(p []byte) (int, error) {
1057+
o.b = append(o.b, p...)
1058+
1059+
o.c.mu.Lock()
1060+
defer o.c.mu.Unlock()
1061+
1062+
lines := strings.Split(string(o.b), "\n")
1063+
1064+
for i, line := range lines {
1065+
l := len(lines)
1066+
// If the last line is not empty, store it in the buffer.
1067+
if i == (l-1) && line != "" {
1068+
o.b = []byte(line)
1069+
if i > 0 {
1070+
o.writeLine("\n", p)
1071+
}
1072+
break
1073+
}
1074+
1075+
buf := new(strings.Builder)
1076+
// The first line is indented 4 spaces. Subsequent lines are
1077+
// indented 8 spaces unless a line is the final one and
1078+
// is empty.
1079+
if i == 0 {
1080+
buf.WriteString(" ")
1081+
buf.WriteString(o.cs)
1082+
} else if i < l-1 {
1083+
buf.WriteString("\n ")
1084+
} else {
1085+
// The final line must be empty otherwise the loop would have
1086+
// terminated earlier.
1087+
buf.WriteString("\n")
1088+
}
1089+
buf.WriteString(line)
1090+
1091+
o.writeLine(buf.String(), p)
1092+
}
1093+
return len(p), nil
1094+
}
1095+
1096+
// writeLine generates the output for a given line.
1097+
func (o *outputWriter) writeLine(s string, p []byte) {
1098+
if o.c.done {
10541099
// This test has already finished. Try and log this message
10551100
// with our parent. If we don't have a parent, panic.
1056-
for parent := c.parent; parent != nil; parent = parent.parent {
1101+
for parent := o.c.parent; parent != nil; parent = parent.parent {
10571102
parent.mu.Lock()
10581103
defer parent.mu.Unlock()
10591104
if !parent.done {
1060-
parent.output = append(parent.output, parent.decorate(s, depth+1)...)
1105+
parent.output = append(parent.output, s...)
10611106
return
10621107
}
10631108
}
1064-
panic("Log in goroutine after " + c.name + " has completed: " + s)
1109+
panic("Log in goroutine after " + o.c.name + " has completed: " + string(p))
10651110
} else {
1066-
if c.chatty != nil {
1067-
if c.bench {
1111+
if o.c.chatty != nil {
1112+
if o.c.bench {
10681113
// Benchmarks don't print === CONT, so we should skip the test
10691114
// printer and just print straight to stdout.
1070-
fmt.Print(c.decorate(s, depth+1))
1115+
fmt.Print(s)
10711116
} else {
1072-
c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1))
1117+
o.c.chatty.Printf(o.c.name, "%s", s)
10731118
}
1074-
1075-
return
1119+
} else {
1120+
o.c.output = append(o.c.output, s...)
10761121
}
1077-
c.output = append(c.output, c.decorate(s, depth+1)...)
10781122
}
10791123
}
10801124

0 commit comments

Comments
 (0)