1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
package parser
import (
"fmt"
"github.com/google/go-cmp/cmp"
"io"
"strings"
"testing"
)
type result struct {
data string // the current data at each iteration
num int // the number of bytes read
forwardErr error
backwardErr error
sought int // the number of bytes sought in case of backwards seek
}
func TestArbitraryReader(t *testing.T) {
for _, test := range []struct {
input string
backto byte
update bool
res []result
}{
{
input: "ciao",
res: []result{
{"ciao", 4, io.ErrUnexpectedEOF, nil, 0},
},
},
{
input: "ciao\nmondo",
res: []result{
{"ciao\n", 5, nil, nil, 0},
{"ciao\nmondo", 5, io.ErrUnexpectedEOF, nil, 0},
},
},
{
input: "ciao\nmondo\n",
res: []result{
{"ciao\n", 5, nil, nil, 0},
{"ciao\nmondo\n", 6, nil, nil, 0},
{"ciao\nmondo\n", 0, io.EOF, nil, 0},
},
},
// Updating the window
{
input: "ciao\nmondo",
update: true,
res: []result{
{"ciao\n", 5, nil, nil, 0},
{"mondo", 5, io.ErrUnexpectedEOF, nil, 0},
},
},
{
input: "ciao\nmondo\n",
update: true,
res: []result{
{"ciao\n", 5, nil, nil, 0},
{"mondo\n", 6, nil, nil, 0},
{"", 0, io.EOF, nil, 0},
},
},
{
input: "abcabc\ncbacba\n",
backto: 'b', // and then seek backwards until this
update: true, // so to start again from the character after its (backto) first occurrence
res: []result{
{"abcabc\n", 7, nil, nil, 3},
{"c\ncbacba\n", 7, nil, nil, 3}, // 9 - 2 (already read)
{"a\n", 0, io.EOF, nil, 0},
},
},
{
input: "ciao\nciao\n",
backto: '\n',
res: []result{
{"ciao\n", 5, nil, nil, 1},
{"ciao\nciao\n", 5, nil, nil, 1},
},
},
{
input: "ciao\nciao",
backto: '\n',
res: []result{
{"ciao\n", 5, nil, nil, 1},
{"ciao\nciao", 4, io.ErrUnexpectedEOF, nil, 0}, // not going backwards since we avoid loop checking for error
},
},
} {
r := ArbitraryReader(strings.NewReader(test.input), '\n')
for _, o := range test.res {
res, err := r.Read()
// Check error reading forward
errorCheck(t, o.forwardErr, err)
if test.backto > 0 && err == nil {
nb, err := r.Seek(test.backto, true)
// Check error reading backwards
errorCheck(t, o.backwardErr, err)
// Check number of sought bytes
check(t, o.sought, nb)
}
// Check number of read bytes
check(t, o.num, len(res))
// Check the current data window
check(t, o.data, string(r.data))
if test.update {
// Updating the start and end position of the window for next run
r.p = r.pe
}
}
}
}
func check(t *testing.T, x, y interface{}) {
if diff := cmp.Diff(x, y); diff != "" {
t.Errorf("(-want +got)\n%s", diff)
}
}
func errorCheck(t *testing.T, x, y error) {
if x != nil && y != nil && x.Error() != y.Error() {
t.Errorf("(-want +got)\n%s", fmt.Sprintf("-: %#v\n+: %#v", x.Error(), y.Error()))
}
}
|