1
2
3
4
5 package proto_test
6
7 import (
8 "bytes"
9 "fmt"
10 "math"
11 "reflect"
12 "testing"
13
14 "github.com/google/go-cmp/cmp"
15
16 "google.golang.org/protobuf/encoding/prototext"
17 "google.golang.org/protobuf/encoding/protowire"
18 "google.golang.org/protobuf/proto"
19 "google.golang.org/protobuf/reflect/protoreflect"
20 "google.golang.org/protobuf/types/known/durationpb"
21
22 "google.golang.org/protobuf/internal/errors"
23 orderpb "google.golang.org/protobuf/internal/testprotos/order"
24 testpb "google.golang.org/protobuf/internal/testprotos/test"
25 test3pb "google.golang.org/protobuf/internal/testprotos/test3"
26 )
27
28 func TestEncode(t *testing.T) {
29 for _, test := range testValidMessages {
30 for _, want := range test.decodeTo {
31 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
32 opts := proto.MarshalOptions{
33 AllowPartial: test.partial,
34 }
35 wire, err := opts.Marshal(want)
36 if err != nil {
37 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want))
38 }
39
40 size := proto.Size(want)
41 if size != len(wire) {
42 t.Errorf("Size and marshal disagree: Size(m)=%v; len(Marshal(m))=%v\nMessage:\n%v", size, len(wire), prototext.Format(want))
43 }
44
45 got := want.ProtoReflect().New().Interface()
46 uopts := proto.UnmarshalOptions{
47 AllowPartial: test.partial,
48 }
49 if err := uopts.Unmarshal(wire, got); err != nil {
50 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want))
51 return
52 }
53 if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() {
54 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want))
55 }
56 })
57 }
58 }
59 }
60
61 func TestEncodeDeterministic(t *testing.T) {
62 for _, test := range testValidMessages {
63 for _, want := range test.decodeTo {
64 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
65 opts := proto.MarshalOptions{
66 Deterministic: true,
67 AllowPartial: test.partial,
68 }
69 wire, err := opts.Marshal(want)
70 if err != nil {
71 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want))
72 }
73 wire2, err := opts.Marshal(want)
74 if err != nil {
75 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want))
76 }
77 if !bytes.Equal(wire, wire2) {
78 t.Fatalf("deterministic marshal returned varying results:\n%v", cmp.Diff(wire, wire2))
79 }
80
81 got := want.ProtoReflect().New().Interface()
82 uopts := proto.UnmarshalOptions{
83 AllowPartial: test.partial,
84 }
85 if err := uopts.Unmarshal(wire, got); err != nil {
86 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want))
87 return
88 }
89 if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() {
90 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want))
91 }
92 })
93 }
94 }
95 }
96
97 func TestEncodeRequiredFieldChecks(t *testing.T) {
98 for _, test := range testValidMessages {
99 if !test.partial {
100 continue
101 }
102 for _, m := range test.decodeTo {
103 t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
104 _, err := proto.Marshal(m)
105 if err == nil {
106 t.Fatalf("Marshal succeeded (want error)\nMessage:\n%v", prototext.Format(m))
107 }
108 })
109 }
110 }
111 }
112
113 func TestEncodeAppend(t *testing.T) {
114 want := []byte("prefix")
115 got := append([]byte(nil), want...)
116 got, err := proto.MarshalOptions{}.MarshalAppend(got, &test3pb.TestAllTypes{
117 SingularString: "value",
118 })
119 if err != nil {
120 t.Fatal(err)
121 }
122 if !bytes.HasPrefix(got, want) {
123 t.Fatalf("MarshalAppend modified prefix: got %v, want prefix %v", got, want)
124 }
125 }
126
127 func TestEncodeInvalidMessages(t *testing.T) {
128 for _, test := range testInvalidMessages {
129 for _, m := range test.decodeTo {
130 if !m.ProtoReflect().IsValid() {
131 continue
132 }
133 t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
134 opts := proto.MarshalOptions{
135 AllowPartial: test.partial,
136 }
137 got, err := opts.Marshal(m)
138 if err == nil {
139 t.Fatalf("Marshal unexpectedly succeeded\noutput bytes: [%x]\nMessage:\n%v", got, prototext.Format(m))
140 }
141 if !errors.Is(err, proto.Error) {
142 t.Fatalf("Marshal error is not a proto.Error: %v", err)
143 }
144 })
145 }
146 }
147 }
148
149 func TestEncodeOneofNilWrapper(t *testing.T) {
150 m := &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofUint32)(nil)}
151 b, err := proto.Marshal(m)
152 if err != nil {
153 t.Fatal(err)
154 }
155 if len(b) > 0 {
156 t.Errorf("Marshal return non-empty, want empty")
157 }
158 }
159
160 func TestMarshalAppendAllocations(t *testing.T) {
161
162
163
164 m := &test3pb.TestAllTypes{SingularInt32: 1}
165 size := proto.Size(m)
166 const count = 1000
167 b := make([]byte, size)
168
169 marshalAllocs := testing.AllocsPerRun(count, func() {
170 _, err := proto.MarshalOptions{}.MarshalAppend(b[:0], m)
171 if err != nil {
172 t.Fatal(err)
173 }
174 })
175 b = nil
176 marshalAppendAllocs := testing.AllocsPerRun(count, func() {
177 var err error
178 b, err = proto.MarshalOptions{}.MarshalAppend(b, m)
179 if err != nil {
180 t.Fatal(err)
181 }
182 })
183 if marshalAllocs != marshalAppendAllocs {
184 t.Errorf("%v allocs/op when writing to a preallocated buffer", marshalAllocs)
185 t.Errorf("%v allocs/op when repeatedly appending to a slice", marshalAppendAllocs)
186 t.Errorf("expect amortized allocs/op to be identical")
187 }
188 }
189
190 func TestEncodeOrder(t *testing.T) {
191
192
193
194
195
196
197
198
199
200 m := &orderpb.Message{
201 Field_1: proto.String("one"),
202 Field_2: proto.String("two"),
203 Field_20: proto.String("twenty"),
204 Oneof_1: &orderpb.Message_Field_10{"ten"},
205 }
206 proto.SetExtension(m, orderpb.E_Field_30, "thirty")
207 proto.SetExtension(m, orderpb.E_Field_31, "thirty-one")
208 proto.SetExtension(m, orderpb.E_Field_32, "thirty-two")
209 want := []protoreflect.FieldNumber{
210 30, 31, 32,
211 1, 2, 20,
212 10,
213 }
214
215
216
217 b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
218 if err != nil {
219 t.Fatal(err)
220 }
221 var got []protoreflect.FieldNumber
222 for len(b) > 0 {
223 num, _, n := protowire.ConsumeField(b)
224 if n < 0 {
225 t.Fatal(protowire.ParseError(n))
226 }
227 b = b[n:]
228 got = append(got, num)
229 }
230 if !reflect.DeepEqual(got, want) {
231 t.Errorf("unexpected field marshal order:\ngot: %v\nwant: %v\nmessage:\n%v", got, want, m)
232 }
233 }
234
235 func TestEncodeLarge(t *testing.T) {
236
237 t.Skip("too slow and memory-hungry to run all the time")
238 size := int64(math.MaxUint32 + 1)
239 m := &testpb.TestAllTypes_NestedMessage{
240 Corecursive: &testpb.TestAllTypes{
241 OptionalBytes: make([]byte, size),
242 },
243 }
244 b, err := proto.Marshal(m)
245 if err != nil {
246 t.Fatalf("Marshal: %v", err)
247 }
248 if got, want := len(b), proto.Size(m); got != want {
249 t.Fatalf("Size(m) = %v, but len(Marshal(m)) = %v", got, want)
250 }
251 if err := proto.Unmarshal(b, m); err != nil {
252 t.Fatalf("Unmarshal: %v", err)
253 }
254 if got, want := int64(len(m.Corecursive.OptionalBytes)), size; got != want {
255 t.Errorf("after round-trip marshal, got len(m.OptionalBytes) = %v, want %v", got, want)
256 }
257 }
258
259
260
261
262 func TestEncodeEmpty(t *testing.T) {
263 for _, m := range []proto.Message{nil, (*testpb.TestAllTypes)(nil), &testpb.TestAllTypes{}} {
264 t.Run(fmt.Sprintf("%T", m), func(t *testing.T) {
265 isValid := m != nil && m.ProtoReflect().IsValid()
266
267 b, err := proto.Marshal(m)
268 if err != nil {
269 t.Errorf("proto.Marshal() = %v", err)
270 }
271 if isNil := b == nil; isNil == isValid {
272 t.Errorf("proto.Marshal() == nil: %v, want %v", isNil, !isValid)
273 }
274
275 b, err = proto.MarshalOptions{}.Marshal(m)
276 if err != nil {
277 t.Errorf("proto.MarshalOptions{}.Marshal() = %v", err)
278 }
279 if isNil := b == nil; isNil == isValid {
280 t.Errorf("proto.MarshalOptions{}.Marshal() = %v, want %v", isNil, !isValid)
281 }
282 })
283 }
284 }
285
286
287
288
289
290
291
292
293 func ExampleMarshal() {
294 b, err := proto.Marshal(&durationpb.Duration{
295 Nanos: 125,
296 })
297 if err != nil {
298 panic(err)
299 }
300
301 fmt.Printf("125ns encoded into %d bytes of Protobuf wire format:\n% x\n", len(b), b)
302
303
304
305
306
307
308
309
310
311 }
312
313
314
315
316
317
318
319
320
321
322 func ExampleMarshalOptions_MarshalAppend_sameBuffer() {
323 var m proto.Message
324
325 opts := proto.MarshalOptions{
326
327 }
328
329 var buf []byte
330 for i := 0; i < 100000; i++ {
331 var err error
332 buf, err = opts.MarshalAppend(buf[:0], m)
333 if err != nil {
334 panic(err)
335 }
336
337
338
339 }
340 }
341
View as plain text