test2json

Imports

Imports #

"bytes"
"encoding/json"
"fmt"
"io"
"strconv"
"strings"
"time"
"unicode"
"unicode/utf8"

Constants & Variables

Timestamp const #

const Timestamp Mode = *ast.BinaryExpr

benchmark var #

var benchmark = *ast.CallExpr

bigFail var #

printed by test after a normal test failure.

var bigFail = *ast.CallExpr

bigFailErrorPrefix var #

printed by 'go test' along with an error if the test binary terminates with an error.

var bigFailErrorPrefix = *ast.CallExpr

bigPass var #

printed by test on successful run.

var bigPass = *ast.CallExpr

emptyName var #

an === NAME line with no test name, if trailing spaces are deleted

var emptyName = *ast.CallExpr

emptyNameLine var #

var emptyNameLine = *ast.CallExpr

fourSpace var #

var fourSpace = *ast.CallExpr

inBuffer var #

inBuffer and outBuffer are the input and output buffer sizes. They're variables so that they can be reduced during testing. The input buffer needs to be able to hold any single test directive line we want to recognize, like: --- PASS: very/nested/s/u/b/t/e/s/t If anyone reports a test directive line > 4k not working, it will be defensible to suggest they restructure their test or test names. The output buffer must be >= utf8.UTFMax, so that it can accumulate any single UTF8 sequence. Lines that fit entirely within the output buffer are emitted in single output events. Otherwise they are split into multiple events. The output buffer size therefore limits the size of the encoding of a single JSON output event. 1k seems like a reasonable balance between wanting to avoid splitting an output line and not wanting to generate enormous output events.

var inBuffer = 4096

marker const #

const marker = *ast.CallExpr

outBuffer var #

inBuffer and outBuffer are the input and output buffer sizes. They're variables so that they can be reduced during testing. The input buffer needs to be able to hold any single test directive line we want to recognize, like: --- PASS: very/nested/s/u/b/t/e/s/t If anyone reports a test directive line > 4k not working, it will be defensible to suggest they restructure their test or test names. The output buffer must be >= utf8.UTFMax, so that it can accumulate any single UTF8 sequence. Lines that fit entirely within the output buffer are emitted in single output events. Otherwise they are split into multiple events. The output buffer size therefore limits the size of the encoding of a single JSON output event. 1k seems like a reasonable balance between wanting to avoid splitting an output line and not wanting to generate enormous output events.

var outBuffer = 1024

reports var #

var reports = [][]byte{...}

skipLinePrefix var #

var skipLinePrefix = *ast.CallExpr

skipLineSuffix var #

var skipLineSuffix = *ast.CallExpr

updates var #

var updates = [][]byte{...}

Type Aliases

Mode type #

Mode controls details of the conversion.

type Mode int

textBytes type #

textBytes is a hack to get JSON to emit a []byte as a string without actually copying it to a string. It implements encoding.TextMarshaler, which returns its text form as a []byte, and then json encodes that text form as a string (which was our goal).

type textBytes []byte

Structs

Converter struct #

A Converter holds the state of a test-to-JSON conversion. It implements io.WriteCloser; the caller writes test output in, and the converter writes JSON output to w.

type Converter struct {
w io.Writer
pkg string
mode Mode
start time.Time
testName string
report []*event
result string
input lineBuffer
output lineBuffer
needMarker bool
failedBuild string
}

event struct #

event is the JSON struct we emit.

type event struct {
Time *time.Time `json:",omitempty"`
Action string
Package string `json:",omitempty"`
Test string `json:",omitempty"`
Elapsed *float64 `json:",omitempty"`
Output *textBytes `json:",omitempty"`
FailedBuild string `json:",omitempty"`
}

lineBuffer struct #

A lineBuffer is an I/O buffer that reacts to writes by invoking input-processing callbacks on whole lines or (for long lines that have been split) line fragments. It should be initialized with b set to a buffer of length 0 but non-zero capacity, and line and part set to the desired input processors. The lineBuffer will call line(x) for any whole line x (including the final newline) that fits entirely in cap(b). It will handle input lines longer than cap(b) by calling part(x) for sections of the line. The line will be split at UTF8 boundaries, and the final call to part for a long line includes the final newline.

type lineBuffer struct {
b []byte
mid bool
line func([]byte)
part func([]byte)
}

Functions

Close method #

Close marks the end of the go test output. It flushes any pending input and then output (only partial lines at this point) and then emits the final overall package-level pass/fail event.

func (c *Converter) Close() error

Exited method #

Exited marks the test process as having exited with the given error.

func (c *Converter) Exited(err error)

MarshalText method #

func (b textBytes) MarshalText() ([]byte, error)

NewConverter function #

NewConverter returns a "test to json" converter. Writes on the returned writer are written as JSON to w, with minimal delay. The writes to w are whole JSON events ending in \n, so that it is safe to run multiple tests writing to multiple converters writing to a single underlying output stream w. As long as the underlying output w can handle concurrent writes from multiple goroutines, the result will be a JSON stream describing the relative ordering of execution in all the concurrent tests. The mode flag adjusts the behavior of the converter. Passing ModeTime includes event timestamps and elapsed times. The pkg string, if present, specifies the import path to report in the JSON stream.

func NewConverter(w io.Writer, pkg string, mode Mode) *Converter

SetFailedBuild method #

SetFailedBuild sets the package ID that is the root cause of a build failure for this test. This will be reported in the final "fail" event's FailedBuild field.

func (c *Converter) SetFailedBuild(pkgID string)

Write method #

Write writes the test input to the converter.

func (c *Converter) Write(b []byte) (int, error)

flush method #

flush flushes the line buffer.

func (l *lineBuffer) flush()

flushReport method #

flushReport flushes all pending PASS/FAIL reports at levels >= depth.

func (c *Converter) flushReport(depth int)

handleInputLine method #

handleInputLine handles a single whole test output line. It must write the line to c.output but may choose to do so before or after emitting other events.

func (c *Converter) handleInputLine(line []byte)

indexEOL function #

indexEOL finds the index of a line ending, returning its position and output width. A line ending is either a \n or the empty string just before a ^V not beginning a line. The output width for \n is 1 (meaning it should be printed) but the output width for ^V is 0 (meaning it should be left to begin the next line).

func indexEOL(b []byte) (pos int, wid int)

isBenchmarkName function #

isBenchmarkName reports whether b is a valid benchmark name that might appear as the first field in a benchmark result line.

func isBenchmarkName(b []byte) bool

trimUTF8 function #

trimUTF8 returns a length t as close to len(b) as possible such that b[:t] does not end in the middle of a possibly-valid UTF-8 sequence. If a large text buffer must be split before position i at the latest, splitting at position trimUTF(b[:i]) avoids splitting a UTF-8 sequence.

func trimUTF8(b []byte) int

write method #

write writes b to the buffer.

func (l *lineBuffer) write(b []byte)

writeEvent method #

writeEvent writes a single event. It adds the package, time (if requested), and test name (if needed).

func (c *Converter) writeEvent(e *event)

writeOutputEvent method #

writeOutputEvent writes a single output event with the given bytes.

func (c *Converter) writeOutputEvent(out []byte)

Generated with Arrow