xref: /aosp_15_r20/external/golang-protobuf/proto/encode_test.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage proto_test
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"bytes"
9*1c12ee1eSDan Willemsen	"fmt"
10*1c12ee1eSDan Willemsen	"math"
11*1c12ee1eSDan Willemsen	"reflect"
12*1c12ee1eSDan Willemsen	"testing"
13*1c12ee1eSDan Willemsen
14*1c12ee1eSDan Willemsen	"github.com/google/go-cmp/cmp"
15*1c12ee1eSDan Willemsen
16*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/encoding/prototext"
17*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/encoding/protowire"
18*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/proto"
19*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
20*1c12ee1eSDan Willemsen
21*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/errors"
22*1c12ee1eSDan Willemsen	orderpb "google.golang.org/protobuf/internal/testprotos/order"
23*1c12ee1eSDan Willemsen	testpb "google.golang.org/protobuf/internal/testprotos/test"
24*1c12ee1eSDan Willemsen	test3pb "google.golang.org/protobuf/internal/testprotos/test3"
25*1c12ee1eSDan Willemsen)
26*1c12ee1eSDan Willemsen
27*1c12ee1eSDan Willemsenfunc TestEncode(t *testing.T) {
28*1c12ee1eSDan Willemsen	for _, test := range testValidMessages {
29*1c12ee1eSDan Willemsen		for _, want := range test.decodeTo {
30*1c12ee1eSDan Willemsen			t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
31*1c12ee1eSDan Willemsen				opts := proto.MarshalOptions{
32*1c12ee1eSDan Willemsen					AllowPartial: test.partial,
33*1c12ee1eSDan Willemsen				}
34*1c12ee1eSDan Willemsen				wire, err := opts.Marshal(want)
35*1c12ee1eSDan Willemsen				if err != nil {
36*1c12ee1eSDan Willemsen					t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want))
37*1c12ee1eSDan Willemsen				}
38*1c12ee1eSDan Willemsen
39*1c12ee1eSDan Willemsen				size := proto.Size(want)
40*1c12ee1eSDan Willemsen				if size != len(wire) {
41*1c12ee1eSDan Willemsen					t.Errorf("Size and marshal disagree: Size(m)=%v; len(Marshal(m))=%v\nMessage:\n%v", size, len(wire), prototext.Format(want))
42*1c12ee1eSDan Willemsen				}
43*1c12ee1eSDan Willemsen
44*1c12ee1eSDan Willemsen				got := want.ProtoReflect().New().Interface()
45*1c12ee1eSDan Willemsen				uopts := proto.UnmarshalOptions{
46*1c12ee1eSDan Willemsen					AllowPartial: test.partial,
47*1c12ee1eSDan Willemsen				}
48*1c12ee1eSDan Willemsen				if err := uopts.Unmarshal(wire, got); err != nil {
49*1c12ee1eSDan Willemsen					t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want))
50*1c12ee1eSDan Willemsen					return
51*1c12ee1eSDan Willemsen				}
52*1c12ee1eSDan Willemsen				if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() {
53*1c12ee1eSDan Willemsen					t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want))
54*1c12ee1eSDan Willemsen				}
55*1c12ee1eSDan Willemsen			})
56*1c12ee1eSDan Willemsen		}
57*1c12ee1eSDan Willemsen	}
58*1c12ee1eSDan Willemsen}
59*1c12ee1eSDan Willemsen
60*1c12ee1eSDan Willemsenfunc TestEncodeDeterministic(t *testing.T) {
61*1c12ee1eSDan Willemsen	for _, test := range testValidMessages {
62*1c12ee1eSDan Willemsen		for _, want := range test.decodeTo {
63*1c12ee1eSDan Willemsen			t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
64*1c12ee1eSDan Willemsen				opts := proto.MarshalOptions{
65*1c12ee1eSDan Willemsen					Deterministic: true,
66*1c12ee1eSDan Willemsen					AllowPartial:  test.partial,
67*1c12ee1eSDan Willemsen				}
68*1c12ee1eSDan Willemsen				wire, err := opts.Marshal(want)
69*1c12ee1eSDan Willemsen				if err != nil {
70*1c12ee1eSDan Willemsen					t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want))
71*1c12ee1eSDan Willemsen				}
72*1c12ee1eSDan Willemsen				wire2, err := opts.Marshal(want)
73*1c12ee1eSDan Willemsen				if err != nil {
74*1c12ee1eSDan Willemsen					t.Fatalf("Marshal error: %v\nMessage:\n%v", err, prototext.Format(want))
75*1c12ee1eSDan Willemsen				}
76*1c12ee1eSDan Willemsen				if !bytes.Equal(wire, wire2) {
77*1c12ee1eSDan Willemsen					t.Fatalf("deterministic marshal returned varying results:\n%v", cmp.Diff(wire, wire2))
78*1c12ee1eSDan Willemsen				}
79*1c12ee1eSDan Willemsen
80*1c12ee1eSDan Willemsen				got := want.ProtoReflect().New().Interface()
81*1c12ee1eSDan Willemsen				uopts := proto.UnmarshalOptions{
82*1c12ee1eSDan Willemsen					AllowPartial: test.partial,
83*1c12ee1eSDan Willemsen				}
84*1c12ee1eSDan Willemsen				if err := uopts.Unmarshal(wire, got); err != nil {
85*1c12ee1eSDan Willemsen					t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, prototext.Format(want))
86*1c12ee1eSDan Willemsen					return
87*1c12ee1eSDan Willemsen				}
88*1c12ee1eSDan Willemsen				if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() {
89*1c12ee1eSDan Willemsen					t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", prototext.Format(got), prototext.Format(want))
90*1c12ee1eSDan Willemsen				}
91*1c12ee1eSDan Willemsen			})
92*1c12ee1eSDan Willemsen		}
93*1c12ee1eSDan Willemsen	}
94*1c12ee1eSDan Willemsen}
95*1c12ee1eSDan Willemsen
96*1c12ee1eSDan Willemsenfunc TestEncodeRequiredFieldChecks(t *testing.T) {
97*1c12ee1eSDan Willemsen	for _, test := range testValidMessages {
98*1c12ee1eSDan Willemsen		if !test.partial {
99*1c12ee1eSDan Willemsen			continue
100*1c12ee1eSDan Willemsen		}
101*1c12ee1eSDan Willemsen		for _, m := range test.decodeTo {
102*1c12ee1eSDan Willemsen			t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
103*1c12ee1eSDan Willemsen				_, err := proto.Marshal(m)
104*1c12ee1eSDan Willemsen				if err == nil {
105*1c12ee1eSDan Willemsen					t.Fatalf("Marshal succeeded (want error)\nMessage:\n%v", prototext.Format(m))
106*1c12ee1eSDan Willemsen				}
107*1c12ee1eSDan Willemsen			})
108*1c12ee1eSDan Willemsen		}
109*1c12ee1eSDan Willemsen	}
110*1c12ee1eSDan Willemsen}
111*1c12ee1eSDan Willemsen
112*1c12ee1eSDan Willemsenfunc TestEncodeAppend(t *testing.T) {
113*1c12ee1eSDan Willemsen	want := []byte("prefix")
114*1c12ee1eSDan Willemsen	got := append([]byte(nil), want...)
115*1c12ee1eSDan Willemsen	got, err := proto.MarshalOptions{}.MarshalAppend(got, &test3pb.TestAllTypes{
116*1c12ee1eSDan Willemsen		SingularString: "value",
117*1c12ee1eSDan Willemsen	})
118*1c12ee1eSDan Willemsen	if err != nil {
119*1c12ee1eSDan Willemsen		t.Fatal(err)
120*1c12ee1eSDan Willemsen	}
121*1c12ee1eSDan Willemsen	if !bytes.HasPrefix(got, want) {
122*1c12ee1eSDan Willemsen		t.Fatalf("MarshalAppend modified prefix: got %v, want prefix %v", got, want)
123*1c12ee1eSDan Willemsen	}
124*1c12ee1eSDan Willemsen}
125*1c12ee1eSDan Willemsen
126*1c12ee1eSDan Willemsenfunc TestEncodeInvalidMessages(t *testing.T) {
127*1c12ee1eSDan Willemsen	for _, test := range testInvalidMessages {
128*1c12ee1eSDan Willemsen		for _, m := range test.decodeTo {
129*1c12ee1eSDan Willemsen			if !m.ProtoReflect().IsValid() {
130*1c12ee1eSDan Willemsen				continue
131*1c12ee1eSDan Willemsen			}
132*1c12ee1eSDan Willemsen			t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
133*1c12ee1eSDan Willemsen				opts := proto.MarshalOptions{
134*1c12ee1eSDan Willemsen					AllowPartial: test.partial,
135*1c12ee1eSDan Willemsen				}
136*1c12ee1eSDan Willemsen				got, err := opts.Marshal(m)
137*1c12ee1eSDan Willemsen				if err == nil {
138*1c12ee1eSDan Willemsen					t.Fatalf("Marshal unexpectedly succeeded\noutput bytes: [%x]\nMessage:\n%v", got, prototext.Format(m))
139*1c12ee1eSDan Willemsen				}
140*1c12ee1eSDan Willemsen				if !errors.Is(err, proto.Error) {
141*1c12ee1eSDan Willemsen					t.Fatalf("Marshal error is not a proto.Error: %v", err)
142*1c12ee1eSDan Willemsen				}
143*1c12ee1eSDan Willemsen			})
144*1c12ee1eSDan Willemsen		}
145*1c12ee1eSDan Willemsen	}
146*1c12ee1eSDan Willemsen}
147*1c12ee1eSDan Willemsen
148*1c12ee1eSDan Willemsenfunc TestEncodeOneofNilWrapper(t *testing.T) {
149*1c12ee1eSDan Willemsen	m := &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofUint32)(nil)}
150*1c12ee1eSDan Willemsen	b, err := proto.Marshal(m)
151*1c12ee1eSDan Willemsen	if err != nil {
152*1c12ee1eSDan Willemsen		t.Fatal(err)
153*1c12ee1eSDan Willemsen	}
154*1c12ee1eSDan Willemsen	if len(b) > 0 {
155*1c12ee1eSDan Willemsen		t.Errorf("Marshal return non-empty, want empty")
156*1c12ee1eSDan Willemsen	}
157*1c12ee1eSDan Willemsen}
158*1c12ee1eSDan Willemsen
159*1c12ee1eSDan Willemsenfunc TestMarshalAppendAllocations(t *testing.T) {
160*1c12ee1eSDan Willemsen	m := &test3pb.TestAllTypes{SingularInt32: 1}
161*1c12ee1eSDan Willemsen	size := proto.Size(m)
162*1c12ee1eSDan Willemsen	const count = 1000
163*1c12ee1eSDan Willemsen	b := make([]byte, size)
164*1c12ee1eSDan Willemsen	// AllocsPerRun returns an integral value.
165*1c12ee1eSDan Willemsen	marshalAllocs := testing.AllocsPerRun(count, func() {
166*1c12ee1eSDan Willemsen		_, err := proto.MarshalOptions{}.MarshalAppend(b[:0], m)
167*1c12ee1eSDan Willemsen		if err != nil {
168*1c12ee1eSDan Willemsen			t.Fatal(err)
169*1c12ee1eSDan Willemsen		}
170*1c12ee1eSDan Willemsen	})
171*1c12ee1eSDan Willemsen	b = nil
172*1c12ee1eSDan Willemsen	marshalAppendAllocs := testing.AllocsPerRun(count, func() {
173*1c12ee1eSDan Willemsen		var err error
174*1c12ee1eSDan Willemsen		b, err = proto.MarshalOptions{}.MarshalAppend(b, m)
175*1c12ee1eSDan Willemsen		if err != nil {
176*1c12ee1eSDan Willemsen			t.Fatal(err)
177*1c12ee1eSDan Willemsen		}
178*1c12ee1eSDan Willemsen	})
179*1c12ee1eSDan Willemsen	if marshalAllocs != marshalAppendAllocs {
180*1c12ee1eSDan Willemsen		t.Errorf("%v allocs/op when writing to a preallocated buffer", marshalAllocs)
181*1c12ee1eSDan Willemsen		t.Errorf("%v allocs/op when repeatedly appending to a slice", marshalAppendAllocs)
182*1c12ee1eSDan Willemsen		t.Errorf("expect amortized allocs/op to be identical")
183*1c12ee1eSDan Willemsen	}
184*1c12ee1eSDan Willemsen}
185*1c12ee1eSDan Willemsen
186*1c12ee1eSDan Willemsenfunc TestEncodeOrder(t *testing.T) {
187*1c12ee1eSDan Willemsen	// We make no guarantees about the stability of wire marshal output.
188*1c12ee1eSDan Willemsen	// The order in which fields are marshaled may change over time.
189*1c12ee1eSDan Willemsen	// If deterministic marshaling is not enabled, it may change over
190*1c12ee1eSDan Willemsen	// successive calls to proto.Marshal in the same binary.
191*1c12ee1eSDan Willemsen	//
192*1c12ee1eSDan Willemsen	// Unfortunately, many users have come to rely on the specific current
193*1c12ee1eSDan Willemsen	// wire marshal output. Perhaps someday we will choose to deliberately
194*1c12ee1eSDan Willemsen	// change the marshal output; until that day comes, this test verifies
195*1c12ee1eSDan Willemsen	// that we don't unintentionally change it.
196*1c12ee1eSDan Willemsen	m := &orderpb.Message{
197*1c12ee1eSDan Willemsen		Field_1:  proto.String("one"),
198*1c12ee1eSDan Willemsen		Field_2:  proto.String("two"),
199*1c12ee1eSDan Willemsen		Field_20: proto.String("twenty"),
200*1c12ee1eSDan Willemsen		Oneof_1:  &orderpb.Message_Field_10{"ten"},
201*1c12ee1eSDan Willemsen	}
202*1c12ee1eSDan Willemsen	proto.SetExtension(m, orderpb.E_Field_30, "thirty")
203*1c12ee1eSDan Willemsen	proto.SetExtension(m, orderpb.E_Field_31, "thirty-one")
204*1c12ee1eSDan Willemsen	proto.SetExtension(m, orderpb.E_Field_32, "thirty-two")
205*1c12ee1eSDan Willemsen	want := []protoreflect.FieldNumber{
206*1c12ee1eSDan Willemsen		30, 31, 32, // extensions first, in number order
207*1c12ee1eSDan Willemsen		1, 2, 20, // non-extension, non-oneof in number order
208*1c12ee1eSDan Willemsen		10, // oneofs last, undefined order
209*1c12ee1eSDan Willemsen	}
210*1c12ee1eSDan Willemsen
211*1c12ee1eSDan Willemsen	// Test with deterministic serialization, since fields are not sorted without
212*1c12ee1eSDan Willemsen	// it when -tags=protoreflect.
213*1c12ee1eSDan Willemsen	b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
214*1c12ee1eSDan Willemsen	if err != nil {
215*1c12ee1eSDan Willemsen		t.Fatal(err)
216*1c12ee1eSDan Willemsen	}
217*1c12ee1eSDan Willemsen	var got []protoreflect.FieldNumber
218*1c12ee1eSDan Willemsen	for len(b) > 0 {
219*1c12ee1eSDan Willemsen		num, _, n := protowire.ConsumeField(b)
220*1c12ee1eSDan Willemsen		if n < 0 {
221*1c12ee1eSDan Willemsen			t.Fatal(protowire.ParseError(n))
222*1c12ee1eSDan Willemsen		}
223*1c12ee1eSDan Willemsen		b = b[n:]
224*1c12ee1eSDan Willemsen		got = append(got, num)
225*1c12ee1eSDan Willemsen	}
226*1c12ee1eSDan Willemsen	if !reflect.DeepEqual(got, want) {
227*1c12ee1eSDan Willemsen		t.Errorf("unexpected field marshal order:\ngot:  %v\nwant: %v\nmessage:\n%v", got, want, m)
228*1c12ee1eSDan Willemsen	}
229*1c12ee1eSDan Willemsen}
230*1c12ee1eSDan Willemsen
231*1c12ee1eSDan Willemsenfunc TestEncodeLarge(t *testing.T) {
232*1c12ee1eSDan Willemsen	// Encode/decode a message large enough to overflow a 32-bit size cache.
233*1c12ee1eSDan Willemsen	t.Skip("too slow and memory-hungry to run all the time")
234*1c12ee1eSDan Willemsen	size := int64(math.MaxUint32 + 1)
235*1c12ee1eSDan Willemsen	m := &testpb.TestAllTypes_NestedMessage{
236*1c12ee1eSDan Willemsen		Corecursive: &testpb.TestAllTypes{
237*1c12ee1eSDan Willemsen			OptionalBytes: make([]byte, size),
238*1c12ee1eSDan Willemsen		},
239*1c12ee1eSDan Willemsen	}
240*1c12ee1eSDan Willemsen	b, err := proto.Marshal(m)
241*1c12ee1eSDan Willemsen	if err != nil {
242*1c12ee1eSDan Willemsen		t.Fatalf("Marshal: %v", err)
243*1c12ee1eSDan Willemsen	}
244*1c12ee1eSDan Willemsen	if got, want := len(b), proto.Size(m); got != want {
245*1c12ee1eSDan Willemsen		t.Fatalf("Size(m) = %v, but len(Marshal(m)) = %v", got, want)
246*1c12ee1eSDan Willemsen	}
247*1c12ee1eSDan Willemsen	if err := proto.Unmarshal(b, m); err != nil {
248*1c12ee1eSDan Willemsen		t.Fatalf("Unmarshal: %v", err)
249*1c12ee1eSDan Willemsen	}
250*1c12ee1eSDan Willemsen	if got, want := int64(len(m.Corecursive.OptionalBytes)), size; got != want {
251*1c12ee1eSDan Willemsen		t.Errorf("after round-trip marshal, got len(m.OptionalBytes) = %v, want %v", got, want)
252*1c12ee1eSDan Willemsen	}
253*1c12ee1eSDan Willemsen}
254*1c12ee1eSDan Willemsen
255*1c12ee1eSDan Willemsen// TestEncodeEmpty tests for boundary conditions when producing an empty output.
256*1c12ee1eSDan Willemsen// These tests are not necessarily a statement of proper behavior,
257*1c12ee1eSDan Willemsen// but exist to detect accidental changes in behavior.
258*1c12ee1eSDan Willemsenfunc TestEncodeEmpty(t *testing.T) {
259*1c12ee1eSDan Willemsen	for _, m := range []proto.Message{nil, (*testpb.TestAllTypes)(nil), &testpb.TestAllTypes{}} {
260*1c12ee1eSDan Willemsen		isValid := m != nil && m.ProtoReflect().IsValid()
261*1c12ee1eSDan Willemsen
262*1c12ee1eSDan Willemsen		b, err := proto.Marshal(m)
263*1c12ee1eSDan Willemsen		if err != nil {
264*1c12ee1eSDan Willemsen			t.Errorf("proto.Marshal() = %v", err)
265*1c12ee1eSDan Willemsen		}
266*1c12ee1eSDan Willemsen		if isNil := b == nil; isNil == isValid {
267*1c12ee1eSDan Willemsen			t.Errorf("proto.Marshal() == nil: %v, want %v", isNil, !isValid)
268*1c12ee1eSDan Willemsen		}
269*1c12ee1eSDan Willemsen
270*1c12ee1eSDan Willemsen		b, err = proto.MarshalOptions{}.Marshal(m)
271*1c12ee1eSDan Willemsen		if err != nil {
272*1c12ee1eSDan Willemsen			t.Errorf("proto.MarshalOptions{}.Marshal() = %v", err)
273*1c12ee1eSDan Willemsen		}
274*1c12ee1eSDan Willemsen		if isNil := b == nil; isNil == isValid {
275*1c12ee1eSDan Willemsen			t.Errorf("proto.MarshalOptions{}.Marshal() = %v, want %v", isNil, !isValid)
276*1c12ee1eSDan Willemsen		}
277*1c12ee1eSDan Willemsen	}
278*1c12ee1eSDan Willemsen}
279