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