aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/go/testdata/script/test_json_ascii.txt8
-rw-r--r--src/cmd/go/testdata/script/test_json_fails.txt18
-rw-r--r--src/cmd/go/testdata/script/test_json_issue35169.txt2
-rw-r--r--src/cmd/go/testdata/script/test_json_prints.txt8
-rw-r--r--src/cmd/internal/test2json/test2json.go85
-rw-r--r--src/cmd/internal/test2json/testdata/ascii.json6
-rw-r--r--src/cmd/internal/test2json/testdata/bench.json4
-rw-r--r--src/cmd/internal/test2json/testdata/benchfail.json6
-rw-r--r--src/cmd/internal/test2json/testdata/frame.json6
-rw-r--r--src/cmd/internal/test2json/testdata/framebig.json128
-rw-r--r--src/cmd/internal/test2json/testdata/frameescape.json141
-rw-r--r--src/cmd/internal/test2json/testdata/frameescape.testbin2573 -> 5484 bytes
-rw-r--r--src/cmd/internal/test2json/testdata/framefail.json11
-rw-r--r--src/cmd/internal/test2json/testdata/framefail.test8
-rw-r--r--src/cmd/internal/test2json/testdata/framefuzz.json48
-rw-r--r--src/cmd/internal/test2json/testdata/issue23036.json6
-rw-r--r--src/cmd/internal/test2json/testdata/issue23920.json14
-rw-r--r--src/cmd/internal/test2json/testdata/issue29755.json26
-rw-r--r--src/cmd/internal/test2json/testdata/panic.json6
-rw-r--r--src/cmd/internal/test2json/testdata/smiley.json170
-rw-r--r--src/cmd/internal/test2json/testdata/timeout.json6
-rw-r--r--src/cmd/internal/test2json/testdata/unicode.json6
-rw-r--r--src/cmd/internal/test2json/testdata/vet.json170
-rw-r--r--src/cmd/test2json/main.go9
-rw-r--r--src/testing/sub_test.go12
-rw-r--r--src/testing/testing.go133
26 files changed, 683 insertions, 354 deletions
diff --git a/src/cmd/go/testdata/script/test_json_ascii.txt b/src/cmd/go/testdata/script/test_json_ascii.txt
index 11eff970cd..8e2f3b6e6f 100644
--- a/src/cmd/go/testdata/script/test_json_ascii.txt
+++ b/src/cmd/go/testdata/script/test_json_ascii.txt
@@ -1,11 +1,11 @@
! go test -json
-stdout '"Action":"output","Package":"p","Test":"Test","Output":"=== RUN Test\\n"'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":"=== RUN Test\\n","OutputType":"frame"'
stdout '"Action":"output","Package":"p","Test":"Test","Output":" x_test.go:11: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n"}'
stdout '"Action":"output","Package":"p","Test":"Test","Output":" \\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\n"}'
-stdout '"Action":"output","Package":"p","Test":"Test","Output":" x_test.go:12: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n"'
-stdout '"Action":"output","Package":"p","Test":"Test","Output":" \\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\n"'
-stdout '"Action":"output","Package":"p","Test":"Test","Output":"--- FAIL: Test \([\d.]+s\)\\n"'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":" x_test.go:12: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n","OutputType":"error"'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":" \\u000b\\f\\r\\u000e\\u000f\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\\n","OutputType":"error-continue"'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":"--- FAIL: Test \([\d.]+s\)\\n","OutputType":"frame"'
-- go.mod --
module p
diff --git a/src/cmd/go/testdata/script/test_json_fails.txt b/src/cmd/go/testdata/script/test_json_fails.txt
new file mode 100644
index 0000000000..b996948d7a
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_json_fails.txt
@@ -0,0 +1,18 @@
+! go test -json
+
+stdout '"Action":"output","Package":"p","Test":"Test","Output":"=== RUN Test\\n","OutputType":"frame"'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":" x_test.go:6: Error1\\n","OutputType":"error"'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":" Error2\\n","OutputType":"error-continue"'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":"--- FAIL: Test \([\d.]+s\)\\n","OutputType":"frame"'
+
+-- go.mod --
+module p
+
+-- x_test.go --
+package p
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Error("Error1\nError2")
+}
diff --git a/src/cmd/go/testdata/script/test_json_issue35169.txt b/src/cmd/go/testdata/script/test_json_issue35169.txt
index fdb57556bd..4372d6ca17 100644
--- a/src/cmd/go/testdata/script/test_json_issue35169.txt
+++ b/src/cmd/go/testdata/script/test_json_issue35169.txt
@@ -12,7 +12,7 @@
! stdout '\{.*"Action":"pass".*\}'
# TODO(#62067): emit this as a build event instead of a test event.
-stdout '\{.*"Action":"output","Package":"example","Output":"FAIL\\texample \[build failed\]\\n"\}'
+stdout '\{.*"Action":"output","Package":"example","Output":"FAIL\\texample \[build failed\]\\n".*\}'
stdout '\{.*"Action":"fail","Package":"example",.*\}'
-- go.mod --
diff --git a/src/cmd/go/testdata/script/test_json_prints.txt b/src/cmd/go/testdata/script/test_json_prints.txt
index f979998068..f8bf88cee8 100644
--- a/src/cmd/go/testdata/script/test_json_prints.txt
+++ b/src/cmd/go/testdata/script/test_json_prints.txt
@@ -1,17 +1,17 @@
go test -json
stdout '"Action":"output","Package":"p","Output":"M1"}'
-stdout '"Action":"output","Package":"p","Test":"Test","Output":"=== RUN Test\\n"}'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":"=== RUN Test\\n","OutputType":"frame"}'
stdout '"Action":"output","Package":"p","Test":"Test","Output":"T1"}'
-stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"=== RUN Test/Sub1\\n"}'
+stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"=== RUN Test/Sub1\\n","OutputType":"frame"}'
stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"Sub1 x_test.go:19: SubLog1\\n"}'
stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"Sub2"}'
-stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"--- PASS: Test/Sub1 \([\d.]+s\)\\n"}'
+stdout '"Action":"output","Package":"p","Test":"Test/Sub1","Output":"--- PASS: Test/Sub1 \([\d.]+s\)\\n","OutputType":"frame"}'
stdout '"Action":"pass","Package":"p","Test":"Test/Sub1","Elapsed"'
stdout '"Action":"output","Package":"p","Test":"Test/Sub3","Output":"foo bar"}'
stdout '"Action":"output","Package":"p","Test":"Test/Sub3","Output":"baz\\n"}'
stdout '"Action":"output","Package":"p","Test":"Test","Output":"T2"}'
-stdout '"Action":"output","Package":"p","Test":"Test","Output":"--- PASS: Test \([\d.]+s\)\\n"}'
+stdout '"Action":"output","Package":"p","Test":"Test","Output":"--- PASS: Test \([\d.]+s\)\\n","OutputType":"frame"}'
stdout '"Action":"pass","Package":"p","Test":"Test","Elapsed"'
stdout '"Action":"output","Package":"p","Output":"M2ok \\tp\\t[\d.]+s\\n"}'
stdout '"Action":"pass","Package":"p","Elapsed"'
diff --git a/src/cmd/internal/test2json/test2json.go b/src/cmd/internal/test2json/test2json.go
index ec392f2dea..f8aa93f3bb 100644
--- a/src/cmd/internal/test2json/test2json.go
+++ b/src/cmd/internal/test2json/test2json.go
@@ -35,6 +35,7 @@ type event struct {
Test string `json:",omitempty"`
Elapsed *float64 `json:",omitempty"`
Output *textBytes `json:",omitempty"`
+ OutputType string `json:",omitempty"`
FailedBuild string `json:",omitempty"`
Key string `json:",omitempty"`
Value string `json:",omitempty"`
@@ -63,6 +64,7 @@ type Converter struct {
input lineBuffer // input buffer
output lineBuffer // output buffer
markFraming bool // require ^V marker to introduce test framing line
+ markErrEnd bool // within an error, require ^N marker to end
markEscape bool // the next character should be considered to be escaped
isFraming bool // indicates the output being written is framing
@@ -101,8 +103,12 @@ var (
//
// Writes on the returned writer are expected to contain markers. Test framing
// such as "=== RUN" and friends are expected to be prefixed with ^V (\x22).
-// Other occurrences of this control character (e.g. calls to T.Log) must be
-// escaped with ^[ (\x1b).
+// Error output is expected to be prefixed with ^O (\x0f) and suffixed with ^N
+// (\x0e). Other occurrences of these control characters (e.g. calls to T.Log)
+// must be escaped with ^[ (\x1b). Test framing will generate events such as
+// start, run, etc as well as output events with an output type of "frame".
+// Error output will generate output events with an output type of "error" or
+// "error-continue". See cmd/test2json help for details.
//
// The writes to w are whole JSON events ending in \n,
// so that it is safe to run multiple tests writing to multiple converters
@@ -163,8 +169,10 @@ func (c *Converter) SetFailedBuild(pkgID string) {
}
const (
- markFraming byte = 'V' &^ '@' // ^V: framing
- markEscape byte = '[' &^ '@' // ^[: escape
+ markFraming byte = 'V' &^ '@' // ^V: framing
+ markErrBegin byte = 'O' &^ '@' // ^O: start of error
+ markErrEnd byte = 'N' &^ '@' // ^N: end of error
+ markEscape byte = '[' &^ '@' // ^[: escape
)
var (
@@ -415,32 +423,91 @@ func (c *Converter) Close() error {
// writeOutputEvent writes a single output event with the given bytes.
func (c *Converter) writeOutputEvent(out []byte) {
+ var typ string
+ if c.isFraming {
+ typ = "frame"
+ } else if c.markErrEnd {
+ typ = "error-continue"
+ }
+
// Check for markers.
//
// An escape mark and the character it escapes may be passed in separate
// buffers. We must maintain state between calls to account for this, thus
// [Converter.markEscape] is set on one loop iteration and used to skip a
// character on the next.
+ //
+ // In most cases, [markErrBegin] will be the first character of a line and
+ // [markErrEnd] will be the last. However we cannot rely on that. For
+ // example, if a call to [T.Error] is preceded by a call to [fmt.Print] that
+ // does not print a newline. Thus we track the error status with
+ // [Converter.markErrEnd] and issue separate events if there is content
+ // before [markErrBegin] or after [markErrEnd].
for i := 0; i < len(out); i++ {
if c.markEscape {
c.markEscape = false
continue
}
- if out[i] == markEscape {
+ switch out[i] {
+ case markEscape:
// Elide the mark
out = append(out[:i], out[i+1:]...)
i--
// Skip the next character
c.markEscape = true
+
+ case markErrBegin:
+ // If there is content before the mark, emit it as a separate event
+ if i > 0 {
+ out2 := out[:i]
+ c.writeEvent(&event{
+ Action: "output",
+ Output: (*textBytes)(&out2),
+ OutputType: typ,
+ })
+ }
+
+ // Process the error
+ c.markErrEnd = true
+ typ = "error"
+ out = out[i+1:]
+ i = 0
+
+ case markErrEnd:
+ // Elide the mark
+ out = append(out[:i], out[i+1:]...)
+
+ // If the next character is \n, include it
+ if i < len(out) && out[i] == '\n' {
+ i++
+ }
+
+ // Emit the error
+ out2 := out[:i]
+ c.writeEvent(&event{
+ Action: "output",
+ Output: (*textBytes)(&out2),
+ OutputType: typ,
+ })
+
+ // Process the rest
+ c.markErrEnd = false
+ typ = ""
+ out = out[i:]
+ i = 0
}
}
- c.writeEvent(&event{
- Action: "output",
- Output: (*textBytes)(&out),
- })
+ // Send the remaining output
+ if len(out) > 0 {
+ c.writeEvent(&event{
+ Action: "output",
+ Output: (*textBytes)(&out),
+ OutputType: typ,
+ })
+ }
}
// writeEvent writes a single event.
diff --git a/src/cmd/internal/test2json/testdata/ascii.json b/src/cmd/internal/test2json/testdata/ascii.json
index 94695a10c5..3f3cf9e081 100644
--- a/src/cmd/internal/test2json/testdata/ascii.json
+++ b/src/cmd/internal/test2json/testdata/ascii.json
@@ -1,11 +1,11 @@
{"Action":"start"}
{"Action":"run","Test":"TestAscii"}
-{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n"}
+{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n","OutputType":"frame"}
{"Action":"output","Test":"TestAscii","Output":"I can eat glass, and it doesn't hurt me. I can eat glass, and it doesn't hurt me.\n"}
{"Action":"output","Test":"TestAscii","Output":"I CAN EAT GLASS, AND IT DOESN'T HURT ME. I CAN EAT GLASS, AND IT DOESN'T HURT ME.\n"}
-{"Action":"output","Test":"TestAscii","Output":"--- PASS: TestAscii\n"}
+{"Action":"output","Test":"TestAscii","Output":"--- PASS: TestAscii\n","OutputType":"frame"}
{"Action":"output","Test":"TestAscii","Output":" i can eat glass, and it doesn't hurt me. i can eat glass, and it doesn't hurt me.\n"}
{"Action":"output","Test":"TestAscii","Output":" V PNA RNG TYNFF, NAQ VG QBRFA'G UHEG ZR. V PNA RNG TYNFF, NAQ VG QBRFA'G UHEG ZR.\n"}
{"Action":"pass","Test":"TestAscii"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/bench.json b/src/cmd/internal/test2json/testdata/bench.json
index 102e189ed7..8981e42eb4 100644
--- a/src/cmd/internal/test2json/testdata/bench.json
+++ b/src/cmd/internal/test2json/testdata/bench.json
@@ -2,7 +2,7 @@
{"Action":"output","Output":"goos: darwin\n"}
{"Action":"output","Output":"goarch: 386\n"}
{"Action":"output","Output":"BenchmarkFoo-8 \t2000000000\t 0.00 ns/op\n"}
-{"Action":"output","Test":"BenchmarkFoo-8","Output":"--- BENCH: BenchmarkFoo-8\n"}
+{"Action":"output","Test":"BenchmarkFoo-8","Output":"--- BENCH: BenchmarkFoo-8\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
@@ -10,6 +10,6 @@
{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
{"Action":"output","Test":"BenchmarkFoo-8","Output":"\tx_test.go:8: My benchmark\n"}
{"Action":"bench","Test":"BenchmarkFoo-8"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"output","Output":"ok \tcommand-line-arguments\t0.009s\n"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/benchfail.json b/src/cmd/internal/test2json/testdata/benchfail.json
index d2d968191c..de5d8098e7 100644
--- a/src/cmd/internal/test2json/testdata/benchfail.json
+++ b/src/cmd/internal/test2json/testdata/benchfail.json
@@ -1,7 +1,7 @@
{"Action":"start"}
-{"Action":"output","Test":"BenchmarkFoo","Output":"--- FAIL: BenchmarkFoo\n"}
+{"Action":"output","Test":"BenchmarkFoo","Output":"--- FAIL: BenchmarkFoo\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkFoo","Output":"\tx_test.go:8: My benchmark\n"}
{"Action":"fail","Test":"BenchmarkFoo"}
-{"Action":"output","Output":"FAIL\n"}
-{"Action":"output","Output":"FAIL\tcommand-line-arguments\t0.008s\n"}
+{"Action":"output","Output":"FAIL\n","OutputType":"frame"}
+{"Action":"output","Output":"FAIL\tcommand-line-arguments\t0.008s\n","OutputType":"frame"}
{"Action":"fail"}
diff --git a/src/cmd/internal/test2json/testdata/frame.json b/src/cmd/internal/test2json/testdata/frame.json
index 9dd29ae977..fb87f5e44c 100644
--- a/src/cmd/internal/test2json/testdata/frame.json
+++ b/src/cmd/internal/test2json/testdata/frame.json
@@ -1,10 +1,10 @@
{"Action":"start"}
{"Action":"run","Test":"TestAscii"}
-{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n"}
+{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n","OutputType":"frame"}
{"Action":"output","Test":"TestAscii","Output":"=== RUN TestNotReally\n"}
-{"Action":"output","Test":"TestAscii","Output":"--- PASS: TestAscii\n"}
+{"Action":"output","Test":"TestAscii","Output":"--- PASS: TestAscii\n","OutputType":"frame"}
{"Action":"output","Test":"TestAscii","Output":" i can eat glass, and it doesn't hurt me. i can eat glass, and it doesn't hurt me.\n"}
{"Action":"output","Test":"TestAscii","Output":"FAIL\n"}
{"Action":"pass","Test":"TestAscii"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/framebig.json b/src/cmd/internal/test2json/testdata/framebig.json
index 54a8a524fe..d2b2b56fb3 100644
--- a/src/cmd/internal/test2json/testdata/framebig.json
+++ b/src/cmd/internal/test2json/testdata/framebig.json
@@ -1,168 +1,168 @@
{"Action":"start"}
{"Action":"run","Test":"TestIndex"}
-{"Action":"output","Test":"TestIndex","Output":"=== RUN TestIndex\n"}
-{"Action":"output","Test":"TestIndex","Output":"--- PASS: TestIndex (0.00s)\n"}
+{"Action":"output","Test":"TestIndex","Output":"=== RUN TestIndex\n","OutputType":"frame"}
+{"Action":"output","Test":"TestIndex","Output":"--- PASS: TestIndex (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestIndex"}
{"Action":"pass","Test":"TestIndex"}
-{"Action":"output","Test":"TestIndex","Output":"=== PASS TestIndex\n"}
+{"Action":"output","Test":"TestIndex","Output":"=== PASS TestIndex\n","OutputType":"frame"}
{"Action":"run","Test":"TestLastIndex"}
-{"Action":"output","Test":"TestLastIndex","Output":"=== RUN TestLastIndex\n"}
-{"Action":"output","Test":"TestLastIndex","Output":"--- PASS: TestLastIndex (0.00s)\n"}
+{"Action":"output","Test":"TestLastIndex","Output":"=== RUN TestLastIndex\n","OutputType":"frame"}
+{"Action":"output","Test":"TestLastIndex","Output":"--- PASS: TestLastIndex (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestLastIndex"}
{"Action":"pass","Test":"TestLastIndex"}
-{"Action":"output","Test":"TestLastIndex","Output":"=== PASS TestLastIndex\n"}
+{"Action":"output","Test":"TestLastIndex","Output":"=== PASS TestLastIndex\n","OutputType":"frame"}
{"Action":"run","Test":"TestIndexAny"}
-{"Action":"output","Test":"TestIndexAny","Output":"=== RUN TestIndexAny\n"}
-{"Action":"output","Test":"TestIndexAny","Output":"--- PASS: TestIndexAny (0.00s)\n"}
+{"Action":"output","Test":"TestIndexAny","Output":"=== RUN TestIndexAny\n","OutputType":"frame"}
+{"Action":"output","Test":"TestIndexAny","Output":"--- PASS: TestIndexAny (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestIndexAny"}
{"Action":"pass","Test":"TestIndexAny"}
-{"Action":"output","Test":"TestIndexAny","Output":"=== PASS TestIndexAny\n"}
+{"Action":"output","Test":"TestIndexAny","Output":"=== PASS TestIndexAny\n","OutputType":"frame"}
{"Action":"run","Test":"TestLastIndexAny"}
-{"Action":"output","Test":"TestLastIndexAny","Output":"=== RUN TestLastIndexAny\n"}
-{"Action":"output","Test":"TestLastIndexAny","Output":"--- PASS: TestLastIndexAny (0.00s)\n"}
+{"Action":"output","Test":"TestLastIndexAny","Output":"=== RUN TestLastIndexAny\n","OutputType":"frame"}
+{"Action":"output","Test":"TestLastIndexAny","Output":"--- PASS: TestLastIndexAny (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestLastIndexAny"}
{"Action":"pass","Test":"TestLastIndexAny"}
-{"Action":"output","Test":"TestLastIndexAny","Output":"=== PASS TestLastIndexAny\n"}
+{"Action":"output","Test":"TestLastIndexAny","Output":"=== PASS TestLastIndexAny\n","OutputType":"frame"}
{"Action":"run","Test":"TestIndexByte"}
-{"Action":"output","Test":"TestIndexByte","Output":"=== RUN TestIndexByte\n"}
-{"Action":"output","Test":"TestIndexByte","Output":"--- PASS: TestIndexByte (0.00s)\n"}
+{"Action":"output","Test":"TestIndexByte","Output":"=== RUN TestIndexByte\n","OutputType":"frame"}
+{"Action":"output","Test":"TestIndexByte","Output":"--- PASS: TestIndexByte (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestIndexByte"}
{"Action":"pass","Test":"TestIndexByte"}
-{"Action":"output","Test":"TestIndexByte","Output":"=== PASS TestIndexByte\n"}
+{"Action":"output","Test":"TestIndexByte","Output":"=== PASS TestIndexByte\n","OutputType":"frame"}
{"Action":"run","Test":"TestLastIndexByte"}
-{"Action":"output","Test":"TestLastIndexByte","Output":"=== RUN TestLastIndexByte\n"}
-{"Action":"output","Test":"TestLastIndexByte","Output":"--- PASS: TestLastIndexByte (0.00s)\n"}
+{"Action":"output","Test":"TestLastIndexByte","Output":"=== RUN TestLastIndexByte\n","OutputType":"frame"}
+{"Action":"output","Test":"TestLastIndexByte","Output":"--- PASS: TestLastIndexByte (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestLastIndexByte"}
{"Action":"pass","Test":"TestLastIndexByte"}
-{"Action":"output","Test":"TestLastIndexByte","Output":"=== PASS TestLastIndexByte\n"}
+{"Action":"output","Test":"TestLastIndexByte","Output":"=== PASS TestLastIndexByte\n","OutputType":"frame"}
{"Action":"run","Test":"TestIndexRandom"}
-{"Action":"output","Test":"TestIndexRandom","Output":"=== RUN TestIndexRandom\n"}
-{"Action":"output","Test":"TestIndexRandom","Output":"--- PASS: TestIndexRandom (0.00s)\n"}
+{"Action":"output","Test":"TestIndexRandom","Output":"=== RUN TestIndexRandom\n","OutputType":"frame"}
+{"Action":"output","Test":"TestIndexRandom","Output":"--- PASS: TestIndexRandom (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestIndexRandom"}
{"Action":"pass","Test":"TestIndexRandom"}
-{"Action":"output","Test":"TestIndexRandom","Output":"=== PASS TestIndexRandom\n"}
+{"Action":"output","Test":"TestIndexRandom","Output":"=== PASS TestIndexRandom\n","OutputType":"frame"}
{"Action":"run","Test":"TestIndexRune"}
-{"Action":"output","Test":"TestIndexRune","Output":"=== RUN TestIndexRune\n"}
-{"Action":"output","Test":"TestIndexRune","Output":"--- PASS: TestIndexRune (0.00s)\n"}
+{"Action":"output","Test":"TestIndexRune","Output":"=== RUN TestIndexRune\n","OutputType":"frame"}
+{"Action":"output","Test":"TestIndexRune","Output":"--- PASS: TestIndexRune (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestIndexRune"}
{"Action":"pass","Test":"TestIndexRune"}
-{"Action":"output","Test":"TestIndexRune","Output":"=== PASS TestIndexRune\n"}
+{"Action":"output","Test":"TestIndexRune","Output":"=== PASS TestIndexRune\n","OutputType":"frame"}
{"Action":"run","Test":"TestIndexFunc"}
-{"Action":"output","Test":"TestIndexFunc","Output":"=== RUN TestIndexFunc\n"}
-{"Action":"output","Test":"TestIndexFunc","Output":"--- PASS: TestIndexFunc (0.00s)\n"}
+{"Action":"output","Test":"TestIndexFunc","Output":"=== RUN TestIndexFunc\n","OutputType":"frame"}
+{"Action":"output","Test":"TestIndexFunc","Output":"--- PASS: TestIndexFunc (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestIndexFunc"}
{"Action":"pass","Test":"TestIndexFunc"}
-{"Action":"output","Test":"TestIndexFunc","Output":"=== PASS TestIndexFunc\n"}
+{"Action":"output","Test":"TestIndexFunc","Output":"=== PASS TestIndexFunc\n","OutputType":"frame"}
{"Action":"run","Test":"ExampleIndex"}
-{"Action":"output","Test":"ExampleIndex","Output":"=== RUN ExampleIndex\n"}
-{"Action":"output","Test":"ExampleIndex","Output":"--- PASS: ExampleIndex (0.00s)\n"}
+{"Action":"output","Test":"ExampleIndex","Output":"=== RUN ExampleIndex\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleIndex","Output":"--- PASS: ExampleIndex (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleIndex"}
{"Action":"run","Test":"ExampleIndexFunc"}
-{"Action":"output","Test":"ExampleIndexFunc","Output":"=== RUN ExampleIndexFunc\n"}
-{"Action":"output","Test":"ExampleIndexFunc","Output":"--- PASS: ExampleIndexFunc (0.00s)\n"}
+{"Action":"output","Test":"ExampleIndexFunc","Output":"=== RUN ExampleIndexFunc\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleIndexFunc","Output":"--- PASS: ExampleIndexFunc (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleIndexFunc"}
{"Action":"run","Test":"ExampleIndexAny"}
-{"Action":"output","Test":"ExampleIndexAny","Output":"=== RUN ExampleIndexAny\n"}
-{"Action":"output","Test":"ExampleIndexAny","Output":"--- PASS: ExampleIndexAny (0.00s)\n"}
+{"Action":"output","Test":"ExampleIndexAny","Output":"=== RUN ExampleIndexAny\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleIndexAny","Output":"--- PASS: ExampleIndexAny (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleIndexAny"}
{"Action":"run","Test":"ExampleIndexByte"}
-{"Action":"output","Test":"ExampleIndexByte","Output":"=== RUN ExampleIndexByte\n"}
-{"Action":"output","Test":"ExampleIndexByte","Output":"--- PASS: ExampleIndexByte (0.00s)\n"}
+{"Action":"output","Test":"ExampleIndexByte","Output":"=== RUN ExampleIndexByte\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleIndexByte","Output":"--- PASS: ExampleIndexByte (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleIndexByte"}
{"Action":"run","Test":"ExampleIndexRune"}
-{"Action":"output","Test":"ExampleIndexRune","Output":"=== RUN ExampleIndexRune\n"}
-{"Action":"output","Test":"ExampleIndexRune","Output":"--- PASS: ExampleIndexRune (0.00s)\n"}
+{"Action":"output","Test":"ExampleIndexRune","Output":"=== RUN ExampleIndexRune\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleIndexRune","Output":"--- PASS: ExampleIndexRune (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleIndexRune"}
{"Action":"run","Test":"ExampleLastIndex"}
-{"Action":"output","Test":"ExampleLastIndex","Output":"=== RUN ExampleLastIndex\n"}
-{"Action":"output","Test":"ExampleLastIndex","Output":"--- PASS: ExampleLastIndex (0.00s)\n"}
+{"Action":"output","Test":"ExampleLastIndex","Output":"=== RUN ExampleLastIndex\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleLastIndex","Output":"--- PASS: ExampleLastIndex (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleLastIndex"}
{"Action":"run","Test":"ExampleLastIndexAny"}
-{"Action":"output","Test":"ExampleLastIndexAny","Output":"=== RUN ExampleLastIndexAny\n"}
-{"Action":"output","Test":"ExampleLastIndexAny","Output":"--- PASS: ExampleLastIndexAny (0.00s)\n"}
+{"Action":"output","Test":"ExampleLastIndexAny","Output":"=== RUN ExampleLastIndexAny\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleLastIndexAny","Output":"--- PASS: ExampleLastIndexAny (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleLastIndexAny"}
{"Action":"run","Test":"ExampleLastIndexByte"}
-{"Action":"output","Test":"ExampleLastIndexByte","Output":"=== RUN ExampleLastIndexByte\n"}
-{"Action":"output","Test":"ExampleLastIndexByte","Output":"--- PASS: ExampleLastIndexByte (0.00s)\n"}
+{"Action":"output","Test":"ExampleLastIndexByte","Output":"=== RUN ExampleLastIndexByte\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleLastIndexByte","Output":"--- PASS: ExampleLastIndexByte (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleLastIndexByte"}
{"Action":"run","Test":"ExampleLastIndexFunc"}
-{"Action":"output","Test":"ExampleLastIndexFunc","Output":"=== RUN ExampleLastIndexFunc\n"}
-{"Action":"output","Test":"ExampleLastIndexFunc","Output":"--- PASS: ExampleLastIndexFunc (0.00s)\n"}
+{"Action":"output","Test":"ExampleLastIndexFunc","Output":"=== RUN ExampleLastIndexFunc\n","OutputType":"frame"}
+{"Action":"output","Test":"ExampleLastIndexFunc","Output":"--- PASS: ExampleLastIndexFunc (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"ExampleLastIndexFunc"}
{"Action":"output","Output":"goos: darwin\n"}
{"Action":"output","Output":"goarch: amd64\n"}
{"Action":"output","Output":"pkg: strings\n"}
{"Action":"output","Output":"cpu: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz\n"}
{"Action":"run","Test":"BenchmarkIndexRune"}
-{"Action":"output","Test":"BenchmarkIndexRune","Output":"=== RUN BenchmarkIndexRune\n"}
+{"Action":"output","Test":"BenchmarkIndexRune","Output":"=== RUN BenchmarkIndexRune\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexRune","Output":"BenchmarkIndexRune\n"}
{"Action":"output","Test":"BenchmarkIndexRune","Output":"BenchmarkIndexRune-16 \t87335496\t 14.27 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexRuneLongString"}
-{"Action":"output","Test":"BenchmarkIndexRuneLongString","Output":"=== RUN BenchmarkIndexRuneLongString\n"}
+{"Action":"output","Test":"BenchmarkIndexRuneLongString","Output":"=== RUN BenchmarkIndexRuneLongString\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexRuneLongString","Output":"BenchmarkIndexRuneLongString\n"}
{"Action":"output","Test":"BenchmarkIndexRuneLongString","Output":"BenchmarkIndexRuneLongString-16 \t57104472\t 18.66 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexRuneFastPath"}
-{"Action":"output","Test":"BenchmarkIndexRuneFastPath","Output":"=== RUN BenchmarkIndexRuneFastPath\n"}
+{"Action":"output","Test":"BenchmarkIndexRuneFastPath","Output":"=== RUN BenchmarkIndexRuneFastPath\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexRuneFastPath","Output":"BenchmarkIndexRuneFastPath\n"}
{"Action":"output","Test":"BenchmarkIndexRuneFastPath","Output":"BenchmarkIndexRuneFastPath-16 \t262380160\t 4.499 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndex"}
-{"Action":"output","Test":"BenchmarkIndex","Output":"=== RUN BenchmarkIndex\n"}
+{"Action":"output","Test":"BenchmarkIndex","Output":"=== RUN BenchmarkIndex\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndex","Output":"BenchmarkIndex\n"}
{"Action":"output","Test":"BenchmarkIndex","Output":"BenchmarkIndex-16 \t248529364\t 4.697 ns/op\n"}
{"Action":"run","Test":"BenchmarkLastIndex"}
-{"Action":"output","Test":"BenchmarkLastIndex","Output":"=== RUN BenchmarkLastIndex\n"}
+{"Action":"output","Test":"BenchmarkLastIndex","Output":"=== RUN BenchmarkLastIndex\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkLastIndex","Output":"BenchmarkLastIndex\n"}
{"Action":"output","Test":"BenchmarkLastIndex","Output":"BenchmarkLastIndex-16 \t293688756\t 4.166 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexByte"}
-{"Action":"output","Test":"BenchmarkIndexByte","Output":"=== RUN BenchmarkIndexByte\n"}
+{"Action":"output","Test":"BenchmarkIndexByte","Output":"=== RUN BenchmarkIndexByte\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexByte","Output":"BenchmarkIndexByte\n"}
{"Action":"output","Test":"BenchmarkIndexByte","Output":"BenchmarkIndexByte-16 \t310338391\t 3.608 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexHard1"}
-{"Action":"output","Test":"BenchmarkIndexHard1","Output":"=== RUN BenchmarkIndexHard1\n"}
+{"Action":"output","Test":"BenchmarkIndexHard1","Output":"=== RUN BenchmarkIndexHard1\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexHard1","Output":"BenchmarkIndexHard1\n"}
{"Action":"output","Test":"BenchmarkIndexHard1","Output":"BenchmarkIndexHard1-16 \t 12852\t 92380 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexHard2"}
-{"Action":"output","Test":"BenchmarkIndexHard2","Output":"=== RUN BenchmarkIndexHard2\n"}
+{"Action":"output","Test":"BenchmarkIndexHard2","Output":"=== RUN BenchmarkIndexHard2\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexHard2","Output":"BenchmarkIndexHard2\n"}
{"Action":"output","Test":"BenchmarkIndexHard2","Output":"BenchmarkIndexHard2-16 \t 8977\t 135080 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexHard3"}
-{"Action":"output","Test":"BenchmarkIndexHard3","Output":"=== RUN BenchmarkIndexHard3\n"}
+{"Action":"output","Test":"BenchmarkIndexHard3","Output":"=== RUN BenchmarkIndexHard3\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexHard3","Output":"BenchmarkIndexHard3\n"}
{"Action":"output","Test":"BenchmarkIndexHard3","Output":"BenchmarkIndexHard3-16 \t 1885\t 532079 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexHard4"}
-{"Action":"output","Test":"BenchmarkIndexHard4","Output":"=== RUN BenchmarkIndexHard4\n"}
+{"Action":"output","Test":"BenchmarkIndexHard4","Output":"=== RUN BenchmarkIndexHard4\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexHard4","Output":"BenchmarkIndexHard4\n"}
{"Action":"output","Test":"BenchmarkIndexHard4","Output":"BenchmarkIndexHard4-16 \t 2298\t 533435 ns/op\n"}
{"Action":"run","Test":"BenchmarkLastIndexHard1"}
-{"Action":"output","Test":"BenchmarkLastIndexHard1","Output":"=== RUN BenchmarkLastIndexHard1\n"}
+{"Action":"output","Test":"BenchmarkLastIndexHard1","Output":"=== RUN BenchmarkLastIndexHard1\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkLastIndexHard1","Output":"BenchmarkLastIndexHard1\n"}
{"Action":"output","Test":"BenchmarkLastIndexHard1","Output":"BenchmarkLastIndexHard1-16 \t 813\t 1295767 ns/op\n"}
{"Action":"run","Test":"BenchmarkLastIndexHard2"}
-{"Action":"output","Test":"BenchmarkLastIndexHard2","Output":"=== RUN BenchmarkLastIndexHard2\n"}
+{"Action":"output","Test":"BenchmarkLastIndexHard2","Output":"=== RUN BenchmarkLastIndexHard2\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkLastIndexHard2","Output":"BenchmarkLastIndexHard2\n"}
{"Action":"output","Test":"BenchmarkLastIndexHard2","Output":"BenchmarkLastIndexHard2-16 \t 784\t 1389403 ns/op\n"}
{"Action":"run","Test":"BenchmarkLastIndexHard3"}
-{"Action":"output","Test":"BenchmarkLastIndexHard3","Output":"=== RUN BenchmarkLastIndexHard3\n"}
+{"Action":"output","Test":"BenchmarkLastIndexHard3","Output":"=== RUN BenchmarkLastIndexHard3\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkLastIndexHard3","Output":"BenchmarkLastIndexHard3\n"}
{"Action":"output","Test":"BenchmarkLastIndexHard3","Output":"BenchmarkLastIndexHard3-16 \t 913\t 1316608 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexTorture"}
-{"Action":"output","Test":"BenchmarkIndexTorture","Output":"=== RUN BenchmarkIndexTorture\n"}
+{"Action":"output","Test":"BenchmarkIndexTorture","Output":"=== RUN BenchmarkIndexTorture\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexTorture","Output":"BenchmarkIndexTorture\n"}
{"Action":"output","Test":"BenchmarkIndexTorture","Output":"BenchmarkIndexTorture-16 \t 98090\t 10201 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexAnyASCII"}
-{"Action":"output","Test":"BenchmarkIndexAnyASCII","Output":"=== RUN BenchmarkIndexAnyASCII\n"}
+{"Action":"output","Test":"BenchmarkIndexAnyASCII","Output":"=== RUN BenchmarkIndexAnyASCII\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexAnyASCII","Output":"BenchmarkIndexAnyASCII\n"}
{"Action":"run","Test":"BenchmarkIndexAnyASCII/1:1"}
-{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:1","Output":"=== RUN BenchmarkIndexAnyASCII/1:1\n"}
+{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:1","Output":"=== RUN BenchmarkIndexAnyASCII/1:1\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:1","Output":"BenchmarkIndexAnyASCII/1:1\n"}
{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:1","Output":"BenchmarkIndexAnyASCII/1:1-16 \t214829462\t 5.592 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexAnyASCII/1:2"}
-{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:2","Output":"=== RUN BenchmarkIndexAnyASCII/1:2\n"}
+{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:2","Output":"=== RUN BenchmarkIndexAnyASCII/1:2\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:2","Output":"BenchmarkIndexAnyASCII/1:2\n"}
{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:2","Output":"BenchmarkIndexAnyASCII/1:2-16 \t155499682\t 7.214 ns/op\n"}
{"Action":"run","Test":"BenchmarkIndexAnyASCII/1:4"}
-{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:4","Output":"=== RUN BenchmarkIndexAnyASCII/1:4\n"}
+{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:4","Output":"=== RUN BenchmarkIndexAnyASCII/1:4\n","OutputType":"frame"}
{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:4","Output":"BenchmarkIndexAnyASCII/1:4\n"}
{"Action":"output","Test":"BenchmarkIndexAnyASCII/1:4","Output":"BenchmarkIndexAnyASCII/1:4-16 \t172757770\t 7.092 ns/op\n"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/frameescape.json b/src/cmd/internal/test2json/testdata/frameescape.json
index c959089b92..99df01ad04 100644
--- a/src/cmd/internal/test2json/testdata/frameescape.json
+++ b/src/cmd/internal/test2json/testdata/frameescape.json
@@ -1,8 +1,8 @@
{"Action":"start"}
{"Action":"run","Test":"TestAscii"}
-{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n"}
+{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n","OutputType":"frame"}
{"Action":"run","Test":"TestAscii/Log"}
-{"Action":"output","Test":"TestAscii/Log","Output":"=== RUN TestAscii/Log\n"}
+{"Action":"output","Test":"TestAscii/Log","Output":"=== RUN TestAscii/Log\n","OutputType":"frame"}
{"Action":"output","Test":"TestAscii/Log","Output":" x_test.go:8: \u0000\n"}
{"Action":"output","Test":"TestAscii/Log","Output":" x_test.go:8: \u0001\n"}
{"Action":"output","Test":"TestAscii/Log","Output":" x_test.go:8: \u0002\n"}
@@ -132,6 +132,139 @@
{"Action":"output","Test":"TestAscii/Log","Output":" x_test.go:8: }\n"}
{"Action":"output","Test":"TestAscii/Log","Output":" x_test.go:8: ~\n"}
{"Action":"output","Test":"TestAscii/Log","Output":" x_test.go:8: \n"}
-{"Action":"output","Test":"TestAscii/Log","Output":"--- PASS: TestAscii/Log (0.00s)\n"}
+{"Action":"output","Test":"TestAscii/Log","Output":"--- PASS: TestAscii/Log (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAscii/Log"}
-{"Action":"output","Test":"TestAscii","Output":"--- PASS: TestAscii (0.00s)\n"}
+{"Action":"run","Test":"TestAscii/Error"}
+{"Action":"output","Test":"TestAscii/Error","Output":"=== RUN TestAscii/Error\n","OutputType":"frame"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0000\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0001\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0002\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0003\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0004\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0005\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0006\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0007\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \b\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \t\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" \n","OutputType":"error-continue"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u000b\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \f\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \r\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u000e\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u000f\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0010\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0011\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0012\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0013\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0014\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0015\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0016\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0017\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0018\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0019\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u001a\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u001b\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u001c\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u001d\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u001e\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u001f\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: !\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \"\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: #\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: $\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: %\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u0026\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: '\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: (\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: )\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: *\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: +\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: ,\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: -\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: .\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: /\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 0\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 1\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 2\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 3\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 4\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 5\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 6\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 7\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 8\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: 9\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: :\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: ;\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u003c\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: =\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \u003e\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: ?\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: @\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: A\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: B\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: C\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: D\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: E\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: F\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: G\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: H\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: I\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: J\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: K\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: L\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: M\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: N\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: O\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: P\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: Q\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: R\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: S\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: T\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: U\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: V\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: W\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: X\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: Y\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: Z\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: [\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \\\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: ]\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: ^\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: _\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: `\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: a\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: b\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: c\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: d\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: e\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: f\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: g\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: h\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: i\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: j\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: k\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: l\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: m\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: n\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: o\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: p\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: q\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: r\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: s\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: t\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: u\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: v\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: w\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: x\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: y\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: z\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: {\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: |\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: }\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: ~\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":" x_test.go:13: \n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii/Error","Output":"--- FAIL: TestAscii/Error (0.00s)\n","OutputType":"frame"}
+{"Action":"fail","Test":"TestAscii/Error"}
+{"Action":"output","Test":"TestAscii","Output":"--- FAIL: TestAscii (0.00s)\n","OutputType":"frame"}
diff --git a/src/cmd/internal/test2json/testdata/frameescape.test b/src/cmd/internal/test2json/testdata/frameescape.test
index 46abdfe1ea..e2abe66830 100644
--- a/src/cmd/internal/test2json/testdata/frameescape.test
+++ b/src/cmd/internal/test2json/testdata/frameescape.test
Binary files differ
diff --git a/src/cmd/internal/test2json/testdata/framefail.json b/src/cmd/internal/test2json/testdata/framefail.json
new file mode 100644
index 0000000000..e355d70303
--- /dev/null
+++ b/src/cmd/internal/test2json/testdata/framefail.json
@@ -0,0 +1,11 @@
+{"Action":"start"}
+{"Action":"run","Test":"TestAscii"}
+{"Action":"output","Test":"TestAscii","Output":"=== RUN TestAscii\n","OutputType":"frame"}
+{"Action":"output","Test":"TestAscii","Output":"foo\n"}
+{"Action":"output","Test":"TestAscii","Output":" one line\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii","Output":"bar\n"}
+{"Action":"output","Test":"TestAscii","Output":" two\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii","Output":" lines\n","OutputType":"error-continue"}
+{"Action":"output","Test":"TestAscii","Output":"baz"}
+{"Action":"output","Test":"TestAscii","Output":" same line\n","OutputType":"error"}
+{"Action":"output","Test":"TestAscii","Output":"--- FAIL: TestAscii\n","OutputType":"frame"}
diff --git a/src/cmd/internal/test2json/testdata/framefail.test b/src/cmd/internal/test2json/testdata/framefail.test
new file mode 100644
index 0000000000..35666076df
--- /dev/null
+++ b/src/cmd/internal/test2json/testdata/framefail.test
@@ -0,0 +1,8 @@
+=== RUN TestAscii
+foo
+ one line
+bar
+ two
+ lines
+baz same line
+--- FAIL: TestAscii
diff --git a/src/cmd/internal/test2json/testdata/framefuzz.json b/src/cmd/internal/test2json/testdata/framefuzz.json
index 25869ee740..c8647dad3a 100644
--- a/src/cmd/internal/test2json/testdata/framefuzz.json
+++ b/src/cmd/internal/test2json/testdata/framefuzz.json
@@ -1,43 +1,43 @@
{"Action":"start"}
{"Action":"run","Test":"TestAddrStringAllocs"}
-{"Action":"output","Test":"TestAddrStringAllocs","Output":"=== RUN TestAddrStringAllocs\n"}
+{"Action":"output","Test":"TestAddrStringAllocs","Output":"=== RUN TestAddrStringAllocs\n","OutputType":"frame"}
{"Action":"run","Test":"TestAddrStringAllocs/zero"}
-{"Action":"output","Test":"TestAddrStringAllocs/zero","Output":"=== RUN TestAddrStringAllocs/zero\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/zero","Output":"=== RUN TestAddrStringAllocs/zero\n","OutputType":"frame"}
{"Action":"run","Test":"TestAddrStringAllocs/ipv4"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv4","Output":"=== RUN TestAddrStringAllocs/ipv4\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv4","Output":"=== RUN TestAddrStringAllocs/ipv4\n","OutputType":"frame"}
{"Action":"run","Test":"TestAddrStringAllocs/ipv6"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv6","Output":"=== RUN TestAddrStringAllocs/ipv6\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv6","Output":"=== RUN TestAddrStringAllocs/ipv6\n","OutputType":"frame"}
{"Action":"run","Test":"TestAddrStringAllocs/ipv6+zone"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv6+zone","Output":"=== RUN TestAddrStringAllocs/ipv6+zone\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv6+zone","Output":"=== RUN TestAddrStringAllocs/ipv6+zone\n","OutputType":"frame"}
{"Action":"run","Test":"TestAddrStringAllocs/ipv4-in-ipv6"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6","Output":"=== RUN TestAddrStringAllocs/ipv4-in-ipv6\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6","Output":"=== RUN TestAddrStringAllocs/ipv4-in-ipv6\n","OutputType":"frame"}
{"Action":"run","Test":"TestAddrStringAllocs/ipv4-in-ipv6+zone"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6+zone","Output":"=== RUN TestAddrStringAllocs/ipv4-in-ipv6+zone\n"}
-{"Action":"output","Test":"TestAddrStringAllocs","Output":"--- PASS: TestAddrStringAllocs (0.00s)\n"}
-{"Action":"output","Test":"TestAddrStringAllocs/zero","Output":" --- PASS: TestAddrStringAllocs/zero (0.00s)\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6+zone","Output":"=== RUN TestAddrStringAllocs/ipv4-in-ipv6+zone\n","OutputType":"frame"}
+{"Action":"output","Test":"TestAddrStringAllocs","Output":"--- PASS: TestAddrStringAllocs (0.00s)\n","OutputType":"frame"}
+{"Action":"output","Test":"TestAddrStringAllocs/zero","Output":" --- PASS: TestAddrStringAllocs/zero (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAddrStringAllocs/zero"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv4","Output":" --- PASS: TestAddrStringAllocs/ipv4 (0.00s)\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv4","Output":" --- PASS: TestAddrStringAllocs/ipv4 (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAddrStringAllocs/ipv4"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv6","Output":" --- PASS: TestAddrStringAllocs/ipv6 (0.00s)\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv6","Output":" --- PASS: TestAddrStringAllocs/ipv6 (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAddrStringAllocs/ipv6"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv6+zone","Output":" --- PASS: TestAddrStringAllocs/ipv6+zone (0.00s)\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv6+zone","Output":" --- PASS: TestAddrStringAllocs/ipv6+zone (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAddrStringAllocs/ipv6+zone"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6","Output":" --- PASS: TestAddrStringAllocs/ipv4-in-ipv6 (0.00s)\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6","Output":" --- PASS: TestAddrStringAllocs/ipv4-in-ipv6 (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAddrStringAllocs/ipv4-in-ipv6"}
-{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6+zone","Output":" --- PASS: TestAddrStringAllocs/ipv4-in-ipv6+zone (0.00s)\n"}
+{"Action":"output","Test":"TestAddrStringAllocs/ipv4-in-ipv6+zone","Output":" --- PASS: TestAddrStringAllocs/ipv4-in-ipv6+zone (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAddrStringAllocs/ipv4-in-ipv6+zone"}
{"Action":"pass","Test":"TestAddrStringAllocs"}
{"Action":"run","Test":"TestPrefixString"}
-{"Action":"output","Test":"TestPrefixString","Output":"=== RUN TestPrefixString\n"}
-{"Action":"output","Test":"TestPrefixString","Output":"--- PASS: TestPrefixString (0.00s)\n"}
+{"Action":"output","Test":"TestPrefixString","Output":"=== RUN TestPrefixString\n","OutputType":"frame"}
+{"Action":"output","Test":"TestPrefixString","Output":"--- PASS: TestPrefixString (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestPrefixString"}
{"Action":"run","Test":"TestInvalidAddrPortString"}
-{"Action":"output","Test":"TestInvalidAddrPortString","Output":"=== RUN TestInvalidAddrPortString\n"}
-{"Action":"output","Test":"TestInvalidAddrPortString","Output":"--- PASS: TestInvalidAddrPortString (0.00s)\n"}
+{"Action":"output","Test":"TestInvalidAddrPortString","Output":"=== RUN TestInvalidAddrPortString\n","OutputType":"frame"}
+{"Action":"output","Test":"TestInvalidAddrPortString","Output":"--- PASS: TestInvalidAddrPortString (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestInvalidAddrPortString"}
{"Action":"run","Test":"TestAsSlice"}
-{"Action":"output","Test":"TestAsSlice","Output":"=== RUN TestAsSlice\n"}
-{"Action":"output","Test":"TestAsSlice","Output":"--- PASS: TestAsSlice (0.00s)\n"}
+{"Action":"output","Test":"TestAsSlice","Output":"=== RUN TestAsSlice\n","OutputType":"frame"}
+{"Action":"output","Test":"TestAsSlice","Output":"--- PASS: TestAsSlice (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestAsSlice"}
{"Action":"output","Test":"TestInlining","Output":" inlining_test.go:102: not in expected set, but also inlinable: \"Addr.string4\"\n"}
{"Action":"output","Test":"TestInlining","Output":" inlining_test.go:102: not in expected set, but also inlinable: \"Prefix.isZero\"\n"}
@@ -55,15 +55,15 @@
{"Action":"output","Test":"TestInlining","Output":" inlining_test.go:102: not in expected set, but also inlinable: \"beUint64\"\n"}
{"Action":"output","Test":"TestInlining","Output":" inlining_test.go:102: not in expected set, but also inlinable: \"appendHexPad\"\n"}
{"Action":"output","Test":"TestInlining","Output":" inlining_test.go:102: not in expected set, but also inlinable: \"lePutUint16\"\n"}
-{"Action":"output","Test":"TestInlining","Output":"--- PASS: TestInlining (0.10s)\n"}
+{"Action":"output","Test":"TestInlining","Output":"--- PASS: TestInlining (0.10s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestInlining"}
{"Action":"run","Test":"FuzzParse"}
-{"Action":"output","Test":"FuzzParse","Output":"=== RUN FuzzParse\n"}
+{"Action":"output","Test":"FuzzParse","Output":"=== RUN FuzzParse\n","OutputType":"frame"}
{"Action":"output","Test":"FuzzParse","Output":"fuzz: elapsed: 0s, gathering baseline coverage: 0/390 completed\n"}
{"Action":"output","Test":"FuzzParse","Output":"fuzz: elapsed: 0s, gathering baseline coverage: 390/390 completed, now fuzzing with 16 workers\n"}
{"Action":"output","Test":"FuzzParse","Output":"fuzz: elapsed: 3s, execs: 438666 (146173/sec), new interesting: 12 (total: 402)\n"}
{"Action":"output","Test":"FuzzParse","Output":"\u0003fuzz: elapsed: 4s, execs: 558467 (147850/sec), new interesting: 15 (total: 405)\n"}
-{"Action":"output","Test":"FuzzParse","Output":"--- PASS: FuzzParse (3.85s)\n"}
+{"Action":"output","Test":"FuzzParse","Output":"--- PASS: FuzzParse (3.85s)\n","OutputType":"frame"}
{"Action":"pass","Test":"FuzzParse"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/issue23036.json b/src/cmd/internal/test2json/testdata/issue23036.json
index bfdc3e5e0f..40a8b67bc5 100644
--- a/src/cmd/internal/test2json/testdata/issue23036.json
+++ b/src/cmd/internal/test2json/testdata/issue23036.json
@@ -1,13 +1,13 @@
{"Action":"start"}
{"Action":"run","Test":"TestActualCase"}
-{"Action":"output","Test":"TestActualCase","Output":"=== RUN TestActualCase\n"}
-{"Action":"output","Test":"TestActualCase","Output":"--- FAIL: TestActualCase (0.00s)\n"}
+{"Action":"output","Test":"TestActualCase","Output":"=== RUN TestActualCase\n","OutputType":"frame"}
+{"Action":"output","Test":"TestActualCase","Output":"--- FAIL: TestActualCase (0.00s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestActualCase","Output":" foo_test.go:14: Differed.\n"}
{"Action":"output","Test":"TestActualCase","Output":" Expected: MyTest:\n"}
{"Action":"output","Test":"TestActualCase","Output":" --- FAIL: Test output from other tool\n"}
{"Action":"output","Test":"TestActualCase","Output":" Actual: not expected\n"}
{"Action":"fail","Test":"TestActualCase"}
-{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"FAIL\n","OutputType":"frame"}
{"Action":"output","Output":"exit status 1\n"}
{"Action":"output","Output":"FAIL github.com/org/project/badtest 0.049s\n"}
{"Action":"fail"}
diff --git a/src/cmd/internal/test2json/testdata/issue23920.json b/src/cmd/internal/test2json/testdata/issue23920.json
index 17e8de6e91..9e49a1c612 100644
--- a/src/cmd/internal/test2json/testdata/issue23920.json
+++ b/src/cmd/internal/test2json/testdata/issue23920.json
@@ -1,15 +1,15 @@
{"Action":"start"}
{"Action":"run","Test":"TestWithColons"}
-{"Action":"output","Test":"TestWithColons","Output":"=== RUN TestWithColons\n"}
+{"Action":"output","Test":"TestWithColons","Output":"=== RUN TestWithColons\n","OutputType":"frame"}
{"Action":"run","Test":"TestWithColons/[::1]"}
-{"Action":"output","Test":"TestWithColons/[::1]","Output":"=== RUN TestWithColons/[::1]\n"}
+{"Action":"output","Test":"TestWithColons/[::1]","Output":"=== RUN TestWithColons/[::1]\n","OutputType":"frame"}
{"Action":"run","Test":"TestWithColons/127.0.0.1:0"}
-{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":"=== RUN TestWithColons/127.0.0.1:0\n"}
-{"Action":"output","Test":"TestWithColons","Output":"--- PASS: TestWithColons (0.00s)\n"}
-{"Action":"output","Test":"TestWithColons/[::1]","Output":" --- PASS: TestWithColons/[::1] (0.00s)\n"}
+{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":"=== RUN TestWithColons/127.0.0.1:0\n","OutputType":"frame"}
+{"Action":"output","Test":"TestWithColons","Output":"--- PASS: TestWithColons (0.00s)\n","OutputType":"frame"}
+{"Action":"output","Test":"TestWithColons/[::1]","Output":" --- PASS: TestWithColons/[::1] (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestWithColons/[::1]"}
-{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":" --- PASS: TestWithColons/127.0.0.1:0 (0.00s)\n"}
+{"Action":"output","Test":"TestWithColons/127.0.0.1:0","Output":" --- PASS: TestWithColons/127.0.0.1:0 (0.00s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestWithColons/127.0.0.1:0"}
{"Action":"pass","Test":"TestWithColons"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/issue29755.json b/src/cmd/internal/test2json/testdata/issue29755.json
index c49bf92ce2..31af660e0e 100644
--- a/src/cmd/internal/test2json/testdata/issue29755.json
+++ b/src/cmd/internal/test2json/testdata/issue29755.json
@@ -1,39 +1,39 @@
{"Action":"start"}
{"Action":"run","Test":"TestOutputWithSubtest"}
-{"Action":"output","Test":"TestOutputWithSubtest","Output":"=== RUN TestOutputWithSubtest\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"=== RUN TestOutputWithSubtest\n","OutputType":"frame"}
{"Action":"run","Test":"TestOutputWithSubtest/sub_test"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"=== RUN TestOutputWithSubtest/sub_test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"=== RUN TestOutputWithSubtest/sub_test\n","OutputType":"frame"}
{"Action":"run","Test":"TestOutputWithSubtest/sub_test/sub2"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":"=== RUN TestOutputWithSubtest/sub_test/sub2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":"=== RUN TestOutputWithSubtest/sub_test/sub2\n","OutputType":"frame"}
{"Action":"run","Test":"TestOutputWithSubtest/sub_test2"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"=== RUN TestOutputWithSubtest/sub_test2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"=== RUN TestOutputWithSubtest/sub_test2\n","OutputType":"frame"}
{"Action":"run","Test":"TestOutputWithSubtest/sub_test2/sub2"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":"=== RUN TestOutputWithSubtest/sub_test2/sub2\n"}
-{"Action":"output","Test":"TestOutputWithSubtest","Output":"--- FAIL: TestOutputWithSubtest (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":"=== RUN TestOutputWithSubtest/sub_test2/sub2\n","OutputType":"frame"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"--- FAIL: TestOutputWithSubtest (0.00s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:6: output before sub tests\n"}
{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:10: output from root test\n"}
{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:15: output from root test\n"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" --- PASS: TestOutputWithSubtest/sub_test (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" --- PASS: TestOutputWithSubtest/sub_test (0.00s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" foo_test.go:9: output from sub test\n"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" foo_test.go:11: more output from sub test\n"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" foo_test.go:16: more output from sub test\n"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":" --- PASS: TestOutputWithSubtest/sub_test/sub2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":" --- PASS: TestOutputWithSubtest/sub_test/sub2 (0.00s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":" foo_test.go:14: output from sub2 test\n"}
{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:22: output from root test\n"}
{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:27: output from root test\n"}
{"Action":"pass","Test":"TestOutputWithSubtest/sub_test/sub2"}
{"Action":"pass","Test":"TestOutputWithSubtest/sub_test"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" --- PASS: TestOutputWithSubtest/sub_test2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" --- PASS: TestOutputWithSubtest/sub_test2 (0.00s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" foo_test.go:21: output from sub test2\n"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" foo_test.go:23: more output from sub test2\n"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" foo_test.go:28: more output from sub test2\n"}
-{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":" --- PASS: TestOutputWithSubtest/sub_test2/sub2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":" --- PASS: TestOutputWithSubtest/sub_test2/sub2 (0.00s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":" foo_test.go:26: output from sub2 test\n"}
{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:32: output after sub test\n"}
{"Action":"pass","Test":"TestOutputWithSubtest/sub_test2/sub2"}
{"Action":"pass","Test":"TestOutputWithSubtest/sub_test2"}
{"Action":"fail","Test":"TestOutputWithSubtest"}
-{"Action":"output","Output":"FAIL\n"}
-{"Action":"output","Output":"FAIL\tgotest.tools/gotestsum/foo\t0.001s\n"}
-{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"FAIL\n","OutputType":"frame"}
+{"Action":"output","Output":"FAIL\tgotest.tools/gotestsum/foo\t0.001s\n","OutputType":"frame"}
+{"Action":"output","Output":"FAIL\n","OutputType":"frame"}
{"Action":"fail"}
diff --git a/src/cmd/internal/test2json/testdata/panic.json b/src/cmd/internal/test2json/testdata/panic.json
index 1cd4384629..47ee1a6eeb 100644
--- a/src/cmd/internal/test2json/testdata/panic.json
+++ b/src/cmd/internal/test2json/testdata/panic.json
@@ -1,5 +1,5 @@
{"Action":"start"}
-{"Action":"output","Test":"TestPanic","Output":"--- FAIL: TestPanic (0.00s)\n"}
+{"Action":"output","Test":"TestPanic","Output":"--- FAIL: TestPanic (0.00s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestPanic","Output":"panic: oops [recovered]\n"}
{"Action":"output","Test":"TestPanic","Output":"\tpanic: oops\n"}
{"Action":"output","Test":"TestPanic","Output":"\n"}
@@ -15,6 +15,6 @@
{"Action":"output","Test":"TestPanic","Output":"created by testing.(*T).Run\n"}
{"Action":"output","Test":"TestPanic","Output":"\tgo/src/testing/testing.go:960 +0x350\n"}
{"Action":"fail","Test":"TestPanic"}
-{"Action":"output","Output":"FAIL\tcommand-line-arguments\t0.042s\n"}
-{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"FAIL\tcommand-line-arguments\t0.042s\n","OutputType":"frame"}
+{"Action":"output","Output":"FAIL\n","OutputType":"frame"}
{"Action":"fail"}
diff --git a/src/cmd/internal/test2json/testdata/smiley.json b/src/cmd/internal/test2json/testdata/smiley.json
index 858843f3af..196bbf2906 100644
--- a/src/cmd/internal/test2json/testdata/smiley.json
+++ b/src/cmd/internal/test2json/testdata/smiley.json
@@ -1,183 +1,183 @@
{"Action":"start"}
{"Action":"run","Test":"Test☺☹"}
-{"Action":"output","Test":"Test☺☹","Output":"=== RUN Test☺☹\n"}
-{"Action":"output","Test":"Test☺☹","Output":"=== PAUSE Test☺☹\n"}
+{"Action":"output","Test":"Test☺☹","Output":"=== RUN Test☺☹\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹","Output":"=== PAUSE Test☺☹\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹"}
{"Action":"run","Test":"Test☺☹Asm"}
-{"Action":"output","Test":"Test☺☹Asm","Output":"=== RUN Test☺☹Asm\n"}
-{"Action":"output","Test":"Test☺☹Asm","Output":"=== PAUSE Test☺☹Asm\n"}
+{"Action":"output","Test":"Test☺☹Asm","Output":"=== RUN Test☺☹Asm\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Asm","Output":"=== PAUSE Test☺☹Asm\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Asm"}
{"Action":"run","Test":"Test☺☹Dirs"}
-{"Action":"output","Test":"Test☺☹Dirs","Output":"=== RUN Test☺☹Dirs\n"}
-{"Action":"output","Test":"Test☺☹Dirs","Output":"=== PAUSE Test☺☹Dirs\n"}
+{"Action":"output","Test":"Test☺☹Dirs","Output":"=== RUN Test☺☹Dirs\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Dirs","Output":"=== PAUSE Test☺☹Dirs\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Dirs"}
{"Action":"run","Test":"TestTags"}
-{"Action":"output","Test":"TestTags","Output":"=== RUN TestTags\n"}
-{"Action":"output","Test":"TestTags","Output":"=== PAUSE TestTags\n"}
+{"Action":"output","Test":"TestTags","Output":"=== RUN TestTags\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags","Output":"=== PAUSE TestTags\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags"}
{"Action":"run","Test":"Test☺☹Verbose"}
-{"Action":"output","Test":"Test☺☹Verbose","Output":"=== RUN Test☺☹Verbose\n"}
-{"Action":"output","Test":"Test☺☹Verbose","Output":"=== PAUSE Test☺☹Verbose\n"}
+{"Action":"output","Test":"Test☺☹Verbose","Output":"=== RUN Test☺☹Verbose\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Verbose","Output":"=== PAUSE Test☺☹Verbose\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Verbose"}
{"Action":"cont","Test":"Test☺☹"}
-{"Action":"output","Test":"Test☺☹","Output":"=== CONT Test☺☹\n"}
+{"Action":"output","Test":"Test☺☹","Output":"=== CONT Test☺☹\n","OutputType":"frame"}
{"Action":"cont","Test":"TestTags"}
-{"Action":"output","Test":"TestTags","Output":"=== CONT TestTags\n"}
+{"Action":"output","Test":"TestTags","Output":"=== CONT TestTags\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹Verbose"}
-{"Action":"output","Test":"Test☺☹Verbose","Output":"=== CONT Test☺☹Verbose\n"}
+{"Action":"output","Test":"Test☺☹Verbose","Output":"=== CONT Test☺☹Verbose\n","OutputType":"frame"}
{"Action":"run","Test":"TestTags/testtag"}
-{"Action":"output","Test":"TestTags/testtag","Output":"=== RUN TestTags/testtag\n"}
-{"Action":"output","Test":"TestTags/testtag","Output":"=== PAUSE TestTags/testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":"=== RUN TestTags/testtag\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags/testtag","Output":"=== PAUSE TestTags/testtag\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags/testtag"}
{"Action":"cont","Test":"Test☺☹Dirs"}
-{"Action":"output","Test":"Test☺☹Dirs","Output":"=== CONT Test☺☹Dirs\n"}
+{"Action":"output","Test":"Test☺☹Dirs","Output":"=== CONT Test☺☹Dirs\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹Asm"}
-{"Action":"output","Test":"Test☺☹Asm","Output":"=== CONT Test☺☹Asm\n"}
+{"Action":"output","Test":"Test☺☹Asm","Output":"=== CONT Test☺☹Asm\n","OutputType":"frame"}
{"Action":"run","Test":"Test☺☹/0"}
-{"Action":"output","Test":"Test☺☹/0","Output":"=== RUN Test☺☹/0\n"}
-{"Action":"output","Test":"Test☺☹/0","Output":"=== PAUSE Test☺☹/0\n"}
+{"Action":"output","Test":"Test☺☹/0","Output":"=== RUN Test☺☹/0\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/0","Output":"=== PAUSE Test☺☹/0\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/0"}
{"Action":"run","Test":"Test☺☹/1"}
-{"Action":"output","Test":"Test☺☹/1","Output":"=== RUN Test☺☹/1\n"}
-{"Action":"output","Test":"Test☺☹/1","Output":"=== PAUSE Test☺☹/1\n"}
+{"Action":"output","Test":"Test☺☹/1","Output":"=== RUN Test☺☹/1\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/1","Output":"=== PAUSE Test☺☹/1\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/1"}
{"Action":"run","Test":"Test☺☹/2"}
-{"Action":"output","Test":"Test☺☹/2","Output":"=== RUN Test☺☹/2\n"}
-{"Action":"output","Test":"Test☺☹/2","Output":"=== PAUSE Test☺☹/2\n"}
+{"Action":"output","Test":"Test☺☹/2","Output":"=== RUN Test☺☹/2\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/2","Output":"=== PAUSE Test☺☹/2\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/2"}
{"Action":"run","Test":"Test☺☹/3"}
-{"Action":"output","Test":"Test☺☹/3","Output":"=== RUN Test☺☹/3\n"}
-{"Action":"output","Test":"Test☺☹/3","Output":"=== PAUSE Test☺☹/3\n"}
+{"Action":"output","Test":"Test☺☹/3","Output":"=== RUN Test☺☹/3\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/3","Output":"=== PAUSE Test☺☹/3\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/3"}
{"Action":"run","Test":"Test☺☹/4"}
-{"Action":"output","Test":"Test☺☹/4","Output":"=== RUN Test☺☹/4\n"}
+{"Action":"output","Test":"Test☺☹/4","Output":"=== RUN Test☺☹/4\n","OutputType":"frame"}
{"Action":"run","Test":"TestTags/x_testtag_y"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== RUN TestTags/x_testtag_y\n"}
-{"Action":"output","Test":"Test☺☹/4","Output":"=== PAUSE Test☺☹/4\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== RUN TestTags/x_testtag_y\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/4","Output":"=== PAUSE Test☺☹/4\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/4"}
{"Action":"run","Test":"Test☺☹/5"}
-{"Action":"output","Test":"Test☺☹/5","Output":"=== RUN Test☺☹/5\n"}
-{"Action":"output","Test":"Test☺☹/5","Output":"=== PAUSE Test☺☹/5\n"}
+{"Action":"output","Test":"Test☺☹/5","Output":"=== RUN Test☺☹/5\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/5","Output":"=== PAUSE Test☺☹/5\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/5"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== PAUSE TestTags/x_testtag_y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== PAUSE TestTags/x_testtag_y\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags/x_testtag_y"}
{"Action":"run","Test":"Test☺☹/6"}
-{"Action":"output","Test":"Test☺☹/6","Output":"=== RUN Test☺☹/6\n"}
+{"Action":"output","Test":"Test☺☹/6","Output":"=== RUN Test☺☹/6\n","OutputType":"frame"}
{"Action":"run","Test":"TestTags/x,testtag,y"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== RUN TestTags/x,testtag,y\n"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== PAUSE TestTags/x,testtag,y\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== RUN TestTags/x,testtag,y\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== PAUSE TestTags/x,testtag,y\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags/x,testtag,y"}
{"Action":"run","Test":"Test☺☹Dirs/testingpkg"}
-{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== RUN Test☺☹Dirs/testingpkg\n"}
-{"Action":"output","Test":"Test☺☹/6","Output":"=== PAUSE Test☺☹/6\n"}
+{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== RUN Test☺☹Dirs/testingpkg\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/6","Output":"=== PAUSE Test☺☹/6\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/6"}
{"Action":"cont","Test":"TestTags/x,testtag,y"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== CONT TestTags/x,testtag,y\n"}
-{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== PAUSE Test☺☹Dirs/testingpkg\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== CONT TestTags/x,testtag,y\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== PAUSE Test☺☹Dirs/testingpkg\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Dirs/testingpkg"}
{"Action":"run","Test":"Test☺☹Dirs/divergent"}
-{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== RUN Test☺☹Dirs/divergent\n"}
+{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== RUN Test☺☹Dirs/divergent\n","OutputType":"frame"}
{"Action":"run","Test":"Test☺☹/7"}
-{"Action":"output","Test":"Test☺☹/7","Output":"=== RUN Test☺☹/7\n"}
-{"Action":"output","Test":"Test☺☹/7","Output":"=== PAUSE Test☺☹/7\n"}
+{"Action":"output","Test":"Test☺☹/7","Output":"=== RUN Test☺☹/7\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/7","Output":"=== PAUSE Test☺☹/7\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹/7"}
-{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== PAUSE Test☺☹Dirs/divergent\n"}
+{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== PAUSE Test☺☹Dirs/divergent\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Dirs/divergent"}
{"Action":"cont","Test":"TestTags/x_testtag_y"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== CONT TestTags/x_testtag_y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== CONT TestTags/x_testtag_y\n","OutputType":"frame"}
{"Action":"cont","Test":"TestTags/testtag"}
-{"Action":"output","Test":"TestTags/testtag","Output":"=== CONT TestTags/testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":"=== CONT TestTags/testtag\n","OutputType":"frame"}
{"Action":"run","Test":"Test☺☹Dirs/buildtag"}
-{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== RUN Test☺☹Dirs/buildtag\n"}
-{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== PAUSE Test☺☹Dirs/buildtag\n"}
+{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== RUN Test☺☹Dirs/buildtag\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== PAUSE Test☺☹Dirs/buildtag\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Dirs/buildtag"}
{"Action":"cont","Test":"Test☺☹/0"}
-{"Action":"output","Test":"Test☺☹/0","Output":"=== CONT Test☺☹/0\n"}
+{"Action":"output","Test":"Test☺☹/0","Output":"=== CONT Test☺☹/0\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹/4"}
-{"Action":"output","Test":"Test☺☹/4","Output":"=== CONT Test☺☹/4\n"}
+{"Action":"output","Test":"Test☺☹/4","Output":"=== CONT Test☺☹/4\n","OutputType":"frame"}
{"Action":"run","Test":"Test☺☹Dirs/incomplete"}
-{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== RUN Test☺☹Dirs/incomplete\n"}
-{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== PAUSE Test☺☹Dirs/incomplete\n"}
+{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== RUN Test☺☹Dirs/incomplete\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== PAUSE Test☺☹Dirs/incomplete\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Dirs/incomplete"}
{"Action":"run","Test":"Test☺☹Dirs/cgo"}
-{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== RUN Test☺☹Dirs/cgo\n"}
-{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== PAUSE Test☺☹Dirs/cgo\n"}
+{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== RUN Test☺☹Dirs/cgo\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== PAUSE Test☺☹Dirs/cgo\n","OutputType":"frame"}
{"Action":"pause","Test":"Test☺☹Dirs/cgo"}
{"Action":"cont","Test":"Test☺☹/7"}
-{"Action":"output","Test":"Test☺☹/7","Output":"=== CONT Test☺☹/7\n"}
+{"Action":"output","Test":"Test☺☹/7","Output":"=== CONT Test☺☹/7\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹/6"}
-{"Action":"output","Test":"Test☺☹/6","Output":"=== CONT Test☺☹/6\n"}
-{"Action":"output","Test":"Test☺☹Verbose","Output":"--- PASS: Test☺☹Verbose (0.04s)\n"}
+{"Action":"output","Test":"Test☺☹/6","Output":"=== CONT Test☺☹/6\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Verbose","Output":"--- PASS: Test☺☹Verbose (0.04s)\n","OutputType":"frame"}
{"Action":"pass","Test":"Test☺☹Verbose"}
{"Action":"cont","Test":"Test☺☹/5"}
-{"Action":"output","Test":"Test☺☹/5","Output":"=== CONT Test☺☹/5\n"}
+{"Action":"output","Test":"Test☺☹/5","Output":"=== CONT Test☺☹/5\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹/3"}
-{"Action":"output","Test":"Test☺☹/3","Output":"=== CONT Test☺☹/3\n"}
+{"Action":"output","Test":"Test☺☹/3","Output":"=== CONT Test☺☹/3\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹/2"}
-{"Action":"output","Test":"Test☺☹/2","Output":"=== CONT Test☺☹/2\n"}
-{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n"}
+{"Action":"output","Test":"Test☺☹/2","Output":"=== CONT Test☺☹/2\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestTags/x_testtag_y","Output":" vet_test.go:187: -tags=x testtag y\n"}
{"Action":"pass","Test":"TestTags/x_testtag_y"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestTags/x,testtag,y","Output":" vet_test.go:187: -tags=x,testtag,y\n"}
{"Action":"pass","Test":"TestTags/x,testtag,y"}
-{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestTags/testtag","Output":" vet_test.go:187: -tags=testtag\n"}
{"Action":"pass","Test":"TestTags/testtag"}
{"Action":"pass","Test":"TestTags"}
{"Action":"cont","Test":"Test☺☹/1"}
-{"Action":"output","Test":"Test☺☹/1","Output":"=== CONT Test☺☹/1\n"}
+{"Action":"output","Test":"Test☺☹/1","Output":"=== CONT Test☺☹/1\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹Dirs/testingpkg"}
-{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== CONT Test☺☹Dirs/testingpkg\n"}
+{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":"=== CONT Test☺☹Dirs/testingpkg\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹Dirs/buildtag"}
-{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== CONT Test☺☹Dirs/buildtag\n"}
+{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":"=== CONT Test☺☹Dirs/buildtag\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹Dirs/divergent"}
-{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== CONT Test☺☹Dirs/divergent\n"}
+{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":"=== CONT Test☺☹Dirs/divergent\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹Dirs/incomplete"}
-{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== CONT Test☺☹Dirs/incomplete\n"}
+{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":"=== CONT Test☺☹Dirs/incomplete\n","OutputType":"frame"}
{"Action":"cont","Test":"Test☺☹Dirs/cgo"}
-{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== CONT Test☺☹Dirs/cgo\n"}
-{"Action":"output","Test":"Test☺☹","Output":"--- PASS: Test☺☹ (0.39s)\n"}
-{"Action":"output","Test":"Test☺☹/5","Output":" --- PASS: Test☺☹/5 (0.07s)\n"}
+{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== CONT Test☺☹Dirs/cgo\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹","Output":"--- PASS: Test☺☹ (0.39s)\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹/5","Output":" --- PASS: Test☺☹/5 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/5","Output":" vet_test.go:114: φιλεσ: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/5"}
-{"Action":"output","Test":"Test☺☹/3","Output":" --- PASS: Test☺☹/3 (0.07s)\n"}
+{"Action":"output","Test":"Test☺☹/3","Output":" --- PASS: Test☺☹/3 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/3","Output":" vet_test.go:114: φιλεσ: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/3"}
-{"Action":"output","Test":"Test☺☹/6","Output":" --- PASS: Test☺☹/6 (0.07s)\n"}
+{"Action":"output","Test":"Test☺☹/6","Output":" --- PASS: Test☺☹/6 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/6","Output":" vet_test.go:114: φιλεσ: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/6"}
-{"Action":"output","Test":"Test☺☹/2","Output":" --- PASS: Test☺☹/2 (0.07s)\n"}
+{"Action":"output","Test":"Test☺☹/2","Output":" --- PASS: Test☺☹/2 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/2","Output":" vet_test.go:114: φιλεσ: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/2"}
-{"Action":"output","Test":"Test☺☹/0","Output":" --- PASS: Test☺☹/0 (0.13s)\n"}
+{"Action":"output","Test":"Test☺☹/0","Output":" --- PASS: Test☺☹/0 (0.13s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/0","Output":" vet_test.go:114: φιλεσ: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/0"}
-{"Action":"output","Test":"Test☺☹/4","Output":" --- PASS: Test☺☹/4 (0.16s)\n"}
+{"Action":"output","Test":"Test☺☹/4","Output":" --- PASS: Test☺☹/4 (0.16s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/4","Output":" vet_test.go:114: φιλεσ: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/4"}
-{"Action":"output","Test":"Test☺☹/1","Output":" --- PASS: Test☺☹/1 (0.07s)\n"}
+{"Action":"output","Test":"Test☺☹/1","Output":" --- PASS: Test☺☹/1 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/1","Output":" vet_test.go:114: φιλεσ: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/1"}
-{"Action":"output","Test":"Test☺☹/7","Output":" --- PASS: Test☺☹/7 (0.19s)\n"}
+{"Action":"output","Test":"Test☺☹/7","Output":" --- PASS: Test☺☹/7 (0.19s)\n","OutputType":"frame"}
{"Action":"output","Test":"Test☺☹/7","Output":" vet_test.go:114: φιλεσ: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/7"}
{"Action":"pass","Test":"Test☺☹"}
-{"Action":"output","Test":"Test☺☹Dirs","Output":"--- PASS: Test☺☹Dirs (0.01s)\n"}
-{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":" --- PASS: Test☺☹Dirs/testingpkg (0.06s)\n"}
+{"Action":"output","Test":"Test☺☹Dirs","Output":"--- PASS: Test☺☹Dirs (0.01s)\n","OutputType":"frame"}
+{"Action":"output","Test":"Test☺☹Dirs/testingpkg","Output":" --- PASS: Test☺☹Dirs/testingpkg (0.06s)\n","OutputType":"frame"}
{"Action":"pass","Test":"Test☺☹Dirs/testingpkg"}
-{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":" --- PASS: Test☺☹Dirs/divergent (0.05s)\n"}
+{"Action":"output","Test":"Test☺☹Dirs/divergent","Output":" --- PASS: Test☺☹Dirs/divergent (0.05s)\n","OutputType":"frame"}
{"Action":"pass","Test":"Test☺☹Dirs/divergent"}
-{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":" --- PASS: Test☺☹Dirs/buildtag (0.06s)\n"}
+{"Action":"output","Test":"Test☺☹Dirs/buildtag","Output":" --- PASS: Test☺☹Dirs/buildtag (0.06s)\n","OutputType":"frame"}
{"Action":"pass","Test":"Test☺☹Dirs/buildtag"}
-{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":" --- PASS: Test☺☹Dirs/incomplete (0.05s)\n"}
+{"Action":"output","Test":"Test☺☹Dirs/incomplete","Output":" --- PASS: Test☺☹Dirs/incomplete (0.05s)\n","OutputType":"frame"}
{"Action":"pass","Test":"Test☺☹Dirs/incomplete"}
-{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":" --- PASS: Test☺☹Dirs/cgo (0.04s)\n"}
+{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":" --- PASS: Test☺☹Dirs/cgo (0.04s)\n","OutputType":"frame"}
{"Action":"pass","Test":"Test☺☹Dirs/cgo"}
{"Action":"pass","Test":"Test☺☹Dirs"}
-{"Action":"output","Test":"Test☺☹Asm","Output":"--- PASS: Test☺☹Asm (0.75s)\n"}
+{"Action":"output","Test":"Test☺☹Asm","Output":"--- PASS: Test☺☹Asm (0.75s)\n","OutputType":"frame"}
{"Action":"pass","Test":"Test☺☹Asm"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"output","Output":"ok \tcmd/vet\t(cached)\n"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/timeout.json b/src/cmd/internal/test2json/testdata/timeout.json
index dc225262f7..325d811d0e 100644
--- a/src/cmd/internal/test2json/testdata/timeout.json
+++ b/src/cmd/internal/test2json/testdata/timeout.json
@@ -1,8 +1,8 @@
{"Action":"start"}
{"Action":"run","Test":"Test"}
-{"Action":"output","Test":"Test","Output":"=== RUN Test\n"}
+{"Action":"output","Test":"Test","Output":"=== RUN Test\n","OutputType":"frame"}
{"Action":"output","Test":"Test","Output":"panic: test timed out after 1s\n"}
{"Action":"output","Test":"Test","Output":"\n"}
-{"Action":"output","Output":"FAIL\tp\t1.111s\n"}
-{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"FAIL\tp\t1.111s\n","OutputType":"frame"}
+{"Action":"output","Output":"FAIL\n","OutputType":"frame"}
{"Action":"fail"}
diff --git a/src/cmd/internal/test2json/testdata/unicode.json b/src/cmd/internal/test2json/testdata/unicode.json
index 2cc3e7322d..aa6e52acb8 100644
--- a/src/cmd/internal/test2json/testdata/unicode.json
+++ b/src/cmd/internal/test2json/testdata/unicode.json
@@ -1,11 +1,11 @@
{"Action":"start"}
{"Action":"run","Test":"TestUnicode"}
-{"Action":"output","Test":"TestUnicode","Output":"=== RUN TestUnicode\n"}
+{"Action":"output","Test":"TestUnicode","Output":"=== RUN TestUnicode\n","OutputType":"frame"}
{"Action":"output","Test":"TestUnicode","Output":"Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.\n"}
{"Action":"output","Test":"TestUnicode","Output":"私はガラスを食べられます。それは私を傷つけません。私はガラスを食べられます。それは私を傷つけません。\n"}
-{"Action":"output","Test":"TestUnicode","Output":"--- PASS: TestUnicode\n"}
+{"Action":"output","Test":"TestUnicode","Output":"--- PASS: TestUnicode\n","OutputType":"frame"}
{"Action":"output","Test":"TestUnicode","Output":" ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ\n"}
{"Action":"output","Test":"TestUnicode","Output":" אני יכול לאכול זכוכית וזה לא מזיק לי. אני יכול לאכול זכוכית וזה לא מזיק לי.\n"}
{"Action":"pass","Test":"TestUnicode"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"pass"}
diff --git a/src/cmd/internal/test2json/testdata/vet.json b/src/cmd/internal/test2json/testdata/vet.json
index 5b09104522..fcdc46e097 100644
--- a/src/cmd/internal/test2json/testdata/vet.json
+++ b/src/cmd/internal/test2json/testdata/vet.json
@@ -1,183 +1,183 @@
{"Action":"start"}
{"Action":"run","Test":"TestVet"}
-{"Action":"output","Test":"TestVet","Output":"=== RUN TestVet\n"}
-{"Action":"output","Test":"TestVet","Output":"=== PAUSE TestVet\n"}
+{"Action":"output","Test":"TestVet","Output":"=== RUN TestVet\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet","Output":"=== PAUSE TestVet\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet"}
{"Action":"run","Test":"TestVetAsm"}
-{"Action":"output","Test":"TestVetAsm","Output":"=== RUN TestVetAsm\n"}
-{"Action":"output","Test":"TestVetAsm","Output":"=== PAUSE TestVetAsm\n"}
+{"Action":"output","Test":"TestVetAsm","Output":"=== RUN TestVetAsm\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetAsm","Output":"=== PAUSE TestVetAsm\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetAsm"}
{"Action":"run","Test":"TestVetDirs"}
-{"Action":"output","Test":"TestVetDirs","Output":"=== RUN TestVetDirs\n"}
-{"Action":"output","Test":"TestVetDirs","Output":"=== PAUSE TestVetDirs\n"}
+{"Action":"output","Test":"TestVetDirs","Output":"=== RUN TestVetDirs\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetDirs","Output":"=== PAUSE TestVetDirs\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetDirs"}
{"Action":"run","Test":"TestTags"}
-{"Action":"output","Test":"TestTags","Output":"=== RUN TestTags\n"}
-{"Action":"output","Test":"TestTags","Output":"=== PAUSE TestTags\n"}
+{"Action":"output","Test":"TestTags","Output":"=== RUN TestTags\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags","Output":"=== PAUSE TestTags\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags"}
{"Action":"run","Test":"TestVetVerbose"}
-{"Action":"output","Test":"TestVetVerbose","Output":"=== RUN TestVetVerbose\n"}
-{"Action":"output","Test":"TestVetVerbose","Output":"=== PAUSE TestVetVerbose\n"}
+{"Action":"output","Test":"TestVetVerbose","Output":"=== RUN TestVetVerbose\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetVerbose","Output":"=== PAUSE TestVetVerbose\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetVerbose"}
{"Action":"cont","Test":"TestVet"}
-{"Action":"output","Test":"TestVet","Output":"=== CONT TestVet\n"}
+{"Action":"output","Test":"TestVet","Output":"=== CONT TestVet\n","OutputType":"frame"}
{"Action":"cont","Test":"TestTags"}
-{"Action":"output","Test":"TestTags","Output":"=== CONT TestTags\n"}
+{"Action":"output","Test":"TestTags","Output":"=== CONT TestTags\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVetVerbose"}
-{"Action":"output","Test":"TestVetVerbose","Output":"=== CONT TestVetVerbose\n"}
+{"Action":"output","Test":"TestVetVerbose","Output":"=== CONT TestVetVerbose\n","OutputType":"frame"}
{"Action":"run","Test":"TestTags/testtag"}
-{"Action":"output","Test":"TestTags/testtag","Output":"=== RUN TestTags/testtag\n"}
-{"Action":"output","Test":"TestTags/testtag","Output":"=== PAUSE TestTags/testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":"=== RUN TestTags/testtag\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags/testtag","Output":"=== PAUSE TestTags/testtag\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags/testtag"}
{"Action":"cont","Test":"TestVetDirs"}
-{"Action":"output","Test":"TestVetDirs","Output":"=== CONT TestVetDirs\n"}
+{"Action":"output","Test":"TestVetDirs","Output":"=== CONT TestVetDirs\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVetAsm"}
-{"Action":"output","Test":"TestVetAsm","Output":"=== CONT TestVetAsm\n"}
+{"Action":"output","Test":"TestVetAsm","Output":"=== CONT TestVetAsm\n","OutputType":"frame"}
{"Action":"run","Test":"TestVet/0"}
-{"Action":"output","Test":"TestVet/0","Output":"=== RUN TestVet/0\n"}
-{"Action":"output","Test":"TestVet/0","Output":"=== PAUSE TestVet/0\n"}
+{"Action":"output","Test":"TestVet/0","Output":"=== RUN TestVet/0\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/0","Output":"=== PAUSE TestVet/0\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/0"}
{"Action":"run","Test":"TestVet/1"}
-{"Action":"output","Test":"TestVet/1","Output":"=== RUN TestVet/1\n"}
-{"Action":"output","Test":"TestVet/1","Output":"=== PAUSE TestVet/1\n"}
+{"Action":"output","Test":"TestVet/1","Output":"=== RUN TestVet/1\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/1","Output":"=== PAUSE TestVet/1\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/1"}
{"Action":"run","Test":"TestVet/2"}
-{"Action":"output","Test":"TestVet/2","Output":"=== RUN TestVet/2\n"}
-{"Action":"output","Test":"TestVet/2","Output":"=== PAUSE TestVet/2\n"}
+{"Action":"output","Test":"TestVet/2","Output":"=== RUN TestVet/2\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/2","Output":"=== PAUSE TestVet/2\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/2"}
{"Action":"run","Test":"TestVet/3"}
-{"Action":"output","Test":"TestVet/3","Output":"=== RUN TestVet/3\n"}
-{"Action":"output","Test":"TestVet/3","Output":"=== PAUSE TestVet/3\n"}
+{"Action":"output","Test":"TestVet/3","Output":"=== RUN TestVet/3\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/3","Output":"=== PAUSE TestVet/3\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/3"}
{"Action":"run","Test":"TestVet/4"}
-{"Action":"output","Test":"TestVet/4","Output":"=== RUN TestVet/4\n"}
+{"Action":"output","Test":"TestVet/4","Output":"=== RUN TestVet/4\n","OutputType":"frame"}
{"Action":"run","Test":"TestTags/x_testtag_y"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== RUN TestTags/x_testtag_y\n"}
-{"Action":"output","Test":"TestVet/4","Output":"=== PAUSE TestVet/4\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== RUN TestTags/x_testtag_y\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/4","Output":"=== PAUSE TestVet/4\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/4"}
{"Action":"run","Test":"TestVet/5"}
-{"Action":"output","Test":"TestVet/5","Output":"=== RUN TestVet/5\n"}
-{"Action":"output","Test":"TestVet/5","Output":"=== PAUSE TestVet/5\n"}
+{"Action":"output","Test":"TestVet/5","Output":"=== RUN TestVet/5\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/5","Output":"=== PAUSE TestVet/5\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/5"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== PAUSE TestTags/x_testtag_y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== PAUSE TestTags/x_testtag_y\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags/x_testtag_y"}
{"Action":"run","Test":"TestVet/6"}
-{"Action":"output","Test":"TestVet/6","Output":"=== RUN TestVet/6\n"}
+{"Action":"output","Test":"TestVet/6","Output":"=== RUN TestVet/6\n","OutputType":"frame"}
{"Action":"run","Test":"TestTags/x,testtag,y"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== RUN TestTags/x,testtag,y\n"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== PAUSE TestTags/x,testtag,y\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== RUN TestTags/x,testtag,y\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== PAUSE TestTags/x,testtag,y\n","OutputType":"frame"}
{"Action":"pause","Test":"TestTags/x,testtag,y"}
{"Action":"run","Test":"TestVetDirs/testingpkg"}
-{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== RUN TestVetDirs/testingpkg\n"}
-{"Action":"output","Test":"TestVet/6","Output":"=== PAUSE TestVet/6\n"}
+{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== RUN TestVetDirs/testingpkg\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/6","Output":"=== PAUSE TestVet/6\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/6"}
{"Action":"cont","Test":"TestTags/x,testtag,y"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== CONT TestTags/x,testtag,y\n"}
-{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== PAUSE TestVetDirs/testingpkg\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":"=== CONT TestTags/x,testtag,y\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== PAUSE TestVetDirs/testingpkg\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetDirs/testingpkg"}
{"Action":"run","Test":"TestVetDirs/divergent"}
-{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== RUN TestVetDirs/divergent\n"}
+{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== RUN TestVetDirs/divergent\n","OutputType":"frame"}
{"Action":"run","Test":"TestVet/7"}
-{"Action":"output","Test":"TestVet/7","Output":"=== RUN TestVet/7\n"}
-{"Action":"output","Test":"TestVet/7","Output":"=== PAUSE TestVet/7\n"}
+{"Action":"output","Test":"TestVet/7","Output":"=== RUN TestVet/7\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/7","Output":"=== PAUSE TestVet/7\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVet/7"}
-{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== PAUSE TestVetDirs/divergent\n"}
+{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== PAUSE TestVetDirs/divergent\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetDirs/divergent"}
{"Action":"cont","Test":"TestTags/x_testtag_y"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== CONT TestTags/x_testtag_y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":"=== CONT TestTags/x_testtag_y\n","OutputType":"frame"}
{"Action":"cont","Test":"TestTags/testtag"}
-{"Action":"output","Test":"TestTags/testtag","Output":"=== CONT TestTags/testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":"=== CONT TestTags/testtag\n","OutputType":"frame"}
{"Action":"run","Test":"TestVetDirs/buildtag"}
-{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== RUN TestVetDirs/buildtag\n"}
-{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== PAUSE TestVetDirs/buildtag\n"}
+{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== RUN TestVetDirs/buildtag\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== PAUSE TestVetDirs/buildtag\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetDirs/buildtag"}
{"Action":"cont","Test":"TestVet/0"}
-{"Action":"output","Test":"TestVet/0","Output":"=== CONT TestVet/0\n"}
+{"Action":"output","Test":"TestVet/0","Output":"=== CONT TestVet/0\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVet/4"}
-{"Action":"output","Test":"TestVet/4","Output":"=== CONT TestVet/4\n"}
+{"Action":"output","Test":"TestVet/4","Output":"=== CONT TestVet/4\n","OutputType":"frame"}
{"Action":"run","Test":"TestVetDirs/incomplete"}
-{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== RUN TestVetDirs/incomplete\n"}
-{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== PAUSE TestVetDirs/incomplete\n"}
+{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== RUN TestVetDirs/incomplete\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== PAUSE TestVetDirs/incomplete\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetDirs/incomplete"}
{"Action":"run","Test":"TestVetDirs/cgo"}
-{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== RUN TestVetDirs/cgo\n"}
-{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== PAUSE TestVetDirs/cgo\n"}
+{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== RUN TestVetDirs/cgo\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== PAUSE TestVetDirs/cgo\n","OutputType":"frame"}
{"Action":"pause","Test":"TestVetDirs/cgo"}
{"Action":"cont","Test":"TestVet/7"}
-{"Action":"output","Test":"TestVet/7","Output":"=== CONT TestVet/7\n"}
+{"Action":"output","Test":"TestVet/7","Output":"=== CONT TestVet/7\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVet/6"}
-{"Action":"output","Test":"TestVet/6","Output":"=== CONT TestVet/6\n"}
-{"Action":"output","Test":"TestVetVerbose","Output":"--- PASS: TestVetVerbose (0.04s)\n"}
+{"Action":"output","Test":"TestVet/6","Output":"=== CONT TestVet/6\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetVerbose","Output":"--- PASS: TestVetVerbose (0.04s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestVetVerbose"}
{"Action":"cont","Test":"TestVet/5"}
-{"Action":"output","Test":"TestVet/5","Output":"=== CONT TestVet/5\n"}
+{"Action":"output","Test":"TestVet/5","Output":"=== CONT TestVet/5\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVet/3"}
-{"Action":"output","Test":"TestVet/3","Output":"=== CONT TestVet/3\n"}
+{"Action":"output","Test":"TestVet/3","Output":"=== CONT TestVet/3\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVet/2"}
-{"Action":"output","Test":"TestVet/2","Output":"=== CONT TestVet/2\n"}
-{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n"}
+{"Action":"output","Test":"TestVet/2","Output":"=== CONT TestVet/2\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n","OutputType":"frame"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestTags/x_testtag_y","Output":" vet_test.go:187: -tags=x testtag y\n"}
{"Action":"pass","Test":"TestTags/x_testtag_y"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestTags/x,testtag,y","Output":" vet_test.go:187: -tags=x,testtag,y\n"}
{"Action":"pass","Test":"TestTags/x,testtag,y"}
-{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestTags/testtag","Output":" vet_test.go:187: -tags=testtag\n"}
{"Action":"pass","Test":"TestTags/testtag"}
{"Action":"pass","Test":"TestTags"}
{"Action":"cont","Test":"TestVet/1"}
-{"Action":"output","Test":"TestVet/1","Output":"=== CONT TestVet/1\n"}
+{"Action":"output","Test":"TestVet/1","Output":"=== CONT TestVet/1\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVetDirs/testingpkg"}
-{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== CONT TestVetDirs/testingpkg\n"}
+{"Action":"output","Test":"TestVetDirs/testingpkg","Output":"=== CONT TestVetDirs/testingpkg\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVetDirs/buildtag"}
-{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== CONT TestVetDirs/buildtag\n"}
+{"Action":"output","Test":"TestVetDirs/buildtag","Output":"=== CONT TestVetDirs/buildtag\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVetDirs/divergent"}
-{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== CONT TestVetDirs/divergent\n"}
+{"Action":"output","Test":"TestVetDirs/divergent","Output":"=== CONT TestVetDirs/divergent\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVetDirs/incomplete"}
-{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== CONT TestVetDirs/incomplete\n"}
+{"Action":"output","Test":"TestVetDirs/incomplete","Output":"=== CONT TestVetDirs/incomplete\n","OutputType":"frame"}
{"Action":"cont","Test":"TestVetDirs/cgo"}
-{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== CONT TestVetDirs/cgo\n"}
-{"Action":"output","Test":"TestVet","Output":"--- PASS: TestVet (0.39s)\n"}
-{"Action":"output","Test":"TestVet/5","Output":" --- PASS: TestVet/5 (0.07s)\n"}
+{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== CONT TestVetDirs/cgo\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet","Output":"--- PASS: TestVet (0.39s)\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVet/5","Output":" --- PASS: TestVet/5 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/5","Output":" vet_test.go:114: files: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
{"Action":"pass","Test":"TestVet/5"}
-{"Action":"output","Test":"TestVet/3","Output":" --- PASS: TestVet/3 (0.07s)\n"}
+{"Action":"output","Test":"TestVet/3","Output":" --- PASS: TestVet/3 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/3","Output":" vet_test.go:114: files: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
{"Action":"pass","Test":"TestVet/3"}
-{"Action":"output","Test":"TestVet/6","Output":" --- PASS: TestVet/6 (0.07s)\n"}
+{"Action":"output","Test":"TestVet/6","Output":" --- PASS: TestVet/6 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/6","Output":" vet_test.go:114: files: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
{"Action":"pass","Test":"TestVet/6"}
-{"Action":"output","Test":"TestVet/2","Output":" --- PASS: TestVet/2 (0.07s)\n"}
+{"Action":"output","Test":"TestVet/2","Output":" --- PASS: TestVet/2 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/2","Output":" vet_test.go:114: files: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
{"Action":"pass","Test":"TestVet/2"}
-{"Action":"output","Test":"TestVet/0","Output":" --- PASS: TestVet/0 (0.13s)\n"}
+{"Action":"output","Test":"TestVet/0","Output":" --- PASS: TestVet/0 (0.13s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/0","Output":" vet_test.go:114: files: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
{"Action":"pass","Test":"TestVet/0"}
-{"Action":"output","Test":"TestVet/4","Output":" --- PASS: TestVet/4 (0.16s)\n"}
+{"Action":"output","Test":"TestVet/4","Output":" --- PASS: TestVet/4 (0.16s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/4","Output":" vet_test.go:114: files: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
{"Action":"pass","Test":"TestVet/4"}
-{"Action":"output","Test":"TestVet/1","Output":" --- PASS: TestVet/1 (0.07s)\n"}
+{"Action":"output","Test":"TestVet/1","Output":" --- PASS: TestVet/1 (0.07s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/1","Output":" vet_test.go:114: files: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
{"Action":"pass","Test":"TestVet/1"}
-{"Action":"output","Test":"TestVet/7","Output":" --- PASS: TestVet/7 (0.19s)\n"}
+{"Action":"output","Test":"TestVet/7","Output":" --- PASS: TestVet/7 (0.19s)\n","OutputType":"frame"}
{"Action":"output","Test":"TestVet/7","Output":" vet_test.go:114: files: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
{"Action":"pass","Test":"TestVet/7"}
{"Action":"pass","Test":"TestVet"}
-{"Action":"output","Test":"TestVetDirs","Output":"--- PASS: TestVetDirs (0.01s)\n"}
-{"Action":"output","Test":"TestVetDirs/testingpkg","Output":" --- PASS: TestVetDirs/testingpkg (0.06s)\n"}
+{"Action":"output","Test":"TestVetDirs","Output":"--- PASS: TestVetDirs (0.01s)\n","OutputType":"frame"}
+{"Action":"output","Test":"TestVetDirs/testingpkg","Output":" --- PASS: TestVetDirs/testingpkg (0.06s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestVetDirs/testingpkg"}
-{"Action":"output","Test":"TestVetDirs/divergent","Output":" --- PASS: TestVetDirs/divergent (0.05s)\n"}
+{"Action":"output","Test":"TestVetDirs/divergent","Output":" --- PASS: TestVetDirs/divergent (0.05s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestVetDirs/divergent"}
-{"Action":"output","Test":"TestVetDirs/buildtag","Output":" --- PASS: TestVetDirs/buildtag (0.06s)\n"}
+{"Action":"output","Test":"TestVetDirs/buildtag","Output":" --- PASS: TestVetDirs/buildtag (0.06s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestVetDirs/buildtag"}
-{"Action":"output","Test":"TestVetDirs/incomplete","Output":" --- PASS: TestVetDirs/incomplete (0.05s)\n"}
+{"Action":"output","Test":"TestVetDirs/incomplete","Output":" --- PASS: TestVetDirs/incomplete (0.05s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestVetDirs/incomplete"}
-{"Action":"output","Test":"TestVetDirs/cgo","Output":" --- PASS: TestVetDirs/cgo (0.04s)\n"}
+{"Action":"output","Test":"TestVetDirs/cgo","Output":" --- PASS: TestVetDirs/cgo (0.04s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestVetDirs/cgo"}
{"Action":"pass","Test":"TestVetDirs"}
-{"Action":"output","Test":"TestVetAsm","Output":"--- PASS: TestVetAsm (0.75s)\n"}
+{"Action":"output","Test":"TestVetAsm","Output":"--- PASS: TestVetAsm (0.75s)\n","OutputType":"frame"}
{"Action":"pass","Test":"TestVetAsm"}
-{"Action":"output","Output":"PASS\n"}
+{"Action":"output","Output":"PASS\n","OutputType":"frame"}
{"Action":"output","Output":"ok \tcmd/vet\t(cached)\n"}
{"Action":"pass"}
diff --git a/src/cmd/test2json/main.go b/src/cmd/test2json/main.go
index dc033b1d5c..ff8cc9c8d5 100644
--- a/src/cmd/test2json/main.go
+++ b/src/cmd/test2json/main.go
@@ -41,6 +41,7 @@
// Test string
// Elapsed float64 // seconds
// Output string
+// OutputType string
// FailedBuild string
// }
//
@@ -85,6 +86,14 @@
// failed to build. This matches the ImportPath field of the "go list" output,
// as well as the BuildEvent.ImportPath field as emitted by "go build -json".
//
+// The OutputType field *may* be set for Action == "output" and indicates the
+// type of output. OutputType will be one of the following:
+//
+// (blank) - regular output
+// frame - test framing, such as "=== RUN ..." or "--- FAIL: ..."
+// error - an error produced by Error(f) or Fatal(f)
+// error-continue - continuation of a multi-line error
+//
// When a benchmark runs, it typically produces a single line of output
// giving timing results. That line is reported in an event with Action == "output"
// and no Test field. If a benchmark logs output or reports a failure
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index fedb0a052d..cad14bea9b 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -219,12 +219,12 @@ func TestTRun(t *T) {
^V--- SKIP: chatty with recursion and json/#00/#01 (N.NNs)
^V=== NAME chatty with recursion and json/#00
^V=== RUN chatty with recursion and json/#00/#02
- sub_test.go:NNN: fail
+^O sub_test.go:NNN: fail^N
^V--- FAIL: chatty with recursion and json/#00/#02 (N.NNs)
^V=== NAME chatty with recursion and json/#00
^V=== RUN chatty with recursion and json/#00/#03
- sub_test.go:NNN: ^[^V^[^[
-^V--- PASS: chatty with recursion and json/#00/#03 (N.NNs)
+^O sub_test.go:NNN: ^[^O^[^N^[^[^N
+^V--- FAIL: chatty with recursion and json/#00/#03 (N.NNs)
^V=== NAME chatty with recursion and json/#00
^V--- FAIL: chatty with recursion and json/#00 (N.NNs)
^V=== NAME chatty with recursion and json
@@ -235,7 +235,7 @@ func TestTRun(t *T) {
t.Run("", func(t *T) {})
t.Run("", func(t *T) { t.Skip("skip") })
t.Run("", func(t *T) { t.Fatal("fail") })
- t.Run("", func(t *T) { t.Log(string(markFraming) + string(markEscape)) })
+ t.Run("", func(t *T) { t.Error(string(markErrBegin) + string(markErrEnd) + string(markEscape)) })
})
},
}, {
@@ -832,6 +832,8 @@ func TestBRun(t *T) {
func makeRegexp(s string) string {
s = regexp.QuoteMeta(s)
s = strings.ReplaceAll(s, "^V", string(markFraming))
+ s = strings.ReplaceAll(s, "^O", string(markErrBegin))
+ s = strings.ReplaceAll(s, "^N", string(markErrEnd))
s = strings.ReplaceAll(s, "^\\[", string(markEscape))
s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d\d?:`)
s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`)
@@ -842,6 +844,8 @@ func makeRegexp(s string) string {
// to text notation.
func notateOutput(s string) string {
s = strings.ReplaceAll(s, string(markFraming), "^V")
+ s = strings.ReplaceAll(s, string(markErrBegin), "^O")
+ s = strings.ReplaceAll(s, string(markErrEnd), "^N")
s = strings.ReplaceAll(s, string(markEscape), "^[")
return s
}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 6cce1a451f..626772e57a 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -563,8 +563,10 @@ func (f *chattyFlag) Get() any {
}
const (
- markFraming byte = 'V' &^ '@' // ^V: framing
- markEscape byte = '[' &^ '@' // ^[: escape
+ markFraming byte = 'V' &^ '@' // ^V: framing
+ markErrBegin byte = 'O' &^ '@' // ^O: start of error
+ markErrEnd byte = 'N' &^ '@' // ^N: end of error
+ markEscape byte = '[' &^ '@' // ^[: escape
)
func (f *chattyFlag) prefix() string {
@@ -627,6 +629,60 @@ func (p *chattyPrinter) Printf(testName, format string, args ...any) {
fmt.Fprintf(p.w, format, args...)
}
+type stringWriter interface {
+ io.Writer
+ io.StringWriter
+}
+
+// escapeWriter is a [io.Writer] that escapes test framing markers.
+type escapeWriter struct {
+ w stringWriter
+}
+
+func (w escapeWriter) WriteString(s string) (int, error) {
+ return w.Write([]byte(s))
+}
+
+func (w escapeWriter) Write(p []byte) (int, error) {
+ var n, m int
+ var err error
+ for len(p) > 0 {
+ i := w.nextMark(p)
+ if i < 0 {
+ break
+ }
+
+ m, err = w.w.Write(p[:i])
+ n += m
+ if err != nil {
+ break
+ }
+
+ m, err = w.w.Write([]byte{markEscape, p[i]})
+ if err != nil {
+ break
+ }
+ if m != 2 {
+ return n, fmt.Errorf("short write")
+ }
+ n++
+ p = p[i+1:]
+ }
+ m, err = w.w.Write(p)
+ n += m
+ return n, err
+}
+
+func (escapeWriter) nextMark(p []byte) int {
+ for i, b := range p {
+ switch b {
+ case markFraming, markErrBegin, markErrEnd, markEscape:
+ return i
+ }
+ }
+ return -1
+}
+
// The maximum number of stack frames to go through when skipping helper functions for
// the purpose of decorating log messages.
const maxStackLen = 50
@@ -1028,7 +1084,7 @@ func (c *common) FailNow() {
// log generates the output. It is always at the same stack depth. log inserts
// indentation and the final newline if necessary. It prefixes the string
// with the file and line of the call site.
-func (c *common) log(s string) {
+func (c *common) log(s string, isErr bool) {
s = strings.TrimSuffix(s, "\n")
// Second and subsequent lines are indented 4 spaces. This is in addition to
@@ -1049,7 +1105,7 @@ func (c *common) log(s string) {
// Output buffered logs.
n.flushPartial()
- n.o.Write([]byte(s))
+ n.o.write([]byte(s), isErr)
}
// destination selects the test to which output should be appended. It returns the
@@ -1137,6 +1193,10 @@ type outputWriter struct {
// Write writes a log message to the test's output stream, properly formatted and
// indented. It may not be called after a test function and all its parents return.
func (o *outputWriter) Write(p []byte) (int, error) {
+ return o.write(p, false)
+}
+
+func (o *outputWriter) write(p []byte, isErr bool) (int, error) {
// o can be nil if this is called from a top-level *TB that is no longer active.
// Just ignore the message in that case.
if o == nil || o.c == nil {
@@ -1158,7 +1218,7 @@ func (o *outputWriter) Write(p []byte) (int, error) {
line = slices.Concat(o.partial, line)
o.partial = o.partial[:0]
}
- o.writeLine(line)
+ o.writeLine(line, isErr && i == 0, isErr && i == last-1)
}
// Save partial line for next call.
o.partial = append(o.partial, lines[last]...)
@@ -1167,22 +1227,41 @@ func (o *outputWriter) Write(p []byte) (int, error) {
}
// writeLine generates the output for a given line.
-func (o *outputWriter) writeLine(b []byte) {
- if !o.c.done && (o.c.chatty != nil) {
- // Escape the framing marker.
- b = escapeMarkers(b)
+func (o *outputWriter) writeLine(b []byte, errBegin, errEnd bool) {
+ if o.c.done || (o.c.chatty == nil) {
+ o.c.output = append(o.c.output, indent...)
+ o.c.output = append(o.c.output, b...)
+ return
+ }
- if o.c.bench {
- // Benchmarks don't print === CONT, so we should skip the test
- // printer and just print straight to stdout.
- fmt.Printf("%s%s", indent, b)
- } else {
- o.c.chatty.Printf(o.c.name, "%s%s", indent, b)
+ // Escape the framing marker.
+ b = escapeMarkers(b)
+
+ // If this is the start of an error, add ^O to the start of the output.
+ var strErrBegin, strErrEnd string
+ if errBegin && o.c.chatty.json {
+ strErrBegin = string(markErrBegin)
+ }
+
+ // If this is the end of an error, add ^N to the end of the output. If the
+ // last character of the output is \n, add ^N before the \n, otherwise
+ // test2json will not handle it correctly.
+ var c []byte
+ if errEnd && o.c.chatty.json {
+ i := len(b)
+ if len(b) > 0 && b[i-1] == '\n' {
+ b, c = b[:i-1], b[i-1:]
}
- return
+ strErrEnd = string(markErrEnd)
+ }
+
+ if o.c.bench {
+ // Benchmarks don't print === CONT, so we should skip the test
+ // printer and just print straight to stdout.
+ fmt.Printf("%s%s%s%s%s", strErrBegin, indent, b, strErrEnd, c)
+ } else {
+ o.c.chatty.Printf(o.c.name, "%s%s%s%s%s", strErrBegin, indent, b, strErrEnd, c)
}
- o.c.output = append(o.c.output, indent...)
- o.c.output = append(o.c.output, b...)
}
func escapeMarkers(b []byte) []byte {
@@ -1211,7 +1290,7 @@ func escapeMarkers(b []byte) []byte {
func nextMark(b []byte) int {
for i, b := range b {
switch b {
- case markFraming, markEscape:
+ case markFraming, markEscape, markErrBegin, markErrEnd:
return i
}
}
@@ -1225,7 +1304,7 @@ func nextMark(b []byte) int {
// It is an error to call Log after a test or benchmark returns.
func (c *common) Log(args ...any) {
c.checkFuzzFn("Log")
- c.log(fmt.Sprintln(args...))
+ c.log(fmt.Sprintln(args...), false)
}
// Logf formats its arguments according to the format, analogous to [fmt.Printf], and
@@ -1236,48 +1315,48 @@ func (c *common) Log(args ...any) {
// It is an error to call Logf after a test or benchmark returns.
func (c *common) Logf(format string, args ...any) {
c.checkFuzzFn("Logf")
- c.log(fmt.Sprintf(format, args...))
+ c.log(fmt.Sprintf(format, args...), false)
}
// Error is equivalent to Log followed by Fail.
func (c *common) Error(args ...any) {
c.checkFuzzFn("Error")
- c.log(fmt.Sprintln(args...))
+ c.log(fmt.Sprintln(args...), true)
c.Fail()
}
// Errorf is equivalent to Logf followed by Fail.
func (c *common) Errorf(format string, args ...any) {
c.checkFuzzFn("Errorf")
- c.log(fmt.Sprintf(format, args...))
+ c.log(fmt.Sprintf(format, args...), true)
c.Fail()
}
// Fatal is equivalent to Log followed by FailNow.
func (c *common) Fatal(args ...any) {
c.checkFuzzFn("Fatal")
- c.log(fmt.Sprintln(args...))
+ c.log(fmt.Sprintln(args...), true)
c.FailNow()
}
// Fatalf is equivalent to Logf followed by FailNow.
func (c *common) Fatalf(format string, args ...any) {
c.checkFuzzFn("Fatalf")
- c.log(fmt.Sprintf(format, args...))
+ c.log(fmt.Sprintf(format, args...), true)
c.FailNow()
}
// Skip is equivalent to Log followed by SkipNow.
func (c *common) Skip(args ...any) {
c.checkFuzzFn("Skip")
- c.log(fmt.Sprintln(args...))
+ c.log(fmt.Sprintln(args...), false)
c.SkipNow()
}
// Skipf is equivalent to Logf followed by SkipNow.
func (c *common) Skipf(format string, args ...any) {
c.checkFuzzFn("Skipf")
- c.log(fmt.Sprintf(format, args...))
+ c.log(fmt.Sprintf(format, args...), false)
c.SkipNow()
}