diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..010c666c --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,17 @@ +name: ci + +on: + pull_request: + push: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: '1.20' + cache: true + - run: go build . + - run: ./gotestsum -f testname diff --git a/.project/golangci-lint.yml b/.project/golangci-lint.yml index 5ef5f797..43d400f5 100644 --- a/.project/golangci-lint.yml +++ b/.project/golangci-lint.yml @@ -31,7 +31,6 @@ linters: - deadcode - depguard - errcheck - - gocognit - goconst - gofmt - goimports diff --git a/.project/goreleaser.yml b/.project/goreleaser.yml index 3a4cf501..fccd9ab9 100644 --- a/.project/goreleaser.yml +++ b/.project/goreleaser.yml @@ -13,6 +13,7 @@ builds: - freebsd - windows - linux + - illumos goarch: - amd64 - arm64 @@ -36,6 +37,14 @@ builds: goarch: s390x - goos: windows goarch: ppc64le + - goos: illumos + goarch: arm + - goos: illumos + goarch: arm64 + - goos: illumos + goarch: s390x + - goos: illumos + goarch: ppc64le checksum: name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt' diff --git a/README.md b/README.md index 0373c9e1..a8acfc41 100644 --- a/README.md +++ b/README.md @@ -40,14 +40,16 @@ The `--format` flag or `GOTESTSUM_FORMAT` environment variable set the format th is used to print the test names, and possibly test output, as the tests run. Most outputs use color to highlight pass, fail, or skip. -The `--format-hivis` flag changes the icons used by `pkgname` formats to higher -visiblity unicode characters. +The `--format-icons` flag changes the icons used by `pkgname` and `testdox` formats. +You can set the `GOTESTSUM_FORMAT_ICONS` environment variable, instead of the flag. +The nerdfonts icons requires a font from [Nerd Fonts](https://www.nerdfonts.com/). Commonly used formats (see `--help` for a full list): * `dots` - print a character for each test. * `pkgname` (default) - print a line for each package. * `testname` - print a line for each test and package. + * `testdox` - print a sentence for each test using [gotestdox](https://github.com/bitfield/gotestdox). * `standard-quiet` - the standard `go test` format. * `standard-verbose` - the standard `go test -v` format. @@ -139,7 +141,8 @@ test run has completed. The binary will be run with the following environment variables set: ``` -GOTESTSUM_FORMAT # gotestsum format (ex: short) +GOTESTSUM_ELAPSED # test run time in seconds (ex: 2.45s) +GOTESTSUM_FORMAT # gotestsum format (ex: pkgname) GOTESTSUM_JSONFILE # path to the jsonfile, empty if no file path was given GOTESTSUM_JUNITFILE # path to the junit.xml file, empty if no file path was given TESTS_ERRORS # number of errors @@ -158,9 +161,15 @@ package may be used to parse the JSON file output. First install the example notification command with `go get gotest.tools/gotestsum/contrib/notify`. The command will be downloaded to `$GOPATH/bin` as `notify`. Note that this -example `notify` command only works on macOS with +example `notify` command only works on Linux with `notify-send` and on macOS with [terminal-notifer](https://github.com/julienXX/terminal-notifier) installed. +On Linux, you need to have some "test-pass" and "test-fail" icons installed in your icon theme. +Some sample icons can be found in `contrib/notify`, and can be installed with `make install`. + +On Windows, you can install [notify-send.exe](https://github.com/vaskovsky/notify-send) +but it does not support custom icons so will have to use the basic "info" and "error". + ``` gotestsum --post-run-command notify ``` @@ -438,6 +447,7 @@ The projects below use (or have used) gotestsum. * [dex](https://github.com/dexidp/dex/blob/master/Makefile) * [coder](https://github.com/coder/coder/blob/main/Makefile) * [docker/cli](https://github.com/docker/cli/blob/master/Makefile) +* [mattermost](https://github.com/mattermost/mattermost/blob/master/server/Makefile) Please open a GitHub issue or pull request to add or remove projects from this list. diff --git a/cmd/handler.go b/cmd/handler.go index 8c472056..0da218d5 100644 --- a/cmd/handler.go +++ b/cmd/handler.go @@ -107,6 +107,14 @@ func newEventHandler(opts *options) (*eventHandler, error) { err: bufio.NewWriter(opts.stderr), maxFails: opts.maxFails, } + + switch opts.format { + case "dots", "dots-v1", "dots-v2": + // Discard the error from the handler to prevent extra lines. The + // error will be printed in the summary. + handler.err = bufio.NewWriter(io.Discard) + } + var err error if opts.jsonFile != "" { _ = os.MkdirAll(filepath.Dir(opts.jsonFile), 0o755) @@ -153,6 +161,7 @@ func postRunHook(opts *options, execution *testjson.Execution) error { if len(command) == 0 { return nil } + log.Debugf("exec: %s", command) cmd := exec.Command(command[0], command[1:]...) cmd.Stdout = opts.stdout @@ -162,6 +171,7 @@ func postRunHook(opts *options, execution *testjson.Execution) error { "GOTESTSUM_JSONFILE="+opts.jsonFile, "GOTESTSUM_JSONFILE_TIMING_EVENTS="+opts.jsonFileTimingEvents, "GOTESTSUM_JUNITFILE="+opts.junitFile, + fmt.Sprintf("GOTESTSUM_ELAPSED=%.3fs", execution.Elapsed().Seconds()), fmt.Sprintf("TESTS_TOTAL=%d", execution.Total()), fmt.Sprintf("TESTS_FAILED=%d", len(execution.Failed())), fmt.Sprintf("TESTS_SKIPPED=%d", len(execution.Skipped())), diff --git a/cmd/handler_test.go b/cmd/handler_test.go index 48322dee..d45bdd1a 100644 --- a/cmd/handler_test.go +++ b/cmd/handler_test.go @@ -2,14 +2,17 @@ package cmd import ( "bytes" - "io/ioutil" + "io" "os" "path/filepath" "strings" "testing" + "gotest.tools/gotestsum/internal/junitxml" + "gotest.tools/gotestsum/internal/text" "gotest.tools/gotestsum/testjson" "gotest.tools/v3/assert" + "gotest.tools/v3/assert/cmp" "gotest.tools/v3/env" "gotest.tools/v3/fs" "gotest.tools/v3/golden" @@ -30,11 +33,21 @@ func TestPostRunHook(t *testing.T) { } env.Patch(t, "GOTESTSUM_FORMAT", "short") + env.Patch(t, "GOTESTSUM_FORMAT_ICONS", "default") exec := newExecFromTestData(t) err = postRunHook(opts, exec) assert.NilError(t, err) - golden.Assert(t, buf.String(), "post-run-hook-expected") + + actual := text.ProcessLines(t, buf, func(line string) string { + if strings.HasPrefix(line, "GOTESTSUM_ELAPSED=0.0") && + strings.HasSuffix(line, "s") { + i := strings.Index(line, "=") + return line[:i] + "=0.000s" + } + return line + }) + golden.Assert(t, actual, "post-run-hook-expected") } func newExecFromTestData(t *testing.T) *testjson.Execution { @@ -60,6 +73,8 @@ func (bufferCloser) Close() error { return nil } func (bufferCloser) Sync() error { return nil } func TestEventHandler_Event_WithMissingActionFail(t *testing.T) { + t.Setenv("GITHUB_ACTIONS", "no") + buf := new(bufferCloser) errBuf := new(bytes.Buffer) format := testjson.NewEventFormatter(errBuf, "testname", testjson.FormatOptions{}) @@ -79,7 +94,7 @@ func TestEventHandler_Event_WithMissingActionFail(t *testing.T) { } func TestEventHandler_Event_MaxFails(t *testing.T) { - format := testjson.NewEventFormatter(ioutil.Discard, "testname", testjson.FormatOptions{}) + format := testjson.NewEventFormatter(io.Discard, "testname", testjson.FormatOptions{}) source := golden.Get(t, "../../testjson/testdata/input/go-test-json.out") cfg := testjson.ScanConfig{ @@ -123,3 +138,40 @@ func TestWriteJunitFile_CreatesDirectory(t *testing.T) { _, err = os.Stat(junitFile) assert.NilError(t, err) } + +func TestScanTestOutput_TestTimeoutPanicRace(t *testing.T) { + run := func(t *testing.T, name string) { + format := testjson.NewEventFormatter(io.Discard, "testname", testjson.FormatOptions{}) + + source := golden.Get(t, "input/go-test-json-"+name+".out") + cfg := testjson.ScanConfig{ + Stdout: bytes.NewReader(source), + Handler: &eventHandler{formatter: format}, + } + exec, err := testjson.ScanTestOutput(cfg) + assert.NilError(t, err) + + out := new(bytes.Buffer) + testjson.PrintSummary(out, exec, testjson.SummarizeAll) + + actual := text.ProcessLines(t, out, text.OpRemoveSummaryLineElapsedTime) + golden.Assert(t, actual, "expected/"+name+"-summary") + + var buf bytes.Buffer + err = junitxml.Write(&buf, exec, junitxml.Config{}) + assert.NilError(t, err) + + assert.Assert(t, cmp.Contains(buf.String(), "panic: test timed out")) + } + + testCases := []string{ + "panic-race-1", + "panic-race-2", + } + + for _, tc := range testCases { + t.Run(tc, func(t *testing.T) { + run(t, tc) + }) + } +} diff --git a/cmd/main.go b/cmd/main.go index 57d5bca6..cd8b2ff7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -56,13 +56,18 @@ func setupFlags(name string) (*pflag.FlagSet, *options) { flags.Usage = func() { usage(os.Stdout, name, flags) } + flags.StringVarP(&opts.format, "format", "f", - lookEnvWithDefault("GOTESTSUM_FORMAT", "short"), + lookEnvWithDefault("GOTESTSUM_FORMAT", "pkgname"), "print format of test input") flags.BoolVar(&opts.formatOptions.HideEmptyPackages, "format-hide-empty-pkg", false, "do not print empty packages in compact formats") flags.BoolVar(&opts.formatOptions.UseHiVisibilityIcons, "format-hivis", false, "use high visibility characters in some formats") + _ = flags.MarkHidden("format-hivis") + flags.StringVar(&opts.formatOptions.Icons, "format-icons", + lookEnvWithDefault("GOTESTSUM_FORMAT_ICONS", ""), + "use different icons, see help for options") flags.BoolVar(&opts.rawCommand, "raw-command", false, "don't prepend 'go test -json' to the 'go test' command") flags.BoolVar(&opts.ignoreNonJSONOutputLines, "ignore-non-json-output-lines", false, @@ -74,7 +79,7 @@ func setupFlags(name string) (*pflag.FlagSet, *options) { flags.StringVar(&opts.jsonFileTimingEvents, "jsonfile-timing-events", lookEnvWithDefault("GOTESTSUM_JSONFILE_TIMING_EVENTS", ""), "write only the pass, skip, and fail TestEvents to the file") - flags.BoolVar(&opts.noColor, "no-color", defaultNoColor, "disable color output") + flags.BoolVar(&opts.noColor, "no-color", defaultNoColor(), "disable color output") flags.Var(opts.hideSummary, "no-summary", "do not print summary of: "+testjson.SummarizeAll.String()) @@ -139,9 +144,19 @@ Formats: pkgname print a line for each package pkgname-and-test-fails print a line for each package and failed test output testname print a line for each test and package + testdox print a sentence for each test using gotestdox + github-actions testname format with github actions log grouping standard-quiet standard go test format standard-verbose standard go test -v format +Format icons: + default the original unicode (✓, ∅, ✖) + hivis higher visibility unicode (✅, ➖, ❌) + text simple text characters (PASS, SKIP, FAIL) + codicons requires a font from https://www.nerdfonts.com/ (  ) + octicons requires a font from https://www.nerdfonts.com/ (  ) + emoticons requires a font from https://www.nerdfonts.com/ (󰇵 󰇶 󰇸) + Commands: %[1]s tool slowest find or skip the slowest tests %[1]s help print this help next @@ -200,12 +215,12 @@ func (o options) Validate() error { return nil } -var defaultNoColor = func() bool { +func defaultNoColor() bool { // fatih/color will only output color when stdout is a terminal which is not // true for many CI environments which support color output. So instead, we // try to detect these CI environments via their environment variables. // This code is based on https://github.com/jwalton/go-supportscolor - if _, exists := os.LookupEnv("CI"); exists { + if value, exists := os.LookupEnv("CI"); exists { var ciEnvNames = []string{ "APPVEYOR", "BUILDKITE", @@ -224,12 +239,15 @@ var defaultNoColor = func() bool { if os.Getenv("CI_NAME") == "codeship" { return false } + if value == "woodpecker" { + return false + } } if _, exists := os.LookupEnv("TEAMCITY_VERSION"); exists { return false } return color.NoColor -}() +} func setupLogging(opts *options) { if opts.debug { @@ -317,7 +335,7 @@ func goTestCmdArgs(opts *options, rerunOpts rerunOpts) []string { return result } - args := opts.args + args := append([]string{}, opts.args...) result := []string{"go", "test"} if len(args) == 0 { diff --git a/cmd/main_e2e_test.go b/cmd/main_e2e_test.go index 1d40f77e..4478600f 100644 --- a/cmd/main_e2e_test.go +++ b/cmd/main_e2e_test.go @@ -31,6 +31,7 @@ func TestE2E_RerunFails(t *testing.T) { if testing.Short() { t.Skip("too slow for short run") } + t.Setenv("GITHUB_ACTIONS", "no") type testCase struct { name string @@ -43,7 +44,7 @@ func TestE2E_RerunFails(t *testing.T) { envVars := osEnviron() envVars["TEST_SEEDFILE"] = tmpFile.Path() - defer env.PatchAll(t, envVars)() + env.PatchAll(t, envVars) flags, opts := setupFlags("gotestsum") assert.NilError(t, flags.Parse(tc.args)) @@ -218,8 +219,9 @@ func TestE2E_MaxFails_EndTestRun(t *testing.T) { envVars := osEnviron() envVars["TEST_SEEDFILE"] = tmpFile.Path() - defer env.PatchAll(t, envVars)() + env.PatchAll(t, envVars) + t.Setenv("GOTESTSUM_FORMAT", "pkgname") flags, opts := setupFlags("gotestsum") args := []string{"--max-fails=2", "--packages=./testdata/e2e/flaky/", "--", "-tags=testdata"} assert.NilError(t, flags.Parse(args)) @@ -244,6 +246,7 @@ func TestE2E_IgnoresWarnings(t *testing.T) { if testing.Short() { t.Skip("too slow for short run") } + t.Setenv("GITHUB_ACTIONS", "no") flags, opts := setupFlags("gotestsum") args := []string{ diff --git a/cmd/main_test.go b/cmd/main_test.go index 526f2ceb..b64ef222 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -10,6 +10,7 @@ import ( "strings" "testing" + "github.com/fatih/color" "gotest.tools/gotestsum/testjson" "gotest.tools/v3/assert" "gotest.tools/v3/assert/cmp" @@ -19,7 +20,8 @@ import ( ) func TestUsage_WithFlagsFromSetupFlags(t *testing.T) { - defer env.PatchAll(t, nil)() + env.PatchAll(t, nil) + patchNoColor(t, false) name := "gotestsum" flags, _ := setupFlags(name) @@ -29,6 +31,14 @@ func TestUsage_WithFlagsFromSetupFlags(t *testing.T) { golden.Assert(t, buf.String(), "gotestsum-help-text") } +func patchNoColor(t *testing.T, value bool) { + orig := color.NoColor + color.NoColor = value + t.Cleanup(func() { + color.NoColor = orig + }) +} + func TestOptions_Validate_FromFlags(t *testing.T) { type testCase struct { name string @@ -97,7 +107,7 @@ func TestGoTestCmdArgs(t *testing.T) { run := func(t *testing.T, name string, tc testCase) { t.Helper() runCase(t, name, func(t *testing.T) { - defer env.PatchAll(t, env.ToMap(tc.env))() + env.PatchAll(t, env.ToMap(tc.env)) actual := goTestCmdArgs(tc.opts, tc.rerunOpts) assert.DeepEqual(t, actual, tc.expected) }) @@ -296,6 +306,21 @@ func TestGoTestCmdArgs(t *testing.T) { }, expected: []string{"go", "test", "-json", "-run=TestOne|TestTwo", "-count", "1", "-run", "./fails"}, }) + t.Run("rerun with -run flag", func(t *testing.T) { + tc := testCase{ + opts: &options{ + args: []string{"-run", "TestExample", "-tags", "some", "-json"}, + packages: []string{"./pkg"}, + }, + rerunOpts: rerunOpts{ + runFlag: "-run=TestOne|TestTwo", + pkg: "./fails", + }, + expected: []string{"go", "test", "-run=TestOne|TestTwo", "-tags", "some", "-json", "./fails"}, + } + run(t, "first", tc) + run(t, "second", tc) + }) } func runCase(t *testing.T, name string, fn func(t *testing.T)) { diff --git a/testjson/testdata/summary/test-timeout-panic-race b/cmd/testdata/expected/panic-race-1-summary similarity index 100% rename from testjson/testdata/summary/test-timeout-panic-race rename to cmd/testdata/expected/panic-race-1-summary diff --git a/cmd/testdata/expected/panic-race-2-summary b/cmd/testdata/expected/panic-race-2-summary new file mode 100644 index 00000000..82b79ac1 --- /dev/null +++ b/cmd/testdata/expected/panic-race-2-summary @@ -0,0 +1,41 @@ + +=== Failed +=== FAIL: example (0.00s) +panic: test timed out after 2s +running tests: + TestSleepsTooLong (2s) + +goroutine 17 [running]: +testing.(*M).startAlarm.func1() + /usr/lib/go/src/testing/testing.go:2241 +0x3c5 +created by time.goFunc + /usr/lib/go/src/time/sleep.go:176 +0x32 + +goroutine 1 [chan receive]: +testing.(*T).Run(0xc0000076c0, {0x52afd7?, 0x4baa25?}, 0x533d98) + /usr/lib/go/src/testing/testing.go:1630 +0x405 +testing.runTests.func1(0x6102c0?) + /usr/lib/go/src/testing/testing.go:2036 +0x45 +testing.tRunner(0xc0000076c0, 0xc000096c88) + /usr/lib/go/src/testing/testing.go:1576 +0x10b +testing.runTests(0xc000026140?, {0x606c80, 0x1, 0x1}, {0x0?, 0x100c0000a6598?, 0x60fae0?}) + /usr/lib/go/src/testing/testing.go:2034 +0x489 +testing.(*M).Run(0xc000026140) + /usr/lib/go/src/testing/testing.go:1906 +0x63a +main.main() + _testmain.go:47 +0x1aa + +goroutine 6 [sleep]: +time.Sleep(0x4a817c800) + /usr/lib/go/src/runtime/time.go:195 +0x135 +gotest.tools/gotestsum/example.TestSleepsTooLong(0x0?) + /home/daniel/pers/code/gotestsum/example/testing_test.go:9 +0x25 +testing.tRunner(0xc000007860, 0x533d98) + /usr/lib/go/src/testing/testing.go:1576 +0x10b +created by testing.(*T).Run + /usr/lib/go/src/testing/testing.go:1629 +0x3ea +FAIL gotest.tools/gotestsum/example 2.003s + +=== FAIL: example TestSleepsTooLong (unknown) + +DONE 1 tests, 2 failures diff --git a/cmd/testdata/gotestsum-help-text b/cmd/testdata/gotestsum-help-text index 048054d7..e4b2c8fc 100644 --- a/cmd/testdata/gotestsum-help-text +++ b/cmd/testdata/gotestsum-help-text @@ -6,9 +6,9 @@ See https://pkg.go.dev/gotest.tools/gotestsum#section-readme for detailed docume Flags: --debug enabled debug logging - -f, --format string print format of test input (default "short") + -f, --format string print format of test input (default "pkgname") --format-hide-empty-pkg do not print empty packages in compact formats - --format-hivis use high visibility characters in some formats + --format-icons string use different icons, see help for options --hide-summary summary hide sections of the summary: skipped,failed,errors,output (default none) --jsonfile string write all TestEvents to file --jsonfile-timing-events string write only the pass, skip, and fail TestEvents to the file @@ -36,9 +36,19 @@ Formats: pkgname print a line for each package pkgname-and-test-fails print a line for each package and failed test output testname print a line for each test and package + testdox print a sentence for each test using gotestdox + github-actions testname format with github actions log grouping standard-quiet standard go test format standard-verbose standard go test -v format +Format icons: + default the original unicode (✓, ∅, ✖) + hivis higher visibility unicode (✅, ➖, ❌) + text simple text characters (PASS, SKIP, FAIL) + codicons requires a font from https://www.nerdfonts.com/ (  ) + octicons requires a font from https://www.nerdfonts.com/ (  ) + emoticons requires a font from https://www.nerdfonts.com/ (󰇵 󰇶 󰇸) + Commands: gotestsum tool slowest find or skip the slowest tests gotestsum help print this help next diff --git a/testjson/testdata/input/go-test-json-panic-race.out b/cmd/testdata/input/go-test-json-panic-race-1.out similarity index 100% rename from testjson/testdata/input/go-test-json-panic-race.out rename to cmd/testdata/input/go-test-json-panic-race-1.out diff --git a/cmd/testdata/input/go-test-json-panic-race-2.out b/cmd/testdata/input/go-test-json-panic-race-2.out new file mode 100644 index 00000000..a512b7b2 --- /dev/null +++ b/cmd/testdata/input/go-test-json-panic-race-2.out @@ -0,0 +1,38 @@ +{"Time":"2023-08-12T12:54:44.132409933-04:00","Action":"start","Package":"gotest.tools/gotestsum/example"} +{"Time":"2023-08-12T12:54:44.133131471-04:00","Action":"run","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong"} +{"Time":"2023-08-12T12:54:44.133140584-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"=== RUN TestSleepsTooLong\n"} +{"Time":"2023-08-12T12:54:46.135570065-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"panic: test timed out after 2s\n"} +{"Time":"2023-08-12T12:54:46.135604434-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"running tests:\n"} +{"Time":"2023-08-12T12:54:46.135608775-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\tTestSleepsTooLong (2s)\n"} +{"Time":"2023-08-12T12:54:46.135611536-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\n"} +{"Time":"2023-08-12T12:54:46.135614121-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"goroutine 17 [running]:\n"} +{"Time":"2023-08-12T12:54:46.135643208-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"testing.(*M).startAlarm.func1()\n"} +{"Time":"2023-08-12T12:54:46.135647115-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:2241 +0x3c5\n"} +{"Time":"2023-08-12T12:54:46.135652292-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"created by time.goFunc\n"} +{"Time":"2023-08-12T12:54:46.135655313-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/time/sleep.go:176 +0x32\n"} +{"Time":"2023-08-12T12:54:46.135657739-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\n"} +{"Time":"2023-08-12T12:54:46.135660238-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"goroutine 1 [chan receive]:\n"} +{"Time":"2023-08-12T12:54:46.135662906-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"testing.(*T).Run(0xc0000076c0, {0x52afd7?, 0x4baa25?}, 0x533d98)\n"} +{"Time":"2023-08-12T12:54:46.135666381-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:1630 +0x405\n"} +{"Time":"2023-08-12T12:54:46.135668821-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"testing.runTests.func1(0x6102c0?)\n"} +{"Time":"2023-08-12T12:54:46.135671151-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:2036 +0x45\n"} +{"Time":"2023-08-12T12:54:46.135673732-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"testing.tRunner(0xc0000076c0, 0xc000096c88)\n"} +{"Time":"2023-08-12T12:54:46.135676164-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:1576 +0x10b\n"} +{"Time":"2023-08-12T12:54:46.135678759-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"testing.runTests(0xc000026140?, {0x606c80, 0x1, 0x1}, {0x0?, 0x100c0000a6598?, 0x60fae0?})\n"} +{"Time":"2023-08-12T12:54:46.135684642-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:2034 +0x489\n"} +{"Time":"2023-08-12T12:54:46.135687261-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"testing.(*M).Run(0xc000026140)\n"} +{"Time":"2023-08-12T12:54:46.135715549-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:1906 +0x63a\n"} +{"Time":"2023-08-12T12:54:46.135718294-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"main.main()\n"} +{"Time":"2023-08-12T12:54:46.135726996-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t_testmain.go:47 +0x1aa\n"} +{"Time":"2023-08-12T12:54:46.135729722-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\n"} +{"Time":"2023-08-12T12:54:46.135732073-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"goroutine 6 [sleep]:\n"} +{"Time":"2023-08-12T12:54:46.135734314-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"time.Sleep(0x4a817c800)\n"} +{"Time":"2023-08-12T12:54:46.13573659-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/runtime/time.go:195 +0x135\n"} +{"Time":"2023-08-12T12:54:46.135739011-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"gotest.tools/gotestsum/example.TestSleepsTooLong(0x0?)\n"} +{"Time":"2023-08-12T12:54:46.135760842-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/home/daniel/pers/code/gotestsum/example/testing_test.go:9 +0x25\n"} +{"Time":"2023-08-12T12:54:46.135763588-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"testing.tRunner(0xc000007860, 0x533d98)\n"} +{"Time":"2023-08-12T12:54:46.135766232-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:1576 +0x10b\n"} +{"Time":"2023-08-12T12:54:46.135768744-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"created by testing.(*T).Run\n"} +{"Time":"2023-08-12T12:54:46.135771535-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Test":"TestSleepsTooLong","Output":"\t/usr/lib/go/src/testing/testing.go:1629 +0x3ea\n"} +{"Time":"2023-08-12T12:54:46.135869063-04:00","Action":"output","Package":"gotest.tools/gotestsum/example","Output":"FAIL\tgotest.tools/gotestsum/example\t2.003s\n"} +{"Time":"2023-08-12T12:54:46.135881864-04:00","Action":"fail","Package":"gotest.tools/gotestsum/example","Elapsed":2.003} diff --git a/cmd/testdata/post-run-hook-expected b/cmd/testdata/post-run-hook-expected index 5c1ebcf5..68241cc9 100644 --- a/cmd/testdata/post-run-hook-expected +++ b/cmd/testdata/post-run-hook-expected @@ -1,4 +1,6 @@ +GOTESTSUM_ELAPSED=0.000s GOTESTSUM_FORMAT=short +GOTESTSUM_FORMAT_ICONS=default GOTESTSUM_JSONFILE=events.json GOTESTSUM_JSONFILE_TIMING_EVENTS=timing.json GOTESTSUM_JUNITFILE=junit.xml diff --git a/cmd/tool/slowest/slowest_test.go b/cmd/tool/slowest/slowest_test.go index a539b374..b25ced9f 100644 --- a/cmd/tool/slowest/slowest_test.go +++ b/cmd/tool/slowest/slowest_test.go @@ -9,7 +9,7 @@ import ( ) func TestUsage_WithFlagsFromSetupFlags(t *testing.T) { - defer env.PatchAll(t, nil)() + env.PatchAll(t, nil) name := "gotestsum tool slowest" flags, _ := setupFlags(name) diff --git a/contrib/notify/.gitignore b/contrib/notify/.gitignore new file mode 100644 index 00000000..f3b695d3 --- /dev/null +++ b/contrib/notify/.gitignore @@ -0,0 +1 @@ +notify diff --git a/contrib/notify/Makefile b/contrib/notify/Makefile new file mode 100644 index 00000000..73771c64 --- /dev/null +++ b/contrib/notify/Makefile @@ -0,0 +1,13 @@ +GO = go +INSTALL = install + +ICONS = icons/test-pass.svg icons/test-fail.svg +ICONDIR = $(HOME)/.icons # or /usr/share/icons + +build: + $(GO) build + +install: $(ICONS) + $(GO) install + $(INSTALL) -d $(ICONDIR) + $(INSTALL) $^ $(ICONDIR) diff --git a/contrib/notify/icons/README.html b/contrib/notify/icons/README.html new file mode 100644 index 00000000..4512a24e --- /dev/null +++ b/contrib/notify/icons/README.html @@ -0,0 +1 @@ +Pass Fail Vectors by Vecteezy diff --git a/contrib/notify/icons/test-fail.svg b/contrib/notify/icons/test-fail.svg new file mode 100644 index 00000000..f6b97c74 --- /dev/null +++ b/contrib/notify/icons/test-fail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contrib/notify/icons/test-pass.svg b/contrib/notify/icons/test-pass.svg new file mode 100644 index 00000000..2e96bdaf --- /dev/null +++ b/contrib/notify/icons/test-pass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/contrib/notify/notify-macos.go b/contrib/notify/notify_darwin.go similarity index 85% rename from contrib/notify/notify-macos.go rename to contrib/notify/notify_darwin.go index 3f6822ca..ad683898 100644 --- a/contrib/notify/notify-macos.go +++ b/contrib/notify/notify_darwin.go @@ -43,9 +43,11 @@ func main() { "-group", "gotestsum", "-subtitle", subtitle, } - log.Printf("terminal-notifier %#v", args) - err := exec.Command("terminal-notifier", args...).Run() - if err != nil { + cmd := exec.Command("terminal-notifier", args...) + log.Printf("%#v", cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { log.Fatalf("Failed to exec: %v", err) } } diff --git a/contrib/notify/notify_linux.go b/contrib/notify/notify_linux.go new file mode 100644 index 00000000..8da6c3e8 --- /dev/null +++ b/contrib/notify/notify_linux.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "strconv" +) + +func main() { + total := envInt("TOTAL") + skipped := envInt("SKIPPED") + failed := envInt("FAILED") + errors := envInt("ERRORS") + + icon := "test-pass" + title := "Passed" + switch { + case errors > 0: + icon = "dialog-warning" + title = "Errored" + case failed > 0: + icon = "test-fail" + title = "Failed" + case skipped > 0: + title = "Passed with skipped" + } + + subtitle := fmt.Sprintf("%d Tests Run", total) + if errors > 0 { + subtitle += fmt.Sprintf(", %d Errored", errors) + } + if failed > 0 { + subtitle += fmt.Sprintf(", %d Failed", failed) + } + if skipped > 0 { + subtitle += fmt.Sprintf(", %d Skipped", skipped) + } + + cmd := exec.Command("notify-send", "--icon", icon, title, subtitle) + log.Printf("%#v", cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + log.Fatalf("Failed to exec: %v", err) + } +} + +func envInt(name string) int { + val := os.Getenv("TESTS_" + name) + n, err := strconv.Atoi(val) + if err != nil { + return 0 + } + return n +} diff --git a/contrib/notify/notify_windows.go b/contrib/notify/notify_windows.go new file mode 100644 index 00000000..f3d384d5 --- /dev/null +++ b/contrib/notify/notify_windows.go @@ -0,0 +1,57 @@ +package main + +import ( + "fmt" + "log" + "os" + "os/exec" + "strconv" +) + +func main() { + total := envInt("TOTAL") + skipped := envInt("SKIPPED") + failed := envInt("FAILED") + errors := envInt("ERRORS") + + icon := "info" // Info 🛈 + title := "Passed" + switch { + case errors > 0: + icon = "important" // Warning ⚠ + title = "Errored" + case failed > 0: + icon = "error" // Error ⮾ + title = "Failed" + case skipped > 0: + title = "Passed with skipped" + } + + subtitle := fmt.Sprintf("%d Tests Run", total) + if errors > 0 { + subtitle += fmt.Sprintf(", %d Errored", errors) + } + if failed > 0 { + subtitle += fmt.Sprintf(", %d Failed", failed) + } + if skipped > 0 { + subtitle += fmt.Sprintf(", %d Skipped", skipped) + } + + cmd := exec.Command("notify-send.exe", "-i", icon, title, subtitle) + log.Printf("%#v", cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + log.Fatalf("Failed to exec: %v", err) + } +} + +func envInt(name string) int { + val := os.Getenv("TESTS_" + name) + n, err := strconv.Atoi(val) + if err != nil { + return 0 + } + return n +} diff --git a/go.mod b/go.mod index 86e78cdc..5e5ef66a 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,16 @@ module gotest.tools/gotestsum require ( + github.com/bitfield/gotestdox v0.2.1 github.com/dnephin/pflag v1.0.7 - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.15.0 github.com/fsnotify/fsnotify v1.5.4 - github.com/google/go-cmp v0.5.8 + github.com/google/go-cmp v0.5.9 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/mattn/go-colorable v0.1.12 // indirect - golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 - golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 - golang.org/x/tools v0.1.11 + golang.org/x/sync v0.3.0 + golang.org/x/sys v0.10.0 + golang.org/x/term v0.10.0 + golang.org/x/tools v0.11.0 gotest.tools/v3 v3.3.0 ) diff --git a/go.sum b/go.sum index 8f8ed3ba..cbd23a8b 100644 --- a/go.sum +++ b/go.sum @@ -1,67 +1,87 @@ +github.com/bitfield/gotestdox v0.2.1 h1:Zj8IMLAO5/oiAKoMmtN96eyFiPZraJRTH2p0zDgtxc0= +github.com/bitfield/gotestdox v0.2.1/go.mod h1:D+gwtS0urjBrzguAkTM2wodsTQYFHdpx8eqRJ3N+9pY= github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY= -golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/dotwriter/writer.go b/internal/dotwriter/writer.go index b4124e23..a1749c80 100644 --- a/internal/dotwriter/writer.go +++ b/internal/dotwriter/writer.go @@ -14,6 +14,7 @@ const ESC = 27 // Writer buffers writes until Flush is called. Flush clears previously written // lines before writing new lines from the buffer. +// The main logic is platform specific, see the related files. type Writer struct { out io.Writer buf bytes.Buffer @@ -25,19 +26,6 @@ func New(out io.Writer) *Writer { return &Writer{out: out} } -// Flush the buffer, writing all buffered lines to out -func (w *Writer) Flush() error { - if w.buf.Len() == 0 { - return nil - } - defer w.hideCursor()() - w.clearLines(w.lineCount) - w.lineCount = bytes.Count(w.buf.Bytes(), []byte{'\n'}) - _, err := w.out.Write(w.buf.Bytes()) - w.buf.Reset() - return err -} - // Write saves buf to a buffer func (w *Writer) Write(buf []byte) (int, error) { return w.buf.Write(buf) diff --git a/internal/dotwriter/writer_posix.go b/internal/dotwriter/writer_posix.go index 24e65e0e..beccae9c 100644 --- a/internal/dotwriter/writer_posix.go +++ b/internal/dotwriter/writer_posix.go @@ -4,17 +4,56 @@ package dotwriter import ( + "bytes" "fmt" - "strings" ) -// clear the line and move the cursor up -var clear = fmt.Sprintf("%c[%dA%c[2K", ESC, 1, ESC) +// hide cursor var hide = fmt.Sprintf("%c[?25l", ESC) + +// show cursor var show = fmt.Sprintf("%c[?25h", ESC) -func (w *Writer) clearLines(count int) { - _, _ = fmt.Fprint(w.out, strings.Repeat(clear, count)) +// Flush the buffer, writing all buffered lines to out +func (w *Writer) Flush() error { + if w.buf.Len() == 0 { + return nil + } + // Hide cursor during write to avoid it moving around the screen + defer w.hideCursor()() + + // Move up to the top of our last output. + w.up(w.lineCount) + lines := bytes.Split(w.buf.Bytes(), []byte{'\n'}) + w.lineCount = len(lines) - 1 // Record how many lines we will write for the next Flush() + for i, line := range lines { + // For each line, write the contents and clear everything else on the line + _, err := w.out.Write(line) + if err != nil { + return err + } + w.clearRest() + // Add a newline if this isn't the last line + if i != len(lines)-1 { + _, err := w.out.Write([]byte{'\n'}) + if err != nil { + return err + } + } + } + w.buf.Reset() + return nil +} + +func (w *Writer) up(count int) { + if count == 0 { + return + } + _, _ = fmt.Fprintf(w.out, "%c[%dA", ESC, count) +} + +func (w *Writer) clearRest() { + _, _ = fmt.Fprintf(w.out, "%c[0K", ESC) } // hideCursor hides the cursor and returns a function to restore the cursor back. diff --git a/internal/dotwriter/writer_windows.go b/internal/dotwriter/writer_windows.go index a56885fb..b73a9f8d 100644 --- a/internal/dotwriter/writer_windows.go +++ b/internal/dotwriter/writer_windows.go @@ -4,6 +4,7 @@ package dotwriter import ( + "bytes" "fmt" "io" "strings" @@ -35,6 +36,19 @@ type fdWriter interface { Fd() uintptr } +// Flush implementation on windows is not ideal; we clear the entire screen before writing, which can result in flashing output +// Windows likely can adopt the same approach as posix if someone invests some effort +func (w *Writer) Flush() error { + if w.buf.Len() == 0 { + return nil + } + w.clearLines(w.lineCount) + w.lineCount = bytes.Count(w.buf.Bytes(), []byte{'\n'}) + _, err := w.out.Write(w.buf.Bytes()) + w.buf.Reset() + return err +} + func (w *Writer) clearLines(count int) { f, ok := w.out.(fdWriter) if ok && !isConsole(f.Fd()) { @@ -71,8 +85,3 @@ func isConsole(fd uintptr) bool { err := windows.GetConsoleMode(windows.Handle(fd), &mode) return err == nil } - -// This may work on Windows but I am not sure how to do it and its optional. For now, just do nothing. -func (w *Writer) hideCursor() func() { - return func() {} -} diff --git a/internal/filewatcher/term_illumos.go b/internal/filewatcher/term_illumos.go new file mode 100644 index 00000000..736d67b0 --- /dev/null +++ b/internal/filewatcher/term_illumos.go @@ -0,0 +1,6 @@ +package filewatcher + +import "golang.org/x/sys/unix" + +const tcGet = unix.TCGETS +const tcSet = unix.TCSETS diff --git a/internal/filewatcher/term_unix.go b/internal/filewatcher/term_unix.go index cf9b7d0f..b700a32b 100644 --- a/internal/filewatcher/term_unix.go +++ b/internal/filewatcher/term_unix.go @@ -26,7 +26,8 @@ func newTerminal() *terminal { } // Start the terminal is non-blocking read mode. The terminal can be reset to -// normal mode by calling Reset. +// normal mode by calling Reset. If os.Stdin is not a terminal or cannot use +// non-blocking reads then a warning is logged and the terminal is not reset. func (r *terminal) Start() { if r == nil { return @@ -34,7 +35,7 @@ func (r *terminal) Start() { fd := int(os.Stdin.Fd()) reset, err := enableNonBlockingRead(fd) if err != nil { - log.Warnf("failed to put terminal (fd %d) into raw mode: %v", fd, err) + log.Warnf("no terminal input -- keyboard shortcuts disabled: %v", err) return } r.reset = reset diff --git a/internal/filewatcher/watch.go b/internal/filewatcher/watch.go index 837ec44e..165e7090 100644 --- a/internal/filewatcher/watch.go +++ b/internal/filewatcher/watch.go @@ -213,7 +213,7 @@ func handleDirCreated(watcher *fsnotify.Watcher, event fsnotify.Event) (handled fileInfo, err := os.Stat(event.Name) if err != nil { - log.Warnf("failed to stat %s: %s", event.Name, err) + log.Debugf("failed to stat %s: %s", event.Name, err) return false } diff --git a/testjson/execution.go b/testjson/execution.go index 531aa4a2..25d4be08 100644 --- a/testjson/execution.go +++ b/testjson/execution.go @@ -63,11 +63,6 @@ func (e TestEvent) PackageEvent() bool { return e.Test == "" } -// ElapsedFormatted returns Elapsed formatted in the go test format, ex (0.00s). -func (e TestEvent) ElapsedFormatted() string { - return fmt.Sprintf("(%.2fs)", e.Elapsed) -} - // Bytes returns the serialized JSON bytes that were parsed to create the event. func (e TestEvent) Bytes() []byte { return e.raw @@ -199,7 +194,6 @@ func (p *Package) addOutput(id int, output string) { if strings.HasPrefix(output, "panic: ") { p.panicked = true } - // TODO: limit size of buffered test output p.output[id] = append(p.output[id], output) } @@ -250,9 +244,14 @@ func tcIDSet(skipped []TestCase) map[int]struct{} { return result } -// TestMainFailed returns true if the package failed, but there were no tests. -// This may occur if the package init() or TestMain exited non-zero. +// TestMainFailed returns true if the package has output related to a failure. This +// may happen if a TestMain or init function panic, or if test timeout +// is reached and output is associated with the package instead of the running +// test. func (p *Package) TestMainFailed() bool { + if p.testTimeoutPanicInTest != "" { + return true + } return p.action == ActionFail && len(p.Failed) == 0 } @@ -538,7 +537,7 @@ func (e *Execution) Failed() []TestCase { // Add package-level failure output if there were no failed tests, or // if the test timeout was reached (because we now have to store that // output on the package). - if pkg.TestMainFailed() || pkg.testTimeoutPanicInTest != "" { + if pkg.TestMainFailed() { failed = append(failed, TestCase{Package: name}) } failed = append(failed, pkg.Failed...) @@ -564,8 +563,9 @@ func FilterFailedUnique(tcs []TestCase) []TestCase { if _, exists := parents[tc.Package]; !exists { parents[tc.Package] = make(map[string]bool) } - if parent := tc.Test.Parent(); parent != "" { - parents[tc.Package][parent] = true + + for p := tc.Test.Parent(); p != ""; p = TestName(p).Parent() { + parents[tc.Package][p] = true } if _, exists := parents[tc.Package][tc.Test.Name()]; exists { continue // tc is a parent of a failing subtest diff --git a/testjson/execution_test.go b/testjson/execution_test.go index dbf88237..81f809dc 100644 --- a/testjson/execution_test.go +++ b/testjson/execution_test.go @@ -157,7 +157,7 @@ func pkgOutput(id int, line string) map[int][]string { return map[int][]string{id: {line}} } -func TestScanOutput_WithMissingEvents(t *testing.T) { +func TestScanTestOutput_WithMissingEvents(t *testing.T) { source := golden.Get(t, "go-test-json-missing-test-events.out") handler := &captureHandler{} cfg := ScanConfig{ @@ -190,7 +190,7 @@ func TestScanOutput_WithMissingEvents(t *testing.T) { assert.DeepEqual(t, expected, handler.events[start:], cmpTestEventShallow) } -func TestScanOutput_WithNonJSONLines(t *testing.T) { +func TestScanTestOutput_WithNonJSONLines(t *testing.T) { source := golden.Get(t, "go-test-json-with-nonjson-stdout.out") nonJSONLine := "|||This line is not valid test2json output.|||" @@ -218,7 +218,7 @@ func TestScanOutput_WithNonJSONLines(t *testing.T) { } } -func TestScanOutput_WithGODEBUG(t *testing.T) { +func TestScanTestOutput_WithGODEBUG(t *testing.T) { goDebugSource := `HASH[moduleIndex] HASH[moduleIndex]: "go1.20.4" HASH /usr/lib/go/src/runtime/debuglog_off.go: d6f147198 @@ -298,3 +298,20 @@ func TestFilterFailedUnique_MultipleNested(t *testing.T) { cmpTestCase := cmp.AllowUnexported(TestCase{}) assert.DeepEqual(t, expected, actual, cmpTestCase) } + +func TestFilterFailedUnique_NestedWithGaps(t *testing.T) { + input := []TestCase{ + {ID: 1, Package: "pkg", Test: "TestParent/foo/bar/baz"}, + {ID: 2, Package: "pkg", Test: "TestParent"}, + {ID: 3, Package: "pkg", Test: "TestParent1/foo/bar"}, + {ID: 4, Package: "pkg", Test: "TestParent1"}, + } + actual := FilterFailedUnique(input) + + expected := []TestCase{ + {ID: 1, Package: "pkg", Test: "TestParent/foo/bar/baz"}, + {ID: 3, Package: "pkg", Test: "TestParent1/foo/bar"}, + } + cmpTestCase := cmp.AllowUnexported(TestCase{}) + assert.DeepEqual(t, expected, actual, cmpTestCase) +} diff --git a/testjson/format.go b/testjson/format.go index 180086e2..e68b325e 100644 --- a/testjson/format.go +++ b/testjson/format.go @@ -4,8 +4,11 @@ import ( "bufio" "fmt" "io" + "os" + "sort" "strings" + "github.com/bitfield/gotestdox" "github.com/fatih/color" ) @@ -73,18 +76,74 @@ func standardJSONFormat(out io.Writer) EventFormatter { }) } +func testNameFormatTestEvent(out io.Writer, event TestEvent) { + pkgPath := RelativePackagePath(event.Package) + + fmt.Fprintf(out, "%s %s%s (%.2fs)\n", + colorEvent(event)(strings.ToUpper(string(event.Action))), + joinPkgToTestName(pkgPath, event.Test), + formatRunID(event.RunID), + event.Elapsed) +} + +func testDoxFormat(out io.Writer, opts FormatOptions) EventFormatter { + buf := bufio.NewWriter(out) + type Result struct { + Event TestEvent + Sentence string + } + + getIcon := getIconFunc(opts) + results := map[string][]Result{} + return eventFormatterFunc(func(event TestEvent, exec *Execution) error { + switch { + case event.PackageEvent(): + if !event.Action.IsTerminal() { + return nil + } + if opts.HideEmptyPackages && len(results[event.Package]) == 0 { + return nil + } + fmt.Fprintf(buf, "%s:\n", event.Package) + tests := results[event.Package] + sort.Slice(tests, func(i, j int) bool { + return tests[i].Sentence < tests[j].Sentence + }) + for _, r := range tests { + fmt.Fprintf(buf, " %s %s (%.2fs)\n", + getIcon(r.Event.Action), + r.Sentence, + r.Event.Elapsed) + } + fmt.Fprintln(buf) + return buf.Flush() + case event.Action.IsTerminal(): + // Fuzz test cases tend not to have interesting names, + // so only report these if they're failures + if isFuzzCase(event) { + return nil + } + results[event.Package] = append(results[event.Package], Result{ + Event: event, + Sentence: gotestdox.Prettify(event.Test), + }) + } + return nil + }) +} + +func isFuzzCase(event TestEvent) bool { + return strings.HasPrefix(event.Test, "Fuzz") && + event.Action == ActionPass && + TestName(event.Test).IsSubTest() +} + func testNameFormat(out io.Writer) EventFormatter { buf := bufio.NewWriter(out) // nolint:errcheck return eventFormatterFunc(func(event TestEvent, exec *Execution) error { formatTest := func() error { - pkgPath := RelativePackagePath(event.Package) - - fmt.Fprintf(buf, "%s %s%s %s\n", - colorEvent(event)(strings.ToUpper(string(event.Action))), - joinPkgToTestName(pkgPath, event.Test), - formatRunID(event.RunID), - event.ElapsedFormatted()) + testNameFormatTestEvent(buf, event) return buf.Flush() } @@ -101,6 +160,7 @@ func testNameFormat(out io.Writer) EventFormatter { result := colorEvent(event)(strings.ToUpper(string(event.Action))) pkg := exec.Package(event.Package) if event.Action == ActionSkip || (event.Action == ActionPass && pkg.Total == 0) { + event.Action = ActionSkip // always color these as skip actions result = colorEvent(event)("EMPTY") } @@ -116,7 +176,7 @@ func testNameFormat(out io.Writer) EventFormatter { pkg.WriteOutputTo(buf, tc.ID) return formatTest() - case event.Action == ActionPass: + case event.Action == ActionPass || event.Action == ActionSkip: return formatTest() } return nil @@ -182,40 +242,109 @@ func pkgNameFormat(out io.Writer, opts FormatOptions) eventFormatterFunc { } } -func shortFormatPackageEvent(opts FormatOptions, event TestEvent, exec *Execution) string { - pkg := exec.Package(event.Package) +type icons struct { + pass string + fail string + skip string + color bool +} - var iconSkipped, iconSuccess, iconFailure string - if opts.UseHiVisibilityIcons { - iconSkipped = "➖" - iconSuccess = "✅" - iconFailure = "❌" +func (i icons) forAction(action Action) string { + if i.color { + switch action { + case ActionPass: + return color.GreenString(i.pass) + case ActionSkip: + return color.YellowString(i.skip) + case ActionFail: + return color.RedString(i.fail) + default: + return " " + } } else { - iconSkipped = "∅" - iconSuccess = "✓" - iconFailure = "✖" + switch action { + case ActionPass: + return i.pass + case ActionSkip: + return i.skip + case ActionFail: + return i.fail + default: + return " " + } } +} +func getIconFunc(opts FormatOptions) func(Action) string { + switch { + case opts.UseHiVisibilityIcons || opts.Icons == "hivis": + return icons{ + pass: "✅", // WHITE HEAVY CHECK MARK + skip: "➖", // HEAVY MINUS SIGN + fail: "❌", // CROSS MARK + color: false, + }.forAction + case opts.Icons == "text": + return icons{ + pass: "PASS", + skip: "SKIP", + fail: "FAIL", + color: true, + }.forAction + case opts.Icons == "codicons": + return icons{ + pass: "\ueba4", // cod-pass + skip: "\ueabd", // cod-circle_slash + fail: "\uea87", // cod-error + color: true, + }.forAction + case opts.Icons == "octicons": + return icons{ + pass: "\uf49e", // oct-check_circle + skip: "\uf517", // oct-skip + fail: "\uf52f", // oct-x_circle + color: true, + }.forAction + case opts.Icons == "emoticons": + return icons{ + pass: "\U000f01f5", // md-emoticon_happy_outline + skip: "\U000f01f6", // md-emoticon_neutral_outline + fail: "\U000f01f8", // md-emoticon_sad_outline + color: true, + }.forAction + default: + return icons{ + pass: "✓", // CHECK MARK + skip: "∅", // EMPTY SET + fail: "✖", // HEAVY MULTIPLICATION X + color: true, + }.forAction + } +} + +func shortFormatPackageEvent(opts FormatOptions, event TestEvent, exec *Execution) string { + pkg := exec.Package(event.Package) + + getIcon := getIconFunc(opts) fmtEvent := func(action string) string { return action + " " + packageLine(event, exec.Package(event.Package)) } - withColor := colorEvent(event) switch event.Action { case ActionSkip: if opts.HideEmptyPackages { return "" } - return fmtEvent(withColor(iconSkipped)) + return fmtEvent(getIcon(event.Action)) case ActionPass: if pkg.Total == 0 { if opts.HideEmptyPackages { return "" } - return fmtEvent(withColor(iconSkipped)) + return fmtEvent(getIcon(ActionSkip)) } - return fmtEvent(withColor(iconSuccess)) + return fmtEvent(getIcon(event.Action)) case ActionFail: - return fmtEvent(withColor(iconFailure)) + return fmtEvent(getIcon(event.Action)) } return "" } @@ -286,7 +415,8 @@ func (e eventFormatterFunc) Format(event TestEvent, output *Execution) error { type FormatOptions struct { HideEmptyPackages bool - UseHiVisibilityIcons bool + UseHiVisibilityIcons bool // Deprecated + Icons string } // NewEventFormatter returns a formatter for printing events. @@ -306,13 +436,80 @@ func NewEventFormatter(out io.Writer, format string, formatOpts FormatOptions) E return dotsFormatV1(out) case "dots-v2": return newDotFormatter(out, formatOpts) + case "gotestdox", "testdox": + return testDoxFormat(out, formatOpts) case "testname", "short-verbose": + if os.Getenv("GITHUB_ACTIONS") == "true" { + return githubActionsFormat(out) + } return testNameFormat(out) case "pkgname", "short": return pkgNameFormat(out, formatOpts) case "pkgname-and-test-fails", "short-with-failures": return pkgNameWithFailuresFormat(out, formatOpts) + case "github-actions", "github-action": + return githubActionsFormat(out) default: return nil } } + +func githubActionsFormat(out io.Writer) EventFormatter { + buf := bufio.NewWriter(out) + + type name struct { + Package string + Test string + } + output := map[name][]string{} + + return eventFormatterFunc(func(event TestEvent, exec *Execution) error { + key := name{Package: event.Package, Test: event.Test} + + // test case output + if event.Test != "" && event.Action == ActionOutput { + if !isFramingLine(event.Output, event.Test) { + output[key] = append(output[key], event.Output) + } + return nil + } + + // test case end event + if event.Test != "" && event.Action.IsTerminal() { + if len(output[key]) > 0 { + buf.WriteString("::group::") + } else { + buf.WriteString(" ") + } + testNameFormatTestEvent(buf, event) + + for _, item := range output[key] { + buf.WriteString(item) + } + if len(output[key]) > 0 { + buf.WriteString("\n::endgroup::\n") + } + delete(output, key) + return buf.Flush() + } + + // package event + if !event.Action.IsTerminal() { + return nil + } + + result := colorEvent(event)(strings.ToUpper(string(event.Action))) + pkg := exec.Package(event.Package) + if event.Action == ActionSkip || (event.Action == ActionPass && pkg.Total == 0) { + event.Action = ActionSkip // always color these as skip actions + result = colorEvent(event)("EMPTY") + } + + buf.WriteString(" ") + buf.WriteString(result) + buf.WriteString(" Package ") + buf.WriteString(packageLine(event, exec.Package(event.Package))) + buf.WriteString("\n") + return buf.Flush() + }) +} diff --git a/testjson/format_test.go b/testjson/format_test.go index 552ae221..6442eddc 100644 --- a/testjson/format_test.go +++ b/testjson/format_test.go @@ -86,6 +86,13 @@ func TestFormats_DefaultGoTestJson(t *testing.T) { } testCases := []testCase{ + { + name: "testdox", + format: func(out io.Writer) EventFormatter { + return testDoxFormat(out, FormatOptions{}) + }, + expectedOut: "format/testdox.out", + }, { name: "testname", format: testNameFormat, @@ -106,10 +113,38 @@ func TestFormats_DefaultGoTestJson(t *testing.T) { { name: "pkgname with hivis", format: func(out io.Writer) EventFormatter { - return pkgNameFormat(out, FormatOptions{UseHiVisibilityIcons: true}) + return pkgNameFormat(out, FormatOptions{Icons: "hivis"}) }, expectedOut: "format/pkgname-hivis.out", }, + { + name: "pkgname with text", + format: func(out io.Writer) EventFormatter { + return pkgNameFormat(out, FormatOptions{Icons: "text"}) + }, + expectedOut: "format/pkgname-text.out", + }, + { + name: "pkgname with codicons", + format: func(out io.Writer) EventFormatter { + return pkgNameFormat(out, FormatOptions{Icons: "codicons"}) + }, + expectedOut: "format/pkgname-codicons.out", + }, + { + name: "pkgname with octicons", + format: func(out io.Writer) EventFormatter { + return pkgNameFormat(out, FormatOptions{Icons: "octicons"}) + }, + expectedOut: "format/pkgname-octicons.out", + }, + { + name: "pkgname with emoticons", + format: func(out io.Writer) EventFormatter { + return pkgNameFormat(out, FormatOptions{Icons: "emoticons"}) + }, + expectedOut: "format/pkgname-emoticons.out", + }, { name: "pkgname with hide-empty", format: func(out io.Writer) EventFormatter { @@ -132,6 +167,11 @@ func TestFormats_DefaultGoTestJson(t *testing.T) { format: standardJSONFormat, expectedOut: "input/go-test-json.out", }, + { + name: "github-actions", + format: githubActionsFormat, + expectedOut: "format/github-actions.out", + }, } for _, tc := range testCases { @@ -171,6 +211,13 @@ func TestFormats_Coverage(t *testing.T) { } testCases := []testCase{ + { + name: "testdox", + format: func(out io.Writer) EventFormatter { + return testDoxFormat(out, FormatOptions{}) + }, + expectedOut: "format/testdox-coverage.out", + }, { name: "testname", format: testNameFormat, @@ -239,6 +286,13 @@ func TestFormats_Shuffle(t *testing.T) { } testCases := []testCase{ + { + name: "testdox", + format: func(out io.Writer) EventFormatter { + return testDoxFormat(out, FormatOptions{}) + }, + expectedOut: "format/testdox-shuffle.out", + }, { name: "testname", format: testNameFormat, diff --git a/testjson/summary.go b/testjson/summary.go index 0bbbee00..a06865b4 100644 --- a/testjson/summary.go +++ b/testjson/summary.go @@ -178,7 +178,7 @@ func writeTestCaseSummary(out io.Writer, execution executionSummary, conf testCa formatRunID(tc.RunID), FormatDurationAsSeconds(tc.Elapsed, 2)) for _, line := range execution.OutputLines(tc) { - if isFramingLine(line) || conf.filter(tc.Test.Name(), line) { + if isFramingLine(line, tc.Test.Name()) { continue } fmt.Fprint(out, line) @@ -192,7 +192,6 @@ func writeTestCaseSummary(out io.Writer, execution executionSummary, conf testCa type testCaseFormatConfig struct { header string prefix string - filter func(testName string, line string) bool getter func(executionSummary) []TestCase } @@ -201,9 +200,6 @@ func formatFailed() testCaseFormatConfig { return testCaseFormatConfig{ header: withColor("Failed"), prefix: withColor("FAIL"), - filter: func(testName string, line string) bool { - return strings.HasPrefix(line, "--- FAIL: "+testName+" ") - }, getter: func(execution executionSummary) []TestCase { return execution.Failed() }, @@ -215,17 +211,17 @@ func formatSkipped() testCaseFormatConfig { return testCaseFormatConfig{ header: withColor("Skipped"), prefix: withColor("SKIP"), - filter: func(testName string, line string) bool { - return strings.HasPrefix(line, "--- SKIP: "+testName+" ") - }, getter: func(execution executionSummary) []TestCase { return execution.Skipped() }, } } -func isFramingLine(line string) bool { +func isFramingLine(line string, testName string) bool { return strings.HasPrefix(line, "=== RUN Test") || strings.HasPrefix(line, "=== PAUSE Test") || - strings.HasPrefix(line, "=== CONT Test") + strings.HasPrefix(line, "=== CONT Test") || + strings.HasPrefix(line, "--- FAIL: "+testName+" ") || + strings.HasPrefix(line, "--- SKIP: "+testName+" ") || + strings.HasPrefix(line, "--- PASS: "+testName+" ") } diff --git a/testjson/summary_test.go b/testjson/summary_test.go index e9b184cd..2c641912 100644 --- a/testjson/summary_test.go +++ b/testjson/summary_test.go @@ -7,7 +7,6 @@ import ( "testing" "time" - "gotest.tools/gotestsum/internal/text" "gotest.tools/v3/assert" "gotest.tools/v3/golden" ) @@ -320,19 +319,3 @@ func scanConfigFromGolden(filename string) func(t *testing.T) ScanConfig { return ScanConfig{Stdout: bytes.NewReader(golden.Get(t, filename))} } } - -func TestSummary_TestTimeoutPanicRace(t *testing.T) { - source := golden.Get(t, "input/go-test-json-panic-race.out") - cfg := ScanConfig{ - Stdout: bytes.NewReader(source), - Handler: &captureHandler{}, - } - exec, err := ScanTestOutput(cfg) - assert.NilError(t, err) - - out := new(bytes.Buffer) - PrintSummary(out, exec, SummarizeAll) - - actual := text.ProcessLines(t, out, text.OpRemoveSummaryLineElapsedTime) - golden.Assert(t, actual, "summary/test-timeout-panic-race") -} diff --git a/testjson/testdata/format/dots-v2.out b/testjson/testdata/format/dots-v2.out index 59f8634f..21f2afa8 100644 --- a/testjson/testdata/format/dots-v2.out +++ b/testjson/testdata/format/dots-v2.out @@ -1,1210 +1,1210 @@ -[?25l - - 1ms testjson/internal/badmain - +[?25l + + 1ms testjson/internal/badmain  + 0 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 0 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good  + 1 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good · - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good · + 1 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good · - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good · + 2 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ·· + 2 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ·· + 3 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ··· + 3 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ··· + 4 tests, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷ + 4 tests, 1 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷ + 5 tests, 1 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷ + 5 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷ + 6 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 6 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 7 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 7 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 8 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 8 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 9 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 9 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 10 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 11 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 12 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 13 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 14 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 15 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 16 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 17 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷·· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷··· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷···· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷····· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷····· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷······ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷······ + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷······· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷······· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷········ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷········ + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷········· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷·········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷·········· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷·········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷·········· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷··········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷··········· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷··········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷··········· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷··········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷··········· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷············ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷············ + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - testjson/internal/good ···↷↷············· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + testjson/internal/good ···↷↷············· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 18 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails  + 19 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails · - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails · + 19 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails · - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails · + 20 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ·· + 20 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ·· + 21 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ··· + 21 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ··· + 22 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 22 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 23 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 23 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 24 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 24 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 25 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 25 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 26 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 27 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 27 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 28 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 28 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 29 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 29 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 30 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 30 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 30 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 30 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 30 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ···· + 30 tests, 2 skipped, 1 failure, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖ + 30 tests, 2 skipped, 2 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖ + 30 tests, 2 skipped, 3 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖ + 30 tests, 2 skipped, 4 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖ + 30 tests, 2 skipped, 5 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖✖ + 30 tests, 2 skipped, 6 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖✖ + 30 tests, 2 skipped, 6 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖✖✖ + 30 tests, 2 skipped, 7 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖✖✖ + 30 tests, 2 skipped, 7 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖✖✖✖ + 30 tests, 2 skipped, 8 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖✖✖✖ + 30 tests, 2 skipped, 8 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + 30 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + 30 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails  + 31 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails · - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails · + 31 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails · - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails · + 32 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ·· + 32 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ·· + 33 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ··· + 33 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ··· + 34 tests, 2 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷ + 34 tests, 3 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷ + 35 tests, 3 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷ + 35 tests, 4 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷ + 36 tests, 4 skipped, 9 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖ + 36 tests, 4 skipped, 10 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖ + 37 tests, 4 skipped, 10 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖· + 37 tests, 4 skipped, 10 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖· + 38 tests, 4 skipped, 10 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 38 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 39 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 39 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 40 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 40 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 41 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 41 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 42 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 43 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 44 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 45 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 46 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 47 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 48 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖ + 49 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖· + 49 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖·· + 49 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖··· + 49 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖···· + 49 tests, 4 skipped, 11 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖ + 49 tests, 4 skipped, 12 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖· + 49 tests, 4 skipped, 12 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖·· + 49 tests, 4 skipped, 12 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 49 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 50 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 51 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 52 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 53 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 54 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 55 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 56 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 57 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖ + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖· + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·· + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖··· + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖···· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖···· + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖····· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖····· + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖······ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖······ + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖······· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖······· + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖········ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖········ + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖········· + 58 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖········· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖········· + 59 tests, 4 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷ + 59 tests, 5 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷ - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷ + 59 tests, 5 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷· + 59 tests, 5 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷· + 59 tests, 5 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷·· + 59 tests, 5 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷·· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷·· + 59 tests, 5 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷··· + 59 tests, 5 skipped, 13 failures, 1 error -[?25h[?25l - - 1ms testjson/internal/badmain - 🖴 testjson/internal/empty - 🖴 testjson/internal/good ···↷↷············· - 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ - 20ms testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷··· - +[?25h[?25l + + 1ms testjson/internal/badmain  + 🖴 testjson/internal/empty  + 🖴 testjson/internal/good ···↷↷············· + 20ms testjson/internal/parallelfails ····✖✖✖✖✖✖✖✖ + 20ms testjson/internal/withfails ···↷↷✖·✖····✖··✖·········↷··· + 59 tests, 5 skipped, 13 failures, 1 error -[?25h +[?25h diff --git a/testjson/testdata/format/github-actions.out b/testjson/testdata/format/github-actions.out new file mode 100644 index 00000000..0e6f3250 --- /dev/null +++ b/testjson/testdata/format/github-actions.out @@ -0,0 +1,213 @@ + FAIL Package testjson/internal/badmain (1ms) + + EMPTY Package testjson/internal/empty (cached) + + PASS testjson/internal/good.TestPassed (0.00s) +::group::PASS testjson/internal/good.TestPassedWithLog (0.00s) + good_test.go:15: this is a log + +::endgroup:: +::group::PASS testjson/internal/good.TestPassedWithStdout (0.00s) +this is a Print + +::endgroup:: +::group::SKIP testjson/internal/good.TestSkipped (0.00s) + good_test.go:23: + +::endgroup:: +::group::SKIP testjson/internal/good.TestSkippedWitLog (0.00s) + good_test.go:27: the skip message + +::endgroup:: +::group::PASS testjson/internal/good.TestWithStderr (0.00s) +this is stderr + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/a/sub (0.00s) + --- PASS: TestNestedSuccess/a/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/a (0.00s) + --- PASS: TestNestedSuccess/a (0.00s) + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/b/sub (0.00s) + --- PASS: TestNestedSuccess/b/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/b (0.00s) + --- PASS: TestNestedSuccess/b (0.00s) + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/c/sub (0.00s) + --- PASS: TestNestedSuccess/c/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/c (0.00s) + --- PASS: TestNestedSuccess/c (0.00s) + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/d/sub (0.00s) + --- PASS: TestNestedSuccess/d/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/good.TestNestedSuccess/d (0.00s) + --- PASS: TestNestedSuccess/d (0.00s) + +::endgroup:: + PASS testjson/internal/good.TestNestedSuccess (0.00s) + PASS testjson/internal/good.TestParallelTheFirst (0.01s) + PASS testjson/internal/good.TestParallelTheThird (0.00s) + PASS testjson/internal/good.TestParallelTheSecond (0.01s) + PASS Package testjson/internal/good (cached) + + PASS testjson/internal/parallelfails.TestPassed (0.00s) +::group::PASS testjson/internal/parallelfails.TestPassedWithLog (0.00s) + fails_test.go:15: this is a log + +::endgroup:: +::group::PASS testjson/internal/parallelfails.TestPassedWithStdout (0.00s) +this is a Print + +::endgroup:: +::group::PASS testjson/internal/parallelfails.TestWithStderr (0.00s) +this is stderr + +::endgroup:: +::group::FAIL testjson/internal/parallelfails.TestNestedParallelFailures/a (0.00s) + fails_test.go:50: failed sub a + --- FAIL: TestNestedParallelFailures/a (0.00s) + +::endgroup:: +::group::FAIL testjson/internal/parallelfails.TestNestedParallelFailures/d (0.00s) + fails_test.go:50: failed sub d + --- FAIL: TestNestedParallelFailures/d (0.00s) + +::endgroup:: +::group::FAIL testjson/internal/parallelfails.TestNestedParallelFailures/c (0.00s) + fails_test.go:50: failed sub c + --- FAIL: TestNestedParallelFailures/c (0.00s) + +::endgroup:: +::group::FAIL testjson/internal/parallelfails.TestNestedParallelFailures/b (0.00s) + fails_test.go:50: failed sub b + --- FAIL: TestNestedParallelFailures/b (0.00s) + +::endgroup:: + FAIL testjson/internal/parallelfails.TestNestedParallelFailures (0.00s) +::group::FAIL testjson/internal/parallelfails.TestParallelTheFirst (0.01s) + fails_test.go:29: failed the first + +::endgroup:: +::group::FAIL testjson/internal/parallelfails.TestParallelTheThird (0.00s) + fails_test.go:41: failed the third + +::endgroup:: +::group::FAIL testjson/internal/parallelfails.TestParallelTheSecond (0.01s) + fails_test.go:35: failed the second + +::endgroup:: + FAIL Package testjson/internal/parallelfails (20ms) + + PASS testjson/internal/withfails.TestPassed (0.00s) +::group::PASS testjson/internal/withfails.TestPassedWithLog (0.00s) + fails_test.go:18: this is a log + +::endgroup:: +::group::PASS testjson/internal/withfails.TestPassedWithStdout (0.00s) +this is a Print + +::endgroup:: +::group::SKIP testjson/internal/withfails.TestSkipped (0.00s) + fails_test.go:26: + +::endgroup:: +::group::SKIP testjson/internal/withfails.TestSkippedWitLog (0.00s) + fails_test.go:30: the skip message + +::endgroup:: +::group::FAIL testjson/internal/withfails.TestFailed (0.00s) + fails_test.go:34: this failed + +::endgroup:: +::group::PASS testjson/internal/withfails.TestWithStderr (0.00s) +this is stderr + +::endgroup:: +::group::FAIL testjson/internal/withfails.TestFailedWithStderr (0.00s) +this is stderr + fails_test.go:43: also failed + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedWithFailure/a/sub (0.00s) + --- PASS: TestNestedWithFailure/a/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedWithFailure/a (0.00s) + --- PASS: TestNestedWithFailure/a (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedWithFailure/b/sub (0.00s) + --- PASS: TestNestedWithFailure/b/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedWithFailure/b (0.00s) + --- PASS: TestNestedWithFailure/b (0.00s) + +::endgroup:: +::group::FAIL testjson/internal/withfails.TestNestedWithFailure/c (0.00s) + fails_test.go:65: failed + --- FAIL: TestNestedWithFailure/c (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedWithFailure/d/sub (0.00s) + --- PASS: TestNestedWithFailure/d/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedWithFailure/d (0.00s) + --- PASS: TestNestedWithFailure/d (0.00s) + +::endgroup:: + FAIL testjson/internal/withfails.TestNestedWithFailure (0.00s) +::group::PASS testjson/internal/withfails.TestNestedSuccess/a/sub (0.00s) + --- PASS: TestNestedSuccess/a/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedSuccess/a (0.00s) + --- PASS: TestNestedSuccess/a (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedSuccess/b/sub (0.00s) + --- PASS: TestNestedSuccess/b/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedSuccess/b (0.00s) + --- PASS: TestNestedSuccess/b (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedSuccess/c/sub (0.00s) + --- PASS: TestNestedSuccess/c/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedSuccess/c (0.00s) + --- PASS: TestNestedSuccess/c (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedSuccess/d/sub (0.00s) + --- PASS: TestNestedSuccess/d/sub (0.00s) + +::endgroup:: +::group::PASS testjson/internal/withfails.TestNestedSuccess/d (0.00s) + --- PASS: TestNestedSuccess/d (0.00s) + +::endgroup:: + PASS testjson/internal/withfails.TestNestedSuccess (0.00s) +::group::SKIP testjson/internal/withfails.TestTimeout (0.00s) + timeout_test.go:13: skipping slow test + +::endgroup:: + PASS testjson/internal/withfails.TestParallelTheFirst (0.01s) + PASS testjson/internal/withfails.TestParallelTheThird (0.00s) + PASS testjson/internal/withfails.TestParallelTheSecond (0.01s) + FAIL Package testjson/internal/withfails (20ms) + diff --git a/testjson/testdata/format/pkgname-codicons.out b/testjson/testdata/format/pkgname-codicons.out new file mode 100644 index 00000000..e8a3bc34 --- /dev/null +++ b/testjson/testdata/format/pkgname-codicons.out @@ -0,0 +1,5 @@ + testjson/internal/badmain (1ms) + testjson/internal/empty (cached) + testjson/internal/good (cached) + testjson/internal/parallelfails (20ms) + testjson/internal/withfails (20ms) diff --git a/testjson/testdata/format/pkgname-emoticons.out b/testjson/testdata/format/pkgname-emoticons.out new file mode 100644 index 00000000..e03a5702 --- /dev/null +++ b/testjson/testdata/format/pkgname-emoticons.out @@ -0,0 +1,5 @@ +󰇸 testjson/internal/badmain (1ms) +󰇶 testjson/internal/empty (cached) +󰇵 testjson/internal/good (cached) +󰇸 testjson/internal/parallelfails (20ms) +󰇸 testjson/internal/withfails (20ms) diff --git a/testjson/testdata/format/pkgname-octicons.out b/testjson/testdata/format/pkgname-octicons.out new file mode 100644 index 00000000..091fb700 --- /dev/null +++ b/testjson/testdata/format/pkgname-octicons.out @@ -0,0 +1,5 @@ + testjson/internal/badmain (1ms) + testjson/internal/empty (cached) + testjson/internal/good (cached) + testjson/internal/parallelfails (20ms) + testjson/internal/withfails (20ms) diff --git a/testjson/testdata/format/pkgname-text.out b/testjson/testdata/format/pkgname-text.out new file mode 100644 index 00000000..c49b2d35 --- /dev/null +++ b/testjson/testdata/format/pkgname-text.out @@ -0,0 +1,5 @@ +FAIL testjson/internal/badmain (1ms) +SKIP testjson/internal/empty (cached) +PASS testjson/internal/good (cached) +FAIL testjson/internal/parallelfails (20ms) +FAIL testjson/internal/withfails (20ms) diff --git a/testjson/testdata/format/testdox-coverage.out b/testjson/testdata/format/testdox-coverage.out new file mode 100644 index 00000000..fe2d7c31 --- /dev/null +++ b/testjson/testdata/format/testdox-coverage.out @@ -0,0 +1,52 @@ +gotest.tools/gotestsum/testjson/internal/badmain: + +gotest.tools/gotestsum/testjson/internal/good: + ✓ Nested success (0.00s) + ✓ Nested success a (0.00s) + ✓ Nested success a sub (0.00s) + ✓ Nested success b (0.00s) + ✓ Nested success b sub (0.00s) + ✓ Nested success c (0.00s) + ✓ Nested success c sub (0.00s) + ✓ Nested success d (0.00s) + ✓ Nested success d sub (0.00s) + ✓ Parallel the first (0.01s) + ✓ Parallel the second (0.01s) + ✓ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ∅ Skipped (0.00s) + ∅ Skipped wit log (0.00s) + ✓ With stderr (0.00s) + +gotest.tools/gotestsum/testjson/internal/stub: + ✖ Failed (0.00s) + ✖ Failed with stderr (0.00s) + ✓ Nested success (0.00s) + ✓ Nested success a (0.00s) + ✓ Nested success a sub (0.00s) + ✓ Nested success b (0.00s) + ✓ Nested success b sub (0.00s) + ✓ Nested success c (0.00s) + ✓ Nested success c sub (0.00s) + ✓ Nested success d (0.00s) + ✓ Nested success d sub (0.00s) + ✖ Nested with failure (0.00s) + ✓ Nested with failure a (0.00s) + ✓ Nested with failure a sub (0.00s) + ✓ Nested with failure b (0.00s) + ✓ Nested with failure b sub (0.00s) + ✖ Nested with failure c (0.00s) + ✓ Nested with failure d (0.00s) + ✓ Nested with failure d sub (0.00s) + ✓ Parallel the first (0.01s) + ✓ Parallel the second (0.01s) + ✓ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ∅ Skipped (0.00s) + ∅ Skipped wit log (0.00s) + ✓ With stderr (0.00s) + diff --git a/testjson/testdata/format/testdox-shuffle.out b/testjson/testdata/format/testdox-shuffle.out new file mode 100644 index 00000000..825669b2 --- /dev/null +++ b/testjson/testdata/format/testdox-shuffle.out @@ -0,0 +1,67 @@ +gotest.tools/gotestsum/testjson/internal/badmain: + +gotest.tools/gotestsum/testjson/internal/good: + ✓ Nested success (0.00s) + ✓ Nested success a (0.00s) + ✓ Nested success a sub (0.00s) + ✓ Nested success b (0.00s) + ✓ Nested success b sub (0.00s) + ✓ Nested success c (0.00s) + ✓ Nested success c sub (0.00s) + ✓ Nested success d (0.00s) + ✓ Nested success d sub (0.00s) + ✓ Parallel the first (0.01s) + ✓ Parallel the second (0.01s) + ✓ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ∅ Skipped (0.00s) + ∅ Skipped wit log (0.00s) + ✓ With stderr (0.00s) + +gotest.tools/gotestsum/testjson/internal/parallelfails: + ✖ Nested parallel failures (0.00s) + ✖ Nested parallel failures a (0.00s) + ✖ Nested parallel failures b (0.00s) + ✖ Nested parallel failures c (0.00s) + ✖ Nested parallel failures d (0.00s) + ✖ Parallel the first (0.01s) + ✖ Parallel the second (0.01s) + ✖ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ✓ With stderr (0.00s) + +gotest.tools/gotestsum/testjson/internal/withfails: + ✖ Failed (0.00s) + ✖ Failed with stderr (0.00s) + ✓ Nested success (0.00s) + ✓ Nested success a (0.00s) + ✓ Nested success a sub (0.00s) + ✓ Nested success b (0.00s) + ✓ Nested success b sub (0.00s) + ✓ Nested success c (0.00s) + ✓ Nested success c sub (0.00s) + ✓ Nested success d (0.00s) + ✓ Nested success d sub (0.00s) + ✖ Nested with failure (0.00s) + ✓ Nested with failure a (0.00s) + ✓ Nested with failure a sub (0.00s) + ✓ Nested with failure b (0.00s) + ✓ Nested with failure b sub (0.00s) + ✖ Nested with failure c (0.00s) + ✓ Nested with failure d (0.00s) + ✓ Nested with failure d sub (0.00s) + ✓ Parallel the first (0.01s) + ✓ Parallel the second (0.01s) + ✓ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ∅ Skipped (0.00s) + ∅ Skipped wit log (0.00s) + ∅ Timeout (0.00s) + ✓ With stderr (0.00s) + diff --git a/testjson/testdata/format/testdox.out b/testjson/testdata/format/testdox.out new file mode 100644 index 00000000..028e8262 --- /dev/null +++ b/testjson/testdata/format/testdox.out @@ -0,0 +1,69 @@ +gotest.tools/gotestsum/testjson/internal/badmain: + +gotest.tools/gotestsum/testjson/internal/empty: + +gotest.tools/gotestsum/testjson/internal/good: + ✓ Nested success (0.00s) + ✓ Nested success a (0.00s) + ✓ Nested success a sub (0.00s) + ✓ Nested success b (0.00s) + ✓ Nested success b sub (0.00s) + ✓ Nested success c (0.00s) + ✓ Nested success c sub (0.00s) + ✓ Nested success d (0.00s) + ✓ Nested success d sub (0.00s) + ✓ Parallel the first (0.01s) + ✓ Parallel the second (0.01s) + ✓ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ∅ Skipped (0.00s) + ∅ Skipped wit log (0.00s) + ✓ With stderr (0.00s) + +gotest.tools/gotestsum/testjson/internal/parallelfails: + ✖ Nested parallel failures (0.00s) + ✖ Nested parallel failures a (0.00s) + ✖ Nested parallel failures b (0.00s) + ✖ Nested parallel failures c (0.00s) + ✖ Nested parallel failures d (0.00s) + ✖ Parallel the first (0.01s) + ✖ Parallel the second (0.01s) + ✖ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ✓ With stderr (0.00s) + +gotest.tools/gotestsum/testjson/internal/withfails: + ✖ Failed (0.00s) + ✖ Failed with stderr (0.00s) + ✓ Nested success (0.00s) + ✓ Nested success a (0.00s) + ✓ Nested success a sub (0.00s) + ✓ Nested success b (0.00s) + ✓ Nested success b sub (0.00s) + ✓ Nested success c (0.00s) + ✓ Nested success c sub (0.00s) + ✓ Nested success d (0.00s) + ✓ Nested success d sub (0.00s) + ✖ Nested with failure (0.00s) + ✓ Nested with failure a (0.00s) + ✓ Nested with failure a sub (0.00s) + ✓ Nested with failure b (0.00s) + ✓ Nested with failure b sub (0.00s) + ✖ Nested with failure c (0.00s) + ✓ Nested with failure d (0.00s) + ✓ Nested with failure d sub (0.00s) + ✓ Parallel the first (0.01s) + ✓ Parallel the second (0.01s) + ✓ Parallel the third (0.00s) + ✓ Passed (0.00s) + ✓ Passed with log (0.00s) + ✓ Passed with stdout (0.00s) + ∅ Skipped (0.00s) + ∅ Skipped wit log (0.00s) + ∅ Timeout (0.00s) + ✓ With stderr (0.00s) + diff --git a/testjson/testdata/format/testname-coverage.out b/testjson/testdata/format/testname-coverage.out index 4364ae4d..0cac2b4a 100644 --- a/testjson/testdata/format/testname-coverage.out +++ b/testjson/testdata/format/testname-coverage.out @@ -3,6 +3,8 @@ FAIL gotestsum/testjson/internal/badmain PASS gotestsum/testjson/internal/good.TestPassed (0.00s) PASS gotestsum/testjson/internal/good.TestPassedWithLog (0.00s) PASS gotestsum/testjson/internal/good.TestPassedWithStdout (0.00s) +SKIP gotestsum/testjson/internal/good.TestSkipped (0.00s) +SKIP gotestsum/testjson/internal/good.TestSkippedWitLog (0.00s) PASS gotestsum/testjson/internal/good.TestWithStderr (0.00s) PASS gotestsum/testjson/internal/good.TestNestedSuccess/a/sub (0.00s) PASS gotestsum/testjson/internal/good.TestNestedSuccess/a (0.00s) @@ -21,6 +23,8 @@ PASS gotestsum/testjson/internal/good (coverage: 0.0% of statements) PASS gotestsum/testjson/internal/stub.TestPassed (0.00s) PASS gotestsum/testjson/internal/stub.TestPassedWithLog (0.00s) PASS gotestsum/testjson/internal/stub.TestPassedWithStdout (0.00s) +SKIP gotestsum/testjson/internal/stub.TestSkipped (0.00s) +SKIP gotestsum/testjson/internal/stub.TestSkippedWitLog (0.00s) === RUN TestFailed --- FAIL: TestFailed (0.00s) stub_test.go:34: this failed diff --git a/testjson/testdata/format/testname-shuffle.out b/testjson/testdata/format/testname-shuffle.out index 58a02335..8d80b36d 100644 --- a/testjson/testdata/format/testname-shuffle.out +++ b/testjson/testdata/format/testname-shuffle.out @@ -1,6 +1,7 @@ sometimes main can exit 2 FAIL testjson/internal/badmain PASS testjson/internal/good.TestPassedWithLog (0.00s) +SKIP testjson/internal/good.TestSkippedWitLog (0.00s) PASS testjson/internal/good.TestPassedWithStdout (0.00s) PASS testjson/internal/good.TestPassed (0.00s) PASS testjson/internal/good.TestNestedSuccess/a/sub (0.00s) @@ -13,6 +14,7 @@ PASS testjson/internal/good.TestNestedSuccess/d/sub (0.00s) PASS testjson/internal/good.TestNestedSuccess/d (0.00s) PASS testjson/internal/good.TestNestedSuccess (0.00s) PASS testjson/internal/good.TestWithStderr (0.00s) +SKIP testjson/internal/good.TestSkipped (0.00s) PASS testjson/internal/good.TestParallelTheSecond (0.01s) PASS testjson/internal/good.TestParallelTheFirst (0.01s) PASS testjson/internal/good.TestParallelTheThird (0.00s) @@ -68,6 +70,7 @@ FAIL testjson/internal/parallelfails.TestParallelTheFirst (0.01s) FAIL testjson/internal/parallelfails.TestParallelTheThird (0.00s) FAIL testjson/internal/parallelfails (-test.shuffle 123456) PASS testjson/internal/withfails.TestPassedWithStdout (0.00s) +SKIP testjson/internal/withfails.TestSkipped (0.00s) PASS testjson/internal/withfails.TestNestedWithFailure/a/sub (0.00s) PASS testjson/internal/withfails.TestNestedWithFailure/a (0.00s) PASS testjson/internal/withfails.TestNestedWithFailure/b/sub (0.00s) @@ -83,6 +86,7 @@ PASS testjson/internal/withfails.TestNestedWithFailure/d (0.00s) FAIL testjson/internal/withfails.TestNestedWithFailure (0.00s) PASS testjson/internal/withfails.TestWithStderr (0.00s) PASS testjson/internal/withfails.TestPassed (0.00s) +SKIP testjson/internal/withfails.TestSkippedWitLog (0.00s) PASS testjson/internal/withfails.TestNestedSuccess/a/sub (0.00s) PASS testjson/internal/withfails.TestNestedSuccess/a (0.00s) PASS testjson/internal/withfails.TestNestedSuccess/b/sub (0.00s) @@ -93,6 +97,7 @@ PASS testjson/internal/withfails.TestNestedSuccess/d/sub (0.00s) PASS testjson/internal/withfails.TestNestedSuccess/d (0.00s) PASS testjson/internal/withfails.TestNestedSuccess (0.00s) PASS testjson/internal/withfails.TestPassedWithLog (0.00s) +SKIP testjson/internal/withfails.TestTimeout (0.00s) === RUN TestFailedWithStderr this is stderr fails_test.go:43: also failed diff --git a/testjson/testdata/format/testname.out b/testjson/testdata/format/testname.out index 5eaedcad..e39dcd42 100644 --- a/testjson/testdata/format/testname.out +++ b/testjson/testdata/format/testname.out @@ -4,6 +4,8 @@ EMPTY testjson/internal/empty (cached) PASS testjson/internal/good.TestPassed (0.00s) PASS testjson/internal/good.TestPassedWithLog (0.00s) PASS testjson/internal/good.TestPassedWithStdout (0.00s) +SKIP testjson/internal/good.TestSkipped (0.00s) +SKIP testjson/internal/good.TestSkippedWitLog (0.00s) PASS testjson/internal/good.TestWithStderr (0.00s) PASS testjson/internal/good.TestNestedSuccess/a/sub (0.00s) PASS testjson/internal/good.TestNestedSuccess/a (0.00s) @@ -71,6 +73,8 @@ FAIL testjson/internal/parallelfails PASS testjson/internal/withfails.TestPassed (0.00s) PASS testjson/internal/withfails.TestPassedWithLog (0.00s) PASS testjson/internal/withfails.TestPassedWithStdout (0.00s) +SKIP testjson/internal/withfails.TestSkipped (0.00s) +SKIP testjson/internal/withfails.TestSkippedWitLog (0.00s) === RUN TestFailed fails_test.go:34: this failed --- FAIL: TestFailed (0.00s) @@ -103,6 +107,7 @@ PASS testjson/internal/withfails.TestNestedSuccess/c (0.00s) PASS testjson/internal/withfails.TestNestedSuccess/d/sub (0.00s) PASS testjson/internal/withfails.TestNestedSuccess/d (0.00s) PASS testjson/internal/withfails.TestNestedSuccess (0.00s) +SKIP testjson/internal/withfails.TestTimeout (0.00s) PASS testjson/internal/withfails.TestParallelTheFirst (0.01s) PASS testjson/internal/withfails.TestParallelTheThird (0.00s) PASS testjson/internal/withfails.TestParallelTheSecond (0.01s)