@@ -797,44 +797,6 @@ func (c *common) frameSkip(skip int) runtime.Frame {
797
797
return firstFrame
798
798
}
799
799
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
-
838
800
// flushToParent writes c.output to the parent after first writing the header
839
801
// with the given format and arguments.
840
802
func (c * common ) flushToParent (testName , format string , args ... any ) {
@@ -1041,40 +1003,122 @@ func (c *common) FailNow() {
1041
1003
runtime .Goexit ()
1042
1004
}
1043
1005
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.
1045
1008
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 ))
1047
1014
}
1048
1015
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 {
1051
1018
c .mu .Lock ()
1052
1019
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 {
1054
1099
// This test has already finished. Try and log this message
1055
1100
// 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 {
1057
1102
parent .mu .Lock ()
1058
1103
defer parent .mu .Unlock ()
1059
1104
if ! parent .done {
1060
- parent .output = append (parent .output , parent . decorate ( s , depth + 1 ) ... )
1105
+ parent .output = append (parent .output , s ... )
1061
1106
return
1062
1107
}
1063
1108
}
1064
- panic ("Log in goroutine after " + c .name + " has completed: " + s )
1109
+ panic ("Log in goroutine after " + o . c .name + " has completed: " + string ( p ) )
1065
1110
} else {
1066
- if c .chatty != nil {
1067
- if c .bench {
1111
+ if o . c .chatty != nil {
1112
+ if o . c .bench {
1068
1113
// Benchmarks don't print === CONT, so we should skip the test
1069
1114
// printer and just print straight to stdout.
1070
- fmt .Print (c . decorate ( s , depth + 1 ) )
1115
+ fmt .Print (s )
1071
1116
} else {
1072
- c .chatty .Printf (c .name , "%s" , c . decorate ( s , depth + 1 ) )
1117
+ o . c .chatty .Printf (o . c .name , "%s" , s )
1073
1118
}
1074
-
1075
- return
1119
+ } else {
1120
+ o . c . output = append ( o . c . output , s ... )
1076
1121
}
1077
- c .output = append (c .output , c .decorate (s , depth + 1 )... )
1078
1122
}
1079
1123
}
1080
1124
0 commit comments