benchfmt: ignore just benchmark name on a line

"go test -v" prints just the benchmark name followed by a newline when
starting each benchmark. Currently, this causes benchfmt to report a
"missing iteration count" error on these lines. Make the parser ignore
this specific case.

Fixes golang/go#58528.

Change-Id: I92032d10f3cd3d4c8e867674c1905df9123f13fc
Reviewed-on: https://go-review.googlesource.com/c/perf/+/540795
Auto-Submit: Austin Clements <austin@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
diff --git a/benchfmt/reader.go b/benchfmt/reader.go
index 32b0ec6..817fd41 100644
--- a/benchfmt/reader.go
+++ b/benchfmt/reader.go
@@ -59,6 +59,7 @@
 }
 
 var noResult = &SyntaxError{"", 0, "Reader.Scan has not been called"}
+var errSkip = &SyntaxError{"", 0, "skip line"}
 
 // NewReader constructs a reader to parse the Go benchmark format from r.
 // fileName is used in error messages; it is purely diagnostic.
@@ -152,13 +153,10 @@
 		// Most lines are benchmark lines, and we can check
 		// for that very quickly, so start with that.
 		if bytes.HasPrefix(line, benchmarkPrefix) {
-			// At this point we commit to this being a
-			// benchmark line. If it's malformed, we treat
-			// that as an error.
-			if err := r.parseBenchmarkLine(line); err != nil {
-				r.q = append(r.q, err)
-			} else {
+			if err := r.parseBenchmarkLine(line); err == nil {
 				r.q = append(r.q, &r.result)
+			} else if err != errSkip {
+				r.q = append(r.q, err)
 			}
 			continue
 		}
@@ -248,8 +246,17 @@
 	line = line[len("Benchmark"):]
 
 	// Read the name.
+	lineLen := len(line)
 	r.result.Name, line = splitField(line)
 
+	// As a special case, if the name is the entire line, we
+	// ignore it. This happens in "go test -v" output, which
+	// prints the benchmark name immediately followed by a newline
+	// when the benchmark starts.
+	if len(line) == 0 && len(r.result.Name) == lineLen {
+		return errSkip
+	}
+
 	// Read the iteration count.
 	f, line = splitField(line)
 	if len(f) == 0 {
diff --git a/benchfmt/reader_test.go b/benchfmt/reader_test.go
index b1bad87..ac6d6cf 100644
--- a/benchfmt/reader_test.go
+++ b/benchfmt/reader_test.go
@@ -179,7 +179,7 @@
 		{
 			"bad lines",
 			`not a benchmark
-BenchmarkMissingIter
+BenchmarkMissingIter 
 BenchmarkBadIter abc
 BenchmarkHugeIter 9999999999999999999999999999999
 BenchmarkMissingVal 100
@@ -250,6 +250,19 @@
 					v(1, "ns/op").res,
 			},
 		},
+		{
+			// go test -v prints just the benchmark name
+			// on a line when starting each benchmark.
+			// Make sure we ignore it.
+			"verbose",
+			`BenchmarkOne
+BenchmarkOne 100 1 ns/op
+`,
+			[]Record{
+				r("One", 100).
+					v(1, "ns/op").res,
+			},
+		},
 	} {
 		t.Run(test.name, func(t *testing.T) {
 			got, _ := parseAll(t, test.input)