1
2
3
4
5 package protodelim_test
6
7 import (
8 "bufio"
9 "bytes"
10 "encoding/binary"
11 "errors"
12 "io"
13 "testing"
14
15 "github.com/google/go-cmp/cmp"
16 "google.golang.org/protobuf/encoding/protodelim"
17 "google.golang.org/protobuf/encoding/protowire"
18 "google.golang.org/protobuf/internal/testprotos/test3"
19 "google.golang.org/protobuf/testing/protocmp"
20 )
21
22 func TestRoundTrip(t *testing.T) {
23 msgs := []*test3.TestAllTypes{
24 {SingularInt32: 1},
25 {SingularString: "hello"},
26 {RepeatedDouble: []float64{1.2, 3.4}},
27 {
28 SingularNestedMessage: &test3.TestAllTypes_NestedMessage{A: 1},
29 RepeatedForeignMessage: []*test3.ForeignMessage{{C: 2}, {D: 3}},
30 },
31 }
32
33 buf := &bytes.Buffer{}
34
35
36 for _, m := range msgs {
37 if n, err := protodelim.MarshalTo(buf, m); err != nil {
38 t.Errorf("protodelim.MarshalTo(_, %v) = %d, %v", m, n, err)
39 }
40 }
41
42 for _, tc := range []struct {
43 name string
44 reader protodelim.Reader
45 }{
46 {name: "defaultbuffer", reader: bufio.NewReader(bytes.NewBuffer(buf.Bytes()))},
47 {name: "smallbuffer", reader: bufio.NewReaderSize(bytes.NewBuffer(buf.Bytes()), 0)},
48 {name: "largebuffer", reader: bufio.NewReaderSize(bytes.NewBuffer(buf.Bytes()), 1<<20)},
49 {name: "notbufio", reader: notBufioReader{bufio.NewReader(bytes.NewBuffer(buf.Bytes()))}},
50 } {
51 t.Run(tc.name, func(t *testing.T) {
52
53 var got []*test3.TestAllTypes
54 for {
55 m := &test3.TestAllTypes{}
56 err := protodelim.UnmarshalFrom(tc.reader, m)
57 if errors.Is(err, io.EOF) {
58 break
59 }
60 if err != nil {
61 t.Errorf("protodelim.UnmarshalFrom(_) = %v", err)
62 continue
63 }
64 got = append(got, m)
65 }
66
67 want := msgs
68 if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
69 t.Errorf("Unmarshaler collected messages: diff -want +got = %s", diff)
70 }
71 })
72 }
73 }
74
75
76 type notBufioReader struct {
77 *bufio.Reader
78 }
79
80 func BenchmarkUnmarshalFrom(b *testing.B) {
81 var manyInt32 []int32
82 for i := int32(0); i < 10000; i++ {
83 manyInt32 = append(manyInt32, i)
84 }
85 var msgs []*test3.TestAllTypes
86 for i := 0; i < 10; i++ {
87 msgs = append(msgs, &test3.TestAllTypes{RepeatedInt32: manyInt32})
88 }
89
90 buf := &bytes.Buffer{}
91
92
93 for _, m := range msgs {
94 if n, err := protodelim.MarshalTo(buf, m); err != nil {
95 b.Errorf("protodelim.MarshalTo(_, %v) = %d, %v", m, n, err)
96 }
97 }
98 bufBytes := buf.Bytes()
99
100 type resetReader interface {
101 protodelim.Reader
102 Reset(io.Reader)
103 }
104
105 for _, tc := range []struct {
106 name string
107 reader resetReader
108 }{
109 {name: "bufio1mib", reader: bufio.NewReaderSize(nil, 1<<20)},
110 {name: "bufio16mib", reader: bufio.NewReaderSize(nil, 1<<24)},
111 {name: "notbufio1mib", reader: notBufioReader{bufio.NewReaderSize(nil, 1<<20)}},
112 {name: "notbufio16mib", reader: notBufioReader{bufio.NewReaderSize(nil, 1<<24)}},
113 } {
114 b.Run(tc.name, func(b *testing.B) {
115 b.ReportAllocs()
116 b.ResetTimer()
117 for i := 0; i < b.N; i++ {
118 tc.reader.Reset(bytes.NewBuffer(bufBytes))
119 var got int
120 m := &test3.TestAllTypes{}
121 for {
122 err := protodelim.UnmarshalFrom(tc.reader, m)
123 if errors.Is(err, io.EOF) {
124 break
125 }
126 if err != nil {
127 b.Errorf("protodelim.UnmarshalFrom(_) = %v", err)
128 continue
129 }
130 got++
131 }
132 if got != len(msgs) {
133 b.Errorf("Got %v messages. Wanted %v", got, len(msgs))
134 }
135 }
136 })
137 }
138 }
139
140 func TestMaxSize(t *testing.T) {
141 in := &test3.TestAllTypes{SingularInt32: 1}
142
143 buf := &bytes.Buffer{}
144
145 if n, err := protodelim.MarshalTo(buf, in); err != nil {
146 t.Errorf("protodelim.MarshalTo(_, %v) = %d, %v", in, n, err)
147 }
148
149 out := &test3.TestAllTypes{}
150 err := protodelim.UnmarshalOptions{MaxSize: 1}.UnmarshalFrom(bufio.NewReader(buf), out)
151
152 var errSize *protodelim.SizeTooLargeError
153 if !errors.As(err, &errSize) {
154 t.Errorf("protodelim.UnmarshalOptions{MaxSize: 1}.UnmarshalFrom(_, _) = %v (%T), want %T", err, err, errSize)
155 }
156 got, want := errSize, &protodelim.SizeTooLargeError{Size: 3, MaxSize: 1}
157 if diff := cmp.Diff(want, got); diff != "" {
158 t.Errorf("protodelim.UnmarshalOptions{MaxSize: 1}.UnmarshalFrom(_, _): diff -want +got = %s", diff)
159 }
160 }
161
162 func TestUnmarshalFrom_UnexpectedEOF(t *testing.T) {
163 buf := &bytes.Buffer{}
164
165
166 sb := protowire.AppendVarint(nil, 42)
167 if _, err := buf.Write(sb); err != nil {
168 t.Fatalf("buf.Write(%v) = _, %v", sb, err)
169 }
170
171 out := &test3.TestAllTypes{}
172 err := protodelim.UnmarshalFrom(bufio.NewReader(buf), out)
173 if got, want := err, io.ErrUnexpectedEOF; got != want {
174 t.Errorf("protodelim.UnmarshalFrom(size-only buf, _) = %v, want %v", got, want)
175 }
176 }
177
178 func TestUnmarshalFrom_PrematureHeader(t *testing.T) {
179 var data = []byte{128}
180 err := protodelim.UnmarshalFrom(bytes.NewReader(data[:]), nil)
181 if got, want := err, io.ErrUnexpectedEOF; !errors.Is(got, want) {
182 t.Errorf("protodelim.UnmarshalFrom(%#v, nil) = %#v; want = %#v", data, got, want)
183 }
184 }
185
186 func TestUnmarshalFrom_InvalidVarint(t *testing.T) {
187 var data = bytes.Repeat([]byte{128}, 2*binary.MaxVarintLen64)
188 err := protodelim.UnmarshalFrom(bytes.NewReader(data[:]), nil)
189 if err == nil {
190 t.Errorf("protodelim.UnmarshalFrom unexpectedly did not error on invalid varint")
191 }
192 }
193
View as plain text