mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
internal/runtime/cgroup: lineReader fuzz test
The original unit test is converted to a fuzz test, to be more confident on future refactors. All sub-tests are converted to seed corpus. Change-Id: Id0c167ed47729a00ea0614d17746ddcc284697d3 Reviewed-on: https://go-review.googlesource.com/c/go/+/723581 Auto-Submit: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
parent
ac3e0ae51a
commit
67851547d8
1 changed files with 136 additions and 97 deletions
|
|
@ -11,131 +11,134 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLineReader(t *testing.T) {
|
type nextLine struct {
|
||||||
type nextLine struct {
|
line string
|
||||||
line string
|
incomplete bool // next call before this line should return incomplete
|
||||||
incomplete bool // next call before this line should return incomplete
|
}
|
||||||
}
|
|
||||||
complete := func(s string) nextLine {
|
|
||||||
return nextLine{line: s}
|
|
||||||
}
|
|
||||||
incomplete := func(s string) nextLine {
|
|
||||||
return nextLine{line: s, incomplete: true}
|
|
||||||
}
|
|
||||||
|
|
||||||
const scratchSize = 8
|
func complete(s string) nextLine {
|
||||||
|
return nextLine{line: s}
|
||||||
|
}
|
||||||
|
func incomplete(s string) nextLine {
|
||||||
|
return nextLine{line: s, incomplete: true}
|
||||||
|
}
|
||||||
|
|
||||||
tests := []struct {
|
const scratchSize = 8
|
||||||
name string
|
|
||||||
contents string
|
var readerTests = []struct {
|
||||||
want []nextLine
|
name string
|
||||||
}{
|
contents string
|
||||||
{
|
want []nextLine
|
||||||
name: "empty",
|
}{
|
||||||
contents: "",
|
{
|
||||||
|
name: "empty",
|
||||||
|
contents: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single",
|
||||||
|
contents: "1234\n",
|
||||||
|
want: []nextLine{
|
||||||
|
complete("1234"),
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: "single",
|
{
|
||||||
contents: "1234\n",
|
name: "single-incomplete",
|
||||||
want: []nextLine{
|
contents: "1234",
|
||||||
complete("1234"),
|
want: []nextLine{
|
||||||
},
|
incomplete("1234"),
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: "single-incomplete",
|
{
|
||||||
contents: "1234",
|
name: "single-exact",
|
||||||
want: []nextLine{
|
contents: "1234567\n",
|
||||||
incomplete("1234"),
|
want: []nextLine{
|
||||||
},
|
complete("1234567"),
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: "single-exact",
|
{
|
||||||
contents: "1234567\n",
|
name: "single-exact-incomplete",
|
||||||
want: []nextLine{
|
contents: "12345678",
|
||||||
complete("1234567"),
|
want: []nextLine{
|
||||||
},
|
incomplete("12345678"),
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: "single-exact-incomplete",
|
{
|
||||||
contents: "12345678",
|
name: "multi",
|
||||||
want: []nextLine{
|
contents: `1234
|
||||||
incomplete("12345678"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "multi",
|
|
||||||
contents: `1234
|
|
||||||
5678
|
5678
|
||||||
`,
|
`,
|
||||||
want: []nextLine{
|
want: []nextLine{
|
||||||
complete("1234"),
|
complete("1234"),
|
||||||
complete("5678"),
|
complete("5678"),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: "multi-short",
|
{
|
||||||
contents: `12
|
name: "multi-short",
|
||||||
|
contents: `12
|
||||||
34
|
34
|
||||||
56
|
56
|
||||||
78
|
78
|
||||||
`,
|
`,
|
||||||
want: []nextLine{
|
want: []nextLine{
|
||||||
complete("12"),
|
complete("12"),
|
||||||
complete("34"),
|
complete("34"),
|
||||||
complete("56"),
|
complete("56"),
|
||||||
complete("78"),
|
complete("78"),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: "multi-notrailingnewline",
|
{
|
||||||
contents: `1234
|
name: "multi-notrailingnewline",
|
||||||
|
contents: `1234
|
||||||
5678`,
|
5678`,
|
||||||
want: []nextLine{
|
want: []nextLine{
|
||||||
complete("1234"),
|
complete("1234"),
|
||||||
incomplete("5678"),
|
incomplete("5678"),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
name: "middle-too-long",
|
{
|
||||||
contents: `1234
|
name: "middle-too-long",
|
||||||
|
contents: `1234
|
||||||
1234567890
|
1234567890
|
||||||
5678
|
5678
|
||||||
`,
|
`,
|
||||||
want: []nextLine{
|
want: []nextLine{
|
||||||
complete("1234"),
|
complete("1234"),
|
||||||
incomplete("12345678"),
|
incomplete("12345678"),
|
||||||
complete("5678"),
|
complete("5678"),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
// Multiple reads required to find newline.
|
{
|
||||||
name: "middle-way-too-long",
|
// Multiple reads required to find newline.
|
||||||
contents: `1234
|
name: "middle-way-too-long",
|
||||||
|
contents: `1234
|
||||||
12345678900000000000000000000000000000000000000000000000000
|
12345678900000000000000000000000000000000000000000000000000
|
||||||
5678
|
5678
|
||||||
`,
|
`,
|
||||||
want: []nextLine{
|
want: []nextLine{
|
||||||
complete("1234"),
|
complete("1234"),
|
||||||
incomplete("12345678"),
|
incomplete("12345678"),
|
||||||
complete("5678"),
|
complete("5678"),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func readString(contents string) func(fd int, b []byte) (int, uintptr) {
|
||||||
|
r := strings.NewReader(contents)
|
||||||
|
return func(fd int, b []byte) (int, uintptr) {
|
||||||
|
n, err := r.Read(b)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
const dummyErrno = 42
|
||||||
|
return n, dummyErrno
|
||||||
|
}
|
||||||
|
return n, 0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
func TestLineReader(t *testing.T) {
|
||||||
|
for _, tc := range readerTests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
r := strings.NewReader(tc.contents)
|
|
||||||
read := func(fd int, b []byte) (int, uintptr) {
|
|
||||||
n, err := r.Read(b)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
const dummyErrno = 42
|
|
||||||
return n, dummyErrno
|
|
||||||
}
|
|
||||||
return n, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var scratch [scratchSize]byte
|
var scratch [scratchSize]byte
|
||||||
l := cgroup.NewLineReader(0, scratch[:], read)
|
l := cgroup.NewLineReader(0, scratch[:], readString(tc.contents))
|
||||||
|
|
||||||
var got []nextLine
|
var got []nextLine
|
||||||
for {
|
for {
|
||||||
|
|
@ -168,3 +171,39 @@ func TestLineReader(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FuzzLineReader(f *testing.F) {
|
||||||
|
for _, tc := range readerTests {
|
||||||
|
f.Add(tc.contents)
|
||||||
|
}
|
||||||
|
f.Fuzz(func(t *testing.T, input string) {
|
||||||
|
scratch := make([]byte, scratchSize)
|
||||||
|
reader := cgroup.NewLineReader(0, scratch, readString(input))
|
||||||
|
for expected := range strings.Lines(input) {
|
||||||
|
err := reader.Next()
|
||||||
|
line := reader.Line()
|
||||||
|
|
||||||
|
var expectedErr error
|
||||||
|
if len(expected) > scratchSize {
|
||||||
|
expected = expected[:scratchSize]
|
||||||
|
expectedErr = cgroup.ErrIncompleteLine
|
||||||
|
} else if expected[len(expected)-1] == '\n' {
|
||||||
|
expected = expected[:len(expected)-1]
|
||||||
|
} else {
|
||||||
|
expectedErr = cgroup.ErrIncompleteLine
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != expectedErr {
|
||||||
|
t.Fatalf("got err %v, want %v", err, expectedErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(line) != expected {
|
||||||
|
t.Fatalf("got %q, want %q", string(line), expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := reader.Next()
|
||||||
|
if err != cgroup.ErrEOF {
|
||||||
|
t.Fatalf("got %v, want EOF", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue