From 1b2039eca670aa4332ab57566b2c53731f71dcfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Stemmer?= Date: Wed, 9 Oct 2019 00:55:55 +0100 Subject: [PATCH] parser/gotest: Create go test -json parser --- pkg/parser/gotest/json.go | 77 ++++++++++++++++++++++++++++++++++ pkg/parser/gotest/json_test.go | 63 ++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 pkg/parser/gotest/json.go create mode 100644 pkg/parser/gotest/json_test.go diff --git a/pkg/parser/gotest/json.go b/pkg/parser/gotest/json.go new file mode 100644 index 0000000..af166a3 --- /dev/null +++ b/pkg/parser/gotest/json.go @@ -0,0 +1,77 @@ +package gotest + +import ( + "bufio" + "encoding/json" + "io" + "time" + + "github.com/jstemmer/go-junit-report/v2/pkg/gtr" +) + +// New returns a new Go test json output parser. +func NewJSON(options ...Option) *JSONParser { + return &JSONParser{gp: New(options...)} +} + +// Parser is a Go test json output Parser. +type JSONParser struct { + gp *Parser +} + +// Parse parses Go test json output from the given io.Reader r and returns +// gtr.Report. +func (p *JSONParser) Parse(r io.Reader) (gtr.Report, error) { + return p.gp.Parse(newJSONReader(r)) +} + +// Events returns the events created by the parser. +func (p *JSONParser) Events() []Event { + return p.gp.Events() +} + +type jsonEvent struct { + Time time.Time + Action string + Package string + Test string + Elapsed float64 // seconds + Output string +} + +type jsonReader struct { + r *bufio.Reader + buf []byte +} + +func newJSONReader(reader io.Reader) *jsonReader { + return &jsonReader{r: bufio.NewReader(reader)} +} + +func (j *jsonReader) Read(p []byte) (int, error) { + var err error + for len(j.buf) == 0 { + j.buf, err = j.readNextLine() + if err != nil { + return 0, err + } + } + n := copy(p, j.buf) + j.buf = j.buf[n:] + return n, nil +} + +func (j jsonReader) readNextLine() ([]byte, error) { + line, err := j.r.ReadBytes('\n') + if err != nil { + return nil, err + } + if len(line) == 0 || line[0] != '{' { + return line, nil + } + var event jsonEvent + if err := json.Unmarshal(line, &event); err != nil { + return nil, err + } + return []byte(event.Output), nil +} diff --git a/pkg/parser/gotest/json_test.go b/pkg/parser/gotest/json_test.go new file mode 100644 index 0000000..1be9068 --- /dev/null +++ b/pkg/parser/gotest/json_test.go @@ -0,0 +1,63 @@ +package gotest + +import ( + "io" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" +) + +var input = `some other output +{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK"} +{"Time":"2019-10-09T00:00:00.708139047+00:00","Action":"output","Package":"package/name/ok","Test":"TestOK","Output":"=== RUN TestOK\n"} +` + +func TestJSONReaderReadAll(t *testing.T) { + r := newJSONReader(strings.NewReader(input)) + got, err := io.ReadAll(r) + if err != nil { + t.Fatal(err) + } + + want := `some other output +=== RUN TestOK +` + + if diff := cmp.Diff(string(got), want); diff != "" { + t.Errorf("unexpected result from jsonReader, diff (-got, +want):\n%s\n", diff) + } +} + +func TestJSONReaderReadSmallBuffer(t *testing.T) { + expected := [][]byte{ + []byte("some"), + []byte(" oth"), + []byte("er o"), + []byte("utpu"), + []byte("t\n"), + []byte("=== "), + []byte("RUN "), + []byte(" Te"), + []byte("stOK"), + []byte("\n"), + } + + r := newJSONReader(strings.NewReader(input)) + buf := make([]byte, 4) + for _, want := range expected { + n, err := r.Read(buf) + if err != nil { + t.Fatalf("Read error: %v", err) + } + + if diff := cmp.Diff(string(buf[:n]), string(want)); diff != "" { + t.Fatalf("unexpected result from jsonReader, diff (-got, +want):\n%s\n", diff) + } + } + + _, err := r.Read(buf) + if err != io.EOF { + t.Fatalf("unexpected result from jsonReader: got %v, want %v", err, io.EOF) + } +}