package gotest

import (
	"flag"
	"os"
	"path/filepath"
	"regexp"
	"testing"
	"time"

	"github.com/jstemmer/go-junit-report/v2/pkg/gtr"

	"github.com/google/go-cmp/cmp"
)

const testdataRoot = "../../../testdata/"

var matchTest = flag.String("match", "", "only test testdata matching this pattern")

var tests = []struct {
	in       string
	expected []gtr.Event
}{
	{"01-pass",
		[]gtr.Event{
			{Type: "run_test", Name: "TestZ"},
			{Type: "end_test", Name: "TestZ", Result: "PASS", Duration: 60 * time.Millisecond},
			{Type: "run_test", Name: "TestA"},
			{Type: "end_test", Name: "TestA", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name", Duration: 160 * time.Millisecond},
		}},
	{"02-fail",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "FAIL", Duration: 20 * time.Millisecond},
			{Type: "output", Data: "\tfile_test.go:11: Error message"},
			{Type: "output", Data: "\tfile_test.go:11: Longer"},
			{Type: "output", Data: "\t\terror"},
			{Type: "output", Data: "\t\tmessage."},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 130 * time.Millisecond},
			{Type: "status", Result: "FAIL"},
			{Type: "output", Data: "exit status 1"},
			{Type: "summary", Result: "FAIL", Name: "package/name", Duration: 151 * time.Millisecond},
		}},
	{"03-skip",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "SKIP", Duration: 20 * time.Millisecond},
			{Type: "output", Data: "\tfile_test.go:11: Skip message"},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 130 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name", Duration: 150 * time.Millisecond},
		}},
	{"04-go_1_4",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 60 * time.Millisecond},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name", Duration: 160 * time.Millisecond},
		}},
	// Test 05 is skipped, because it was actually testing XML output
	{"06-mixed",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 60 * time.Millisecond},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name1", Duration: 160 * time.Millisecond},
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "FAIL", Duration: 20 * time.Millisecond},
			{Type: "output", Data: "\tfile_test.go:11: Error message"},
			{Type: "output", Data: "\tfile_test.go:11: Longer"},
			{Type: "output", Data: "\t\terror"},
			{Type: "output", Data: "\t\tmessage."},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 130 * time.Millisecond},
			{Type: "status", Result: "FAIL"},
			{Type: "output", Data: "exit status 1"},
			{Type: "summary", Result: "FAIL", Name: "package/name2", Duration: 151 * time.Millisecond},
		}},
	{"07-compiled_test",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 60 * time.Millisecond},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
		}},
	{"08-parallel",
		[]gtr.Event{
			{Type: "run_test", Name: "TestDoFoo"},
			{Type: "run_test", Name: "TestDoFoo2"},
			{Type: "end_test", Name: "TestDoFoo", Result: "PASS", Duration: 270 * time.Millisecond},
			{Type: "output", Data: "\tcov_test.go:10: DoFoo log 1"},
			{Type: "output", Data: "\tcov_test.go:10: DoFoo log 2"},
			{Type: "end_test", Name: "TestDoFoo2", Result: "PASS", Duration: 160 * time.Millisecond},
			{Type: "output", Data: "\tcov_test.go:21: DoFoo2 log 1"},
			{Type: "output", Data: "\tcov_test.go:21: DoFoo2 log 2"},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name", Duration: 440 * time.Millisecond},
		}},
	{"09-coverage",
		[]gtr.Event{
			{Type: "run_test", Name: "TestZ"},
			{Type: "end_test", Name: "TestZ", Result: "PASS", Duration: 60 * time.Millisecond},
			{Type: "run_test", Name: "TestA"},
			{Type: "end_test", Name: "TestA", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "coverage", CovPct: 13.37},
			{Type: "summary", Result: "ok", Name: "package/name", Duration: 160 * time.Millisecond},
		}},
	{"10-multipkg-coverage",
		[]gtr.Event{
			{Type: "run_test", Name: "TestA"},
			{Type: "end_test", Name: "TestA", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "run_test", Name: "TestB"},
			{Type: "end_test", Name: "TestB", Result: "PASS", Duration: 300 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "coverage", CovPct: 10},
			{Type: "summary", Result: "ok", Name: "package1/foo", Duration: 400 * time.Millisecond, CovPct: 10},
			{Type: "run_test", Name: "TestC"},
			{Type: "end_test", Name: "TestC", Result: "PASS", Duration: 4200 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "coverage", CovPct: 99.8},
			{Type: "summary", Result: "ok", Name: "package2/bar", Duration: 4200 * time.Millisecond, CovPct: 99.8},
		}},
	{"11-go_1_5",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 20 * time.Millisecond},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 30 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name", Duration: 50 * time.Millisecond},
		}},
	{"12-go_1_7",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "run_test", Name: "TestOne/Child"},
			{Type: "run_test", Name: "TestOne/Child#01"},
			{Type: "run_test", Name: "TestOne/Child=02"},
			{Type: "end_test", Name: "TestOne", Result: "PASS", Duration: 10 * time.Millisecond},
			{Type: "end_test", Name: "TestOne/Child", Result: "PASS", Indent: 1, Duration: 20 * time.Millisecond},
			{Type: "end_test", Name: "TestOne/Child#01", Result: "PASS", Indent: 1, Duration: 30 * time.Millisecond},
			{Type: "end_test", Name: "TestOne/Child=02", Result: "PASS", Indent: 1, Duration: 40 * time.Millisecond},
			{Type: "run_test", Name: "TestTwo"},
			{Type: "run_test", Name: "TestTwo/Child"},
			{Type: "run_test", Name: "TestTwo/Child#01"},
			{Type: "run_test", Name: "TestTwo/Child=02"},
			{Type: "end_test", Name: "TestTwo", Result: "PASS", Duration: 10 * time.Millisecond},
			{Type: "end_test", Name: "TestTwo/Child", Result: "PASS", Indent: 1, Duration: 20 * time.Millisecond},
			{Type: "end_test", Name: "TestTwo/Child#01", Result: "PASS", Indent: 1, Duration: 30 * time.Millisecond},
			{Type: "end_test", Name: "TestTwo/Child=02", Result: "PASS", Indent: 1, Duration: 40 * time.Millisecond},
			{Type: "run_test", Name: "TestThree"},
			{Type: "run_test", Name: "TestThree/a#1"},
			{Type: "run_test", Name: "TestThree/a#1/b#1"},
			{Type: "run_test", Name: "TestThree/a#1/b#1/c#1"},
			{Type: "end_test", Name: "TestThree", Result: "PASS", Duration: 10 * time.Millisecond},
			{Type: "end_test", Name: "TestThree/a#1", Result: "PASS", Indent: 1, Duration: 20 * time.Millisecond},
			{Type: "end_test", Name: "TestThree/a#1/b#1", Result: "PASS", Indent: 2, Duration: 30 * time.Millisecond},
			{Type: "end_test", Name: "TestThree/a#1/b#1/c#1", Result: "PASS", Indent: 3, Duration: 40 * time.Millisecond},
			{Type: "run_test", Name: "TestFour"},
			{Type: "run_test", Name: "TestFour/#00"},
			{Type: "run_test", Name: "TestFour/#01"},
			{Type: "run_test", Name: "TestFour/#02"},
			{Type: "end_test", Name: "TestFour", Result: "FAIL", Duration: 20 * time.Millisecond},
			{Type: "end_test", Name: "TestFour/#00", Result: "FAIL", Indent: 1, Duration: 0},
			{Type: "output", Data: "    \texample.go:12: Expected abc  OBTAINED:"},
			{Type: "output", Data: "    \t\txyz"},
			{Type: "output", Data: "    \texample.go:123: Expected and obtained are different."},
			{Type: "end_test", Name: "TestFour/#01", Result: "SKIP", Indent: 1, Duration: 0},
			{Type: "output", Data: "    \texample.go:1234: Not supported yet."},
			{Type: "end_test", Name: "TestFour/#02", Result: "PASS", Indent: 1, Duration: 0},
			{Type: "run_test", Name: "TestFive"},
			{Type: "end_test", Name: "TestFive", Result: "SKIP", Duration: 0},
			{Type: "output", Data: "\texample.go:1392: Not supported yet."},
			{Type: "run_test", Name: "TestSix"},
			{Type: "end_test", Name: "TestSix", Result: "FAIL", Duration: 0},
			{Type: "output", Data: "\texample.go:371: This should not fail!"},
			{Type: "status", Result: "FAIL"},
			{Type: "summary", Result: "FAIL", Name: "package/name", Duration: 50 * time.Millisecond},
		}},
	{"13-syntax-error",
		[]gtr.Event{
			{Type: "output", Data: "# package/name/failing1"},
			{Type: "output", Data: "failing1/failing_test.go:15: undefined: x"},
			{Type: "output", Data: "# package/name/failing2"},
			{Type: "output", Data: "failing2/another_failing_test.go:20: undefined: y"},
			{Type: "output", Data: "# package/name/setupfailing1"},
			{Type: "output", Data: "setupfailing1/failing_test.go:4: cannot find package \"other/package\" in any of:"},
			{Type: "output", Data: "	/path/vendor (vendor tree)"},
			{Type: "output", Data: "	/path/go/root (from $GOROOT)"},
			{Type: "output", Data: "	/path/go/path (from $GOPATH)"},
			{Type: "run_test", Name: "TestA"},
			{Type: "end_test", Name: "TestA", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name/passing1", Duration: 100 * time.Millisecond},
			{Type: "run_test", Name: "TestB"},
			{Type: "end_test", Name: "TestB", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name/passing2", Duration: 100 * time.Millisecond},
			{Type: "summary", Result: "FAIL", Name: "package/name/failing1", Data: "[build failed]"},
			{Type: "summary", Result: "FAIL", Name: "package/name/failing2", Data: "[build failed]"},
			{Type: "summary", Result: "FAIL", Name: "package/name/setupfailing1", Data: "[setup failed]"},
		}},
	{"14-panic",
		[]gtr.Event{
			{Type: "output", Data: "panic: init"},
			{Type: "output", Data: "stacktrace"},
			{Type: "summary", Result: "FAIL", Name: "package/panic", Duration: 3 * time.Millisecond},
			{Type: "output", Data: "panic: init"},
			{Type: "output", Data: "stacktrace"},
			{Type: "summary", Result: "FAIL", Name: "package/panic2", Duration: 3 * time.Millisecond},
		}},
	{"15-empty",
		[]gtr.Event{
			{Type: "output", Data: "testing: warning: no tests to run"},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/empty", Duration: 1 * time.Millisecond},
		}},
	{"16-repeated-names",
		[]gtr.Event{
			{Type: "run_test", Name: "TestRepeat"},
			{Type: "end_test", Name: "TestRepeat", Result: "PASS"},
			{Type: "run_test", Name: "TestRepeat"},
			{Type: "end_test", Name: "TestRepeat", Result: "PASS"},
			{Type: "run_test", Name: "TestRepeat"},
			{Type: "end_test", Name: "TestRepeat", Result: "PASS"},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/repeated-names", Duration: 1 * time.Millisecond},
		}},
	{"17-race",
		[]gtr.Event{
			{Type: "run_test", Name: "TestRace"},
			{Type: "output", Data: "test output"},
			{Type: "output", Data: "2 0xc4200153d0"},
			{Type: "output", Data: "=================="},
			{Type: "output", Data: "WARNING: DATA RACE"},
			{Type: "output", Data: "Write at 0x00c4200153d0 by goroutine 7:"},
			{Type: "output", Data: "  race_test.TestRace.func1()"},
			{Type: "output", Data: "      race_test.go:13 +0x3b"},
			{Type: "output", Data: ""},
			{Type: "output", Data: "Previous write at 0x00c4200153d0 by goroutine 6:"},
			{Type: "output", Data: "  race_test.TestRace()"},
			{Type: "output", Data: "      race_test.go:15 +0x136"},
			{Type: "output", Data: "  testing.tRunner()"},
			{Type: "output", Data: "      /usr/local/Cellar/go/1.8.3/libexec/src/testing/testing.go:657 +0x107"},
			{Type: "output", Data: ""},
			{Type: "output", Data: "Goroutine 7 (running) created at:"},
			{Type: "output", Data: "  race_test.TestRace()"},
			{Type: "output", Data: "      race_test.go:14 +0x125"},
			{Type: "output", Data: "  testing.tRunner()"},
			{Type: "output", Data: "      /usr/local/Cellar/go/1.8.3/libexec/src/testing/testing.go:657 +0x107"},
			{Type: "output", Data: ""},
			{Type: "output", Data: "Goroutine 6 (running) created at:"},
			{Type: "output", Data: "  testing.(*T).Run()"},
			{Type: "output", Data: "      /usr/local/Cellar/go/1.8.3/libexec/src/testing/testing.go:697 +0x543"},
			{Type: "output", Data: "  testing.runTests.func1()"},
			{Type: "output", Data: "      /usr/local/Cellar/go/1.8.3/libexec/src/testing/testing.go:882 +0xaa"},
			{Type: "output", Data: "  testing.tRunner()"},
			{Type: "output", Data: "      /usr/local/Cellar/go/1.8.3/libexec/src/testing/testing.go:657 +0x107"},
			{Type: "output", Data: "  testing.runTests()"},
			{Type: "output", Data: "      /usr/local/Cellar/go/1.8.3/libexec/src/testing/testing.go:888 +0x4e0"},
			{Type: "output", Data: "  testing.(*M).Run()"},
			{Type: "output", Data: "      /usr/local/Cellar/go/1.8.3/libexec/src/testing/testing.go:822 +0x1c3"},
			{Type: "output", Data: "  main.main()"},
			{Type: "output", Data: "      _test/_testmain.go:52 +0x20f"},
			{Type: "output", Data: "=================="},
			{Type: "end_test", Name: "TestRace", Result: "FAIL"},
			{Type: "output", Data: "\ttesting.go:610: race detected during execution of test"},
			{Type: "status", Result: "FAIL"},
			{Type: "output", Data: "exit status 1"},
			{Type: "summary", Result: "FAIL", Name: "race_test", Duration: 15 * time.Millisecond},
		}},
	{"18-coverpkg",
		[]gtr.Event{
			{Type: "run_test", Name: "TestA"},
			{Type: "end_test", Name: "TestA", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "run_test", Name: "TestB"},
			{Type: "end_test", Name: "TestB", Result: "PASS", Duration: 300 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "coverage", CovPct: 10, CovPackages: []string{"fmt", "encoding/xml"}},
			{Type: "summary", Result: "ok", Name: "package1/foo", Duration: 400 * time.Millisecond, CovPct: 10, CovPackages: []string{"fmt", "encoding/xml"}},
			{Type: "run_test", Name: "TestC"},
			{Type: "end_test", Name: "TestC", Result: "PASS", Duration: 4200 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "coverage", CovPct: 99.8, CovPackages: []string{"fmt", "encoding/xml"}},
			{Type: "summary", Result: "ok", Name: "package2/bar", Duration: 4200 * time.Millisecond, CovPct: 99.8, CovPackages: []string{"fmt", "encoding/xml"}},
		}},
	{"19-pass",
		[]gtr.Event{
			{Type: "run_test", Name: "TestZ"},
			{Type: "output", Data: "some inline text"},
			{Type: "end_test", Name: "TestZ", Result: "PASS", Duration: 60 * time.Millisecond},
			{Type: "run_test", Name: "TestA"},
			{Type: "end_test", Name: "TestA", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name", Duration: 160 * time.Millisecond},
		}},
	{"20-parallel",
		[]gtr.Event{
			{Type: "run_test", Name: "FirstTest"},
			{Type: "output", Data: "Message from first"},
			{Type: "pause_test", Name: "FirstTest"},
			{Type: "run_test", Name: "SecondTest"},
			{Type: "output", Data: "Message from second"},
			{Type: "pause_test", Name: "SecondTest"},
			{Type: "cont_test", Name: "FirstTest"},
			{Type: "output", Data: "Supplemental from first"},
			{Type: "run_test", Name: "ThirdTest"},
			{Type: "output", Data: "Message from third"},
			{Type: "end_test", Name: "ThirdTest", Result: "FAIL", Duration: 10 * time.Millisecond},
			{Type: "output", Data: "\tparallel_test.go:32: ThirdTest error"},
			{Type: "end_test", Name: "FirstTest", Result: "FAIL", Duration: 2 * time.Second},
			{Type: "output", Data: "\tparallel_test.go:14: FirstTest error"},
			{Type: "end_test", Name: "SecondTest", Result: "FAIL", Duration: 1 * time.Second},
			{Type: "output", Data: "\tparallel_test.go:23: SecondTest error"},
			{Type: "status", Result: "FAIL"},
			{Type: "output", Data: "exit status 1"},
			{Type: "summary", Result: "FAIL", Name: "pkg/parallel", Duration: 3010 * time.Millisecond},
		}},
	{"21-cached",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "PASS"},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/one", Data: "(cached)"},
		}},
	{"22-bench",
		[]gtr.Event{
			{Type: "output", Data: "goos: darwin"},
			{Type: "output", Data: "goarch: amd64"},
			{Type: "output", Data: "pkg: code.internal/state"},
			{Type: "benchmark", Name: "BenchmarkParse", Iterations: 2000000, NsPerOp: 604},
			{Type: "benchmark", Name: "BenchmarkReadingList", Iterations: 1000000, NsPerOp: 1425},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/basic", Duration: 3212 * time.Millisecond},
		}},
	{"23-benchmem",
		[]gtr.Event{
			{Type: "output", Data: "goos: darwin"},
			{Type: "output", Data: "goarch: amd64"},
			{Type: "output", Data: "pkg: code.internal/state"},
			{Type: "benchmark", Name: "BenchmarkIpsHistoryInsert", Iterations: 30000, NsPerOp: 52568, BytesPerOp: 24879, AllocsPerOp: 494},
			{Type: "benchmark", Name: "BenchmarkIpsHistoryLookup", Iterations: 100000, NsPerOp: 15208, BytesPerOp: 7369, AllocsPerOp: 143},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/one", Duration: 9415 * time.Millisecond},
		}},
	{"24-benchtests",
		[]gtr.Event{
			{Type: "run_test", Name: "TestNew"},
			{Type: "run_test", Name: "TestNew/no"},
			{Type: "run_test", Name: "TestNew/normal"},
			{Type: "end_test", Name: "TestNew", Result: "PASS"},
			{Type: "end_test", Name: "TestNew/no", Result: "PASS", Indent: 1},
			{Type: "end_test", Name: "TestNew/normal", Result: "PASS", Indent: 1},
			{Type: "run_test", Name: "TestWriteThis"},
			{Type: "end_test", Name: "TestWriteThis", Result: "PASS"},
			{Type: "output", Data: "goos: darwin"},
			{Type: "output", Data: "goarch: amd64"},
			{Type: "output", Data: "pkg: package3/baz"},
			{Type: "benchmark", Name: "BenchmarkDeepMerge", Iterations: 500000, NsPerOp: 2611, BytesPerOp: 1110, AllocsPerOp: 16},
			{Type: "benchmark", Name: "BenchmarkNext", Iterations: 500000, NsPerOp: 100, BytesPerOp: 100, AllocsPerOp: 1},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package3/baz", Duration: 1382 * time.Millisecond},
		}},
	{"25-benchcount",
		[]gtr.Event{
			{Type: "benchmark", Name: "BenchmarkNew", Iterations: 5000000, NsPerOp: 350, BytesPerOp: 80, AllocsPerOp: 3},
			{Type: "benchmark", Name: "BenchmarkNew", Iterations: 5000000, NsPerOp: 357, BytesPerOp: 80, AllocsPerOp: 3},
			{Type: "benchmark", Name: "BenchmarkNew", Iterations: 5000000, NsPerOp: 354, BytesPerOp: 80, AllocsPerOp: 3},
			{Type: "benchmark", Name: "BenchmarkNew", Iterations: 5000000, NsPerOp: 358, BytesPerOp: 80, AllocsPerOp: 3},
			{Type: "benchmark", Name: "BenchmarkNew", Iterations: 5000000, NsPerOp: 345, BytesPerOp: 80, AllocsPerOp: 3},
			{Type: "benchmark", Name: "BenchmarkFew", Iterations: 5000000, NsPerOp: 100, BytesPerOp: 20, AllocsPerOp: 1},
			{Type: "benchmark", Name: "BenchmarkFew", Iterations: 5000000, NsPerOp: 105, BytesPerOp: 20, AllocsPerOp: 1},
			{Type: "benchmark", Name: "BenchmarkFew", Iterations: 5000000, NsPerOp: 102, BytesPerOp: 20, AllocsPerOp: 1},
			{Type: "benchmark", Name: "BenchmarkFew", Iterations: 5000000, NsPerOp: 102, BytesPerOp: 20, AllocsPerOp: 1},
			{Type: "benchmark", Name: "BenchmarkFew", Iterations: 5000000, NsPerOp: 102, BytesPerOp: 20, AllocsPerOp: 1},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "pkg/count", Duration: 14211 * time.Millisecond},
		}},
	{"26-testbenchmultiple",
		[]gtr.Event{
			{Type: "output", Data: "pkg: mycode/common"},
			{Type: "benchmark", Name: "BenchmarkParse", Iterations: 1000000, NsPerOp: 1591},
			{Type: "benchmark", Name: "BenchmarkNewTask", Iterations: 3000000, NsPerOp: 391},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "mycode/common", Duration: 7267 * time.Millisecond},
			{Type: "output", Data: "pkg: mycode/benchmarks/channels"},
			{Type: "benchmark", Name: "BenchmarkFanout/Channel/10", Iterations: 500000, NsPerOp: 4673},
			{Type: "benchmark", Name: "BenchmarkFanout/Channel/100", Iterations: 50000, NsPerOp: 24965},
			{Type: "benchmark", Name: "BenchmarkFanout/Channel/1000", Iterations: 10000, NsPerOp: 195672},
			{Type: "benchmark", Name: "BenchmarkFanout/Channel/10000", Iterations: 500, NsPerOp: 2410200},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "mycode/benchmarks/channels", Duration: 47084 * time.Millisecond},
		}},
	{"27-benchdecimal",
		[]gtr.Event{
			{Type: "output", Data: "goos: darwin"},
			{Type: "output", Data: "goarch: amd64"},
			{Type: "output", Data: "pkg: really/small"},
			{Type: "benchmark", Name: "BenchmarkItsy", Iterations: 30000000, NsPerOp: 45.7},
			{Type: "benchmark", Name: "BenchmarkTeeny", Iterations: 1000000000, NsPerOp: 2.12},
			{Type: "benchmark", Name: "BenchmarkWeeny", Iterations: 2000000000, NsPerOp: 0.26},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "really/small", Duration: 4344 * time.Millisecond},
		}},
	{"28-bench-1cpu",
		[]gtr.Event{
			{Type: "output", Data: "pkg: single/cpu"},
			{Type: "benchmark", Name: "BenchmarkRing", Iterations: 20000000, NsPerOp: 74.2},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "single/cpu", Duration: 9467 * time.Millisecond},
		}},
	{"29-bench-16cpu",
		[]gtr.Event{
			{Type: "output", Data: "pkg: sixteen/cpu"},
			{Type: "benchmark", Name: "BenchmarkRingaround", Iterations: 100000, NsPerOp: 13571},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "sixteen/cpu", Duration: 1522 * time.Millisecond},
		}},
	{"30-stdout",
		[]gtr.Event{
			{Type: "run_test", Name: "TestFailWithStdoutAndTestOutput"},
			{Type: "output", Data: "multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "single-line stdout"},
			{Type: "end_test", Name: "TestFailWithStdoutAndTestOutput", Result: "FAIL", Duration: 100 * time.Millisecond},
			{Type: "output", Data: "    example_test.go:13: single-line error"},
			{Type: "output", Data: "    example_test.go:14: multi"},
			{Type: "output", Data: "        line"},
			{Type: "output", Data: "        error"},
			{Type: "run_test", Name: "TestFailWithStdoutAndNoTestOutput"},
			{Type: "output", Data: "multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "single-line stdout"},
			{Type: "end_test", Name: "TestFailWithStdoutAndNoTestOutput", Result: "FAIL", Duration: 150 * time.Millisecond},
			{Type: "run_test", Name: "TestFailWithTestOutput"},
			{Type: "end_test", Name: "TestFailWithTestOutput", Result: "FAIL", Duration: 200 * time.Millisecond},
			{Type: "output", Data: "    example_test.go:26: single-line error"},
			{Type: "output", Data: "    example_test.go:27: multi"},
			{Type: "output", Data: "        line"},
			{Type: "output", Data: "        error"},
			{Type: "run_test", Name: "TestFailWithNoTestOutput"},
			{Type: "end_test", Name: "TestFailWithNoTestOutput", Result: "FAIL", Duration: 250 * time.Millisecond},
			{Type: "run_test", Name: "TestPassWithStdoutAndTestOutput"},
			{Type: "output", Data: "multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "single-line stdout"},
			{Type: "end_test", Name: "TestPassWithStdoutAndTestOutput", Result: "PASS", Duration: 300 * time.Millisecond},
			{Type: "output", Data: "    example_test.go:39: single-line info"},
			{Type: "output", Data: "    example_test.go:40: multi"},
			{Type: "output", Data: "        line"},
			{Type: "output", Data: "        info"},
			{Type: "run_test", Name: "TestPassWithStdoutAndNoTestOutput"},
			{Type: "output", Data: "multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "single-line stdout"},
			{Type: "end_test", Name: "TestPassWithStdoutAndNoTestOutput", Result: "PASS", Duration: 350 * time.Millisecond},
			{Type: "run_test", Name: "TestPassWithTestOutput"},
			{Type: "end_test", Name: "TestPassWithTestOutput", Result: "PASS", Duration: 400 * time.Millisecond},
			{Type: "output", Data: "    example_test.go:51: single-line info"},
			{Type: "output", Data: "    example_test.go:52: multi"},
			{Type: "output", Data: "        line"},
			{Type: "output", Data: "        info"},
			{Type: "run_test", Name: "TestPassWithNoTestOutput"},
			{Type: "end_test", Name: "TestPassWithNoTestOutput", Result: "PASS", Duration: 500 * time.Millisecond},
			{Type: "run_test", Name: "TestSubtests"},
			{Type: "run_test", Name: "TestSubtests/TestFailWithStdoutAndTestOutput"},
			{Type: "output", Data: "1 multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "1 single-line stdout"},
			{Type: "run_test", Name: "TestSubtests/TestFailWithStdoutAndNoTestOutput"},
			{Type: "output", Data: "2 multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "2 single-line stdout"},
			{Type: "run_test", Name: "TestSubtests/TestFailWithTestOutput"},
			{Type: "run_test", Name: "TestSubtests/TestFailWithNoTestOutput"},
			{Type: "run_test", Name: "TestSubtests/TestPassWithStdoutAndTestOutput"},
			{Type: "output", Data: "4 multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "4 single-line stdout"},
			{Type: "run_test", Name: "TestSubtests/TestPassWithStdoutAndNoTestOutput"},
			{Type: "output", Data: "5 multi"},
			{Type: "output", Data: "line"},
			{Type: "output", Data: "stdout"},
			{Type: "output", Data: "5 single-line stdout"},
			{Type: "run_test", Name: "TestSubtests/TestPassWithTestOutput"},
			{Type: "run_test", Name: "TestSubtests/TestPassWithNoTestOutput"},
			{Type: "end_test", Name: "TestSubtests", Result: "FAIL", Duration: 2270 * time.Millisecond},
			{Type: "end_test", Name: "TestSubtests/TestFailWithStdoutAndTestOutput", Result: "FAIL", Indent: 1, Duration: 100 * time.Millisecond},
			{Type: "output", Data: "        example_test.go:65: 1 single-line error"},
			{Type: "output", Data: "        example_test.go:66: 1 multi"},
			{Type: "output", Data: "            line"},
			{Type: "output", Data: "            error"},
			{Type: "end_test", Name: "TestSubtests/TestFailWithStdoutAndNoTestOutput", Result: "FAIL", Indent: 1, Duration: 150 * time.Millisecond},
			{Type: "end_test", Name: "TestSubtests/TestFailWithTestOutput", Result: "FAIL", Indent: 1, Duration: 200 * time.Millisecond},
			{Type: "output", Data: "        example_test.go:78: 3 single-line error"},
			{Type: "output", Data: "        example_test.go:79: 3 multi"},
			{Type: "output", Data: "            line"},
			{Type: "output", Data: "            error"},
			{Type: "end_test", Name: "TestSubtests/TestFailWithNoTestOutput", Result: "FAIL", Indent: 1, Duration: 250 * time.Millisecond},
			{Type: "end_test", Name: "TestSubtests/TestPassWithStdoutAndTestOutput", Result: "PASS", Indent: 1, Duration: 300 * time.Millisecond},
			{Type: "output", Data: "        example_test.go:91: 4 single-line info"},
			{Type: "output", Data: "        example_test.go:92: 4 multi"},
			{Type: "output", Data: "            line"},
			{Type: "output", Data: "            info"},
			{Type: "end_test", Name: "TestSubtests/TestPassWithStdoutAndNoTestOutput", Result: "PASS", Indent: 1, Duration: 350 * time.Millisecond},
			{Type: "end_test", Name: "TestSubtests/TestPassWithTestOutput", Result: "PASS", Indent: 1, Duration: 400 * time.Millisecond},
			{Type: "output", Data: "        example_test.go:103: 6 single-line info"},
			{Type: "output", Data: "        example_test.go:104: 6 multi"},
			{Type: "output", Data: "            line"},
			{Type: "output", Data: "            info"},
			{Type: "end_test", Name: "TestSubtests/TestPassWithNoTestOutput", Result: "PASS", Indent: 1, Duration: 500 * time.Millisecond},
			{Type: "status", Result: "FAIL"},
			{Type: "summary", Result: "FAIL", Name: "package/name1", Duration: 4567 * time.Millisecond},
		}},
	{"31-syntax-error-test-binary",
		[]gtr.Event{
			{Type: "output", Data: "# package/name/failing1 [package/name/failing1.test]"},
			{Type: "output", Data: "failing1/failing_test.go:15: undefined: x"},
			{Type: "output", Data: "# package/name/failing2 [package/name/failing2.test]"},
			{Type: "output", Data: "failing2/another_failing_test.go:20: undefined: y"},
			{Type: "output", Data: "# package/name/setupfailing1 [package/name/setupfailing1.test]"},
			{Type: "output", Data: "setupfailing1/failing_test.go:4: cannot find package \"other/package\" in any of:"},
			{Type: "output", Data: "\t/path/vendor (vendor tree)"},
			{Type: "output", Data: "\t/path/go/root (from $GOROOT)"},
			{Type: "output", Data: "\t/path/go/path (from $GOPATH)"},
			{Type: "run_test", Name: "TestA"},
			{Type: "end_test", Name: "TestA", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name/passing1", Duration: 100 * time.Millisecond},
			{Type: "run_test", Name: "TestB"},
			{Type: "end_test", Name: "TestB", Result: "PASS", Duration: 100 * time.Millisecond},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "package/name/passing2", Duration: 100 * time.Millisecond},
			{Type: "summary", Result: "FAIL", Name: "package/name/failing1", Data: "[build failed]"},
			{Type: "summary", Result: "FAIL", Name: "package/name/failing2", Data: "[build failed]"},
			{Type: "summary", Result: "FAIL", Name: "package/name/setupfailing1", Data: "[setup failed]"},
		}},
	{"32-failed-summary",
		[]gtr.Event{
			{Type: "run_test", Name: "TestOne"},
			{Type: "end_test", Name: "TestOne", Result: "PASS"},
			{Type: "status", Result: "PASS"},
			{Type: "output", Data: "panic: panic"},
			{Type: "summary", Result: "FAIL", Name: "github.com/jstemmer/test/failedsummary", Duration: 5 * time.Millisecond},
		}},
	{"130-bench-mb",
		[]gtr.Event{
			{Type: "output", Data: "goos: linux"},
			{Type: "output", Data: "goarch: amd64"},
			{Type: "output", Data: "pkg: compress/flate"},
			{Type: "benchmark", Name: "BenchmarkDecode/Digits/Huffman/1e4", Iterations: 10000, NsPerOp: 104427, MBPerSec: 95.76, BytesPerOp: 40629, AllocsPerOp: 5},
			{Type: "benchmark", Name: "BenchmarkEncode/Digits/Huffman/1e4", Iterations: 50000, NsPerOp: 28334, MBPerSec: 352.93},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "compress/flate", Duration: 83202 * time.Millisecond},
		}},
	{"131-whitespace",
		[]gtr.Event{
			{Type: "run_test", Name: "TestFlat"},
			{Type: "output", Data: "printf 1"},
			{Type: "output", Data: "printf 2"},
			{Type: "end_test", Name: "TestFlat", Result: "PASS"},
			{Type: "output", Data: "\twhitespace_test.go:9: log 1"},
			{Type: "output", Data: "\twhitespace_test.go:10: log 2"},
			{Type: "run_test", Name: "TestWithSpace"},
			{Type: "output", Data: "no-space"},
			{Type: "output", Data: " one-space"},
			{Type: "output", Data: "  two-space"},
			{Type: "output", Data: "    four-space"},
			{Type: "output", Data: "        eight-space"},
			{Type: "output", Data: "no-space"},
			{Type: "end_test", Name: "TestWithSpace", Result: "PASS"},
			{Type: "output", Data: "\twhitespace_test.go:16: no-space"},
			{Type: "output", Data: "\twhitespace_test.go:17:  one-space"},
			{Type: "output", Data: "\twhitespace_test.go:18:   two-space"},
			{Type: "output", Data: "\twhitespace_test.go:19:     four-space"},
			{Type: "output", Data: "\twhitespace_test.go:20:         eight-space"},
			{Type: "output", Data: "\twhitespace_test.go:21: no-space"},
			{Type: "run_test", Name: "TestWithTab"},
			{Type: "output", Data: "no-tab"},
			{Type: "output", Data: "\tone-tab"},
			{Type: "output", Data: "\t\ttwo-tab"},
			{Type: "end_test", Name: "TestWithTab", Result: "PASS"},
			{Type: "output", Data: "\twhitespace_test.go:31: no-tab"},
			{Type: "output", Data: "\twhitespace_test.go:32: \tone-tab"},
			{Type: "output", Data: "\twhitespace_test.go:33: \t\ttwo-tab"},
			{Type: "run_test", Name: "TestWithNewlinesFlat"},
			{Type: "output", Data: "no-newline"},
			{Type: "output", Data: "one-newline"},
			{Type: "output", Data: "one-newline"},
			{Type: "output", Data: "two-newlines"},
			{Type: "output", Data: "two-newlines"},
			{Type: "output", Data: "two-newlines"},
			{Type: "end_test", Name: "TestWithNewlinesFlat", Result: "PASS"},
			{Type: "output", Data: "\twhitespace_test.go:40: no-newline"},
			{Type: "output", Data: "\twhitespace_test.go:41: one-newline"},
			{Type: "output", Data: "\t\tone-newline"},
			{Type: "output", Data: "\twhitespace_test.go:42: two-newlines"},
			{Type: "output", Data: "\t\ttwo-newlines"},
			{Type: "output", Data: "\t\ttwo-newlines"},
			{Type: "run_test", Name: "TestSubTests"},
			{Type: "run_test", Name: "TestSubTests/TestFlat"},
			{Type: "output", Data: "printf 1"},
			{Type: "output", Data: "printf 2"},
			{Type: "run_test", Name: "TestSubTests/TestWithSpace"},
			{Type: "output", Data: "no-space"},
			{Type: "output", Data: " one-space"},
			{Type: "output", Data: "  two-space"},
			{Type: "output", Data: "    four-space"},
			{Type: "output", Data: "        eight-space"},
			{Type: "output", Data: "no-space"},
			{Type: "run_test", Name: "TestSubTests/TestWithTab"},
			{Type: "output", Data: "no-tab"},
			{Type: "output", Data: "\tone-tab"},
			{Type: "output", Data: "\t\ttwo-tab"},
			{Type: "run_test", Name: "TestSubTests/TestWithNewlinesFlat"},
			{Type: "output", Data: "no-newline"},
			{Type: "output", Data: "one-newline"},
			{Type: "output", Data: "one-newline"},
			{Type: "output", Data: "two-newlines"},
			{Type: "output", Data: "two-newlines"},
			{Type: "output", Data: "two-newlines"},
			{Type: "end_test", Name: "TestSubTests", Result: "PASS"},
			{Type: "end_test", Name: "TestSubTests/TestFlat", Result: "PASS", Indent: 1},
			{Type: "output", Data: "    \twhitespace_test.go:9: log 1"},
			{Type: "output", Data: "    \twhitespace_test.go:10: log 2"},
			{Type: "end_test", Name: "TestSubTests/TestWithSpace", Result: "PASS", Indent: 1},
			{Type: "output", Data: "    \twhitespace_test.go:16: no-space"},
			{Type: "output", Data: "    \twhitespace_test.go:17:  one-space"},
			{Type: "output", Data: "    \twhitespace_test.go:18:   two-space"},
			{Type: "output", Data: "    \twhitespace_test.go:19:     four-space"},
			{Type: "output", Data: "    \twhitespace_test.go:20:         eight-space"},
			{Type: "output", Data: "    \twhitespace_test.go:21: no-space"},
			{Type: "end_test", Name: "TestSubTests/TestWithTab", Result: "PASS", Indent: 1},
			{Type: "output", Data: "    \twhitespace_test.go:31: no-tab"},
			{Type: "output", Data: "    \twhitespace_test.go:32: 	one-tab"},
			{Type: "output", Data: "    \twhitespace_test.go:33: 		two-tab"},
			{Type: "end_test", Name: "TestSubTests/TestWithNewlinesFlat", Result: "PASS", Indent: 1},
			{Type: "output", Data: "    \twhitespace_test.go:40: no-newline"},
			{Type: "output", Data: "    \twhitespace_test.go:41: one-newline"},
			{Type: "output", Data: "    \t\tone-newline"},
			{Type: "output", Data: "    \twhitespace_test.go:42: two-newlines"},
			{Type: "output", Data: "    \t\ttwo-newlines"},
			{Type: "output", Data: "    \t\ttwo-newlines"},
			{Type: "status", Result: "PASS"},
			{Type: "summary", Result: "ok", Name: "github.com/jstemmer/test/whitespace", Duration: 1 * time.Millisecond},
		}},
}

func TestParse(t *testing.T) {
	matchRegex := compileMatch(t)
	for _, test := range tests {
		t.Run(test.in, func(t *testing.T) {
			if !matchRegex.MatchString(test.in) || len(test.expected) == 0 {
				t.SkipNow()
			}
			testParse(t, test.in, test.expected)
		})
	}
}

func testParse(t *testing.T, name string, expected []gtr.Event) {
	f, err := os.Open(filepath.Join(testdataRoot, name+".txt"))
	if err != nil {
		t.Errorf("error reading %s: %v", name, err)
		return
	}
	defer f.Close()

	actual, err := Parse(f)
	if err != nil {
		t.Errorf("Parse(%s) error: %v", name, err)
		return
	}

	if diff := cmp.Diff(actual, expected); diff != "" {
		t.Errorf("Parse %s returned unexpected events, diff (-got, +want):\n%v", name, diff)
	}
}

func compileMatch(t *testing.T) *regexp.Regexp {
	rx, err := regexp.Compile(*matchTest)
	if err != nil {
		t.Fatalf("Error compiling -match flag %q: %v", *matchTest, err)
	}
	return rx
}