Repository: gotestyourself/gotestsum
Pull request #234 (2022-02-22 20:21:43)

Pass stdin to go test
It may be useful to pipe the `go test` JSON to `gotestsum`. There are a few ways in which this could be achieved:

1. Passing stdin to `testjson.ScanConfig` seems the most sensible, but it may be complicated and may cause unintended side effects. For instance, assuming `gotestsum` were to contextually switch between using stdin and `go test`, existing invocations of `gotestsum` where data is being piped would no longer work. Providing a new flag to opt-in may be helpful? Maybe a sub-command?

2. (This PR) Passing stdin to `--raw-command` allows stdin to be piped to stdout via use of a tool like `cat`.

---

Given the changes included in this PR, `gotestsum` can read `go test` JSON via stdin with:

```sh
cat out.json | gotestsum --raw-command -- cat
```

This may be useful when the JSON is generated via other tools (i.e Bazel). For example:

```sh
bazel test //... |& go tool test2json | gotestsum --raw-command -- cat
# or
bazel test //... |& gotestsum --raw-command -- go tool test2json
```

What do you think?


Patch:
diff --git a/README.md b/README.md
index 5a22bc2..e01f46e 100644
--- a/README.md
+++ b/README.md
@@ -232,6 +232,11 @@ stdout and stderr output:
   stderr, not the `test2json` stdout). Any stderr produced by tests is not
   considered an error (it will be in the `test2json` stdout).
 
+**Example: accept intput from stdin**
+```
+cat out.json | gotestsum --raw-command -- cat
+```
+
 **Example: run tests with profiling enabled**
 
 Using a `profile.sh` script like this:
diff --git a/cmd/main.go b/cmd/main.go
index ffa08f8..3bb0335 100644
--- a/cmd/main.go
+++ b/cmd/main.go
@@ -356,6 +356,7 @@ func startGoTest(ctx context.Context, args []string) (*proc, error) {
 	}
 
 	cmd := exec.CommandContext(ctx, args[0], args[1:]...)
+	cmd.Stdin = os.Stdin
 	p := proc{cmd: cmd}
 	log.Debugf("exec: %s", cmd.Args)
 	var err error


Test patch:
diff --git a/cmd/main_test.go b/cmd/main_test.go
index cd5deb3..ae06dc3 100644
--- a/cmd/main_test.go
+++ b/cmd/main_test.go
@@ -2,12 +2,15 @@ package cmd
 
 import (
 	"bytes"
+	"encoding/json"
 	"os"
 	"os/exec"
 	"strings"
 	"testing"
 
+	"gotest.tools/gotestsum/testjson"
 	"gotest.tools/v3/assert"
+	"gotest.tools/v3/assert/cmp"
 	"gotest.tools/v3/env"
 	"gotest.tools/v3/golden"
 )
@@ -399,3 +402,41 @@ func TestRun_RerunFails_PanicPreventsRerun(t *testing.T) {
 	err := run(opts)
 	assert.ErrorContains(t, err, "rerun aborted because previous run had a suspected panic", out.String())
 }
+
+func TestRun_InputFromStdin(t *testing.T) {
+	stdin := os.Stdin
+	t.Cleanup(func() { os.Stdin = stdin })
+
+	r, w, err := os.Pipe()
+	assert.NilError(t, err)
+	t.Cleanup(func() { _ = r.Close() })
+
+	os.Stdin = r
+
+	go func() {
+		defer func() { _ = w.Close() }()
+
+		e := json.NewEncoder(w)
+		for _, event := range []testjson.TestEvent{
+			{Action: "run", Package: "pkg"},
+			{Action: "run", Package: "pkg", Test: "TestOne"},
+			{Action: "fail", Package: "pkg", Test: "TestOne"},
+			{Action: "fail", Package: "pkg"},
+		} {
+			assert.Check(t, e.Encode(event))
+		}
+	}()
+
+	stdout := new(bytes.Buffer)
+	err = run(&options{
+		args:        []string{"cat"},
+		format:      "testname",
+		hideSummary: newHideSummaryValue(),
+		rawCommand:  true,
+
+		stdout: stdout,
+		stderr: os.Stderr,
+	})
+	assert.NilError(t, err)
+	assert.Assert(t, cmp.Contains(stdout.String(), "DONE 1"))
+}