mirror of
https://github.com/golang/go
synced 2024-11-05 17:26:11 -07:00
0110d43865
CL 179377 introduced an optimized parser for coverage profiles. The parser replaces the following regex: ^(.+):([0-9]+)\.([0-9]+),([0-9]+)\.([0-9]+) ([0-9]+) ([0-9]+)$ With this regex, negative numbers in the coverage profiles resulted in parsing errors. With the new parser in place, this is no longer the case. This commit restores the old behavior. Change-Id: Iaa72035f1f587ed186eaf5a84b209df88e67fb57 GitHub-Last-Rev: 07470fba9d587e6d3f383409fc8cf52bb882a984 GitHub-Pull-Request: golang/tools#195 Reviewed-on: https://go-review.googlesource.com/c/tools/+/213357 Reviewed-by: Katharine Berry <ktbry@google.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
262 lines
5.6 KiB
Go
262 lines
5.6 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package cover
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseProfiles(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
output []*Profile
|
|
expectErr bool
|
|
}{
|
|
{
|
|
name: "parsing an empty file produces empty output",
|
|
input: `mode: set`,
|
|
output: []*Profile{},
|
|
},
|
|
{
|
|
name: "simple valid file produces expected output",
|
|
input: `mode: set
|
|
some/fancy/path:42.69,44.16 2 1`,
|
|
output: []*Profile{
|
|
{
|
|
FileName: "some/fancy/path",
|
|
Mode: "set",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 42, StartCol: 69,
|
|
EndLine: 44, EndCol: 16,
|
|
NumStmt: 2, Count: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "file with syntax characters in path produces expected output",
|
|
input: `mode: set
|
|
some fancy:path/some,file.go:42.69,44.16 2 1`,
|
|
output: []*Profile{
|
|
{
|
|
FileName: "some fancy:path/some,file.go",
|
|
Mode: "set",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 42, StartCol: 69,
|
|
EndLine: 44, EndCol: 16,
|
|
NumStmt: 2, Count: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "file with multiple blocks in one file produces expected output",
|
|
input: `mode: set
|
|
some/fancy/path:42.69,44.16 2 1
|
|
some/fancy/path:44.16,46.3 1 0`,
|
|
output: []*Profile{
|
|
{
|
|
FileName: "some/fancy/path",
|
|
Mode: "set",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 42, StartCol: 69,
|
|
EndLine: 44, EndCol: 16,
|
|
NumStmt: 2, Count: 1,
|
|
},
|
|
{
|
|
StartLine: 44, StartCol: 16,
|
|
EndLine: 46, EndCol: 3,
|
|
NumStmt: 1, Count: 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "file with multiple files produces expected output",
|
|
input: `mode: set
|
|
another/fancy/path:44.16,46.3 1 0
|
|
some/fancy/path:42.69,44.16 2 1`,
|
|
output: []*Profile{
|
|
{
|
|
FileName: "another/fancy/path",
|
|
Mode: "set",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 44, StartCol: 16,
|
|
EndLine: 46, EndCol: 3,
|
|
NumStmt: 1, Count: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
FileName: "some/fancy/path",
|
|
Mode: "set",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 42, StartCol: 69,
|
|
EndLine: 44, EndCol: 16,
|
|
NumStmt: 2, Count: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "intertwined files are merged correctly",
|
|
input: `mode: set
|
|
some/fancy/path:42.69,44.16 2 1
|
|
another/fancy/path:47.2,47.13 1 1
|
|
some/fancy/path:44.16,46.3 1 0`,
|
|
output: []*Profile{
|
|
{
|
|
FileName: "another/fancy/path",
|
|
Mode: "set",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 47, StartCol: 2,
|
|
EndLine: 47, EndCol: 13,
|
|
NumStmt: 1, Count: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
FileName: "some/fancy/path",
|
|
Mode: "set",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 42, StartCol: 69,
|
|
EndLine: 44, EndCol: 16,
|
|
NumStmt: 2, Count: 1,
|
|
},
|
|
{
|
|
StartLine: 44, StartCol: 16,
|
|
EndLine: 46, EndCol: 3,
|
|
NumStmt: 1, Count: 0,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "duplicate blocks are merged correctly",
|
|
input: `mode: count
|
|
some/fancy/path:42.69,44.16 2 4
|
|
some/fancy/path:42.69,44.16 2 3`,
|
|
output: []*Profile{
|
|
{
|
|
FileName: "some/fancy/path",
|
|
Mode: "count",
|
|
Blocks: []ProfileBlock{
|
|
{
|
|
StartLine: 42, StartCol: 69,
|
|
EndLine: 44, EndCol: 16,
|
|
NumStmt: 2, Count: 7,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "an invalid mode line is an error",
|
|
input: `mode:count`,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "a missing field is an error",
|
|
input: `mode: count
|
|
some/fancy/path:42.69,44.16 2`,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "a missing path field is an error",
|
|
input: `mode: count
|
|
42.69,44.16 2 3`,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "a non-numeric count is an error",
|
|
input: `mode: count
|
|
42.69,44.16 2 nope`,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "an empty path is an error",
|
|
input: `mode: count
|
|
:42.69,44.16 2 3`,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "a negative count is an error",
|
|
input: `mode: count
|
|
some/fancy/path:42.69,44.16 2 -1`,
|
|
expectErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
f, err := ioutil.TempFile("", "")
|
|
if err != nil {
|
|
t.Fatalf("Failed to create a temp file: %v.", err)
|
|
}
|
|
defer func() {
|
|
f.Close()
|
|
os.Remove(f.Name())
|
|
}()
|
|
n, err := f.WriteString(tc.input)
|
|
if err != nil {
|
|
t.Fatalf("Failed to write to temp file: %v", err)
|
|
}
|
|
if n < len(tc.input) {
|
|
t.Fatalf("Didn't write enough bytes to temp file (wrote %d, expected %d).", n, len(tc.input))
|
|
}
|
|
if err := f.Sync(); err != nil {
|
|
t.Fatalf("Failed to sync temp file: %v", err)
|
|
}
|
|
|
|
result, err := ParseProfiles(f.Name())
|
|
if err != nil {
|
|
if !tc.expectErr {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
return
|
|
}
|
|
if tc.expectErr {
|
|
t.Errorf("Expected an error, but got value %q", stringifyProfileArray(result))
|
|
}
|
|
if !reflect.DeepEqual(result, tc.output) {
|
|
t.Errorf("Mismatched results.\nExpected: %s\nActual: %s", stringifyProfileArray(tc.output), stringifyProfileArray(result))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func stringifyProfileArray(profiles []*Profile) string {
|
|
deref := make([]Profile, 0, len(profiles))
|
|
for _, p := range profiles {
|
|
deref = append(deref, *p)
|
|
}
|
|
return fmt.Sprintf("%#v", deref)
|
|
}
|
|
|
|
func BenchmarkParseLine(b *testing.B) {
|
|
const line = "k8s.io/kubernetes/cmd/kube-controller-manager/app/options/ttlafterfinishedcontroller.go:31.73,32.14 1 1"
|
|
b.SetBytes(int64(len(line)))
|
|
for n := 0; n < b.N; n++ {
|
|
parseLine(line)
|
|
}
|
|
}
|