blob: 663612db9290c50dc8329be5401ab86fd302e19c [file] [log] [blame]
Damien Neilc37adef2019-04-01 13:49:56 -07001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Damien Neil99f24c32019-03-13 17:06:42 -07005package proto_test
6
7import (
8 "bytes"
9 "fmt"
Damien Neil99f24c32019-03-13 17:06:42 -070010 "testing"
11
Damien Neil99f24c32019-03-13 17:06:42 -070012 "github.com/google/go-cmp/cmp"
Joe Tsaic51e2e02019-07-13 00:44:41 -070013 "google.golang.org/protobuf/internal/flags"
Damien Neile89e6242019-05-13 23:55:40 -070014 "google.golang.org/protobuf/proto"
Damien Neil3016b732019-04-07 12:43:10 -070015
Joe Tsai9b22b932019-08-08 19:23:32 -070016 testpb "google.golang.org/protobuf/internal/testprotos/test"
Damien Neile89e6242019-05-13 23:55:40 -070017 test3pb "google.golang.org/protobuf/internal/testprotos/test3"
Damien Neil99f24c32019-03-13 17:06:42 -070018)
19
20func TestEncode(t *testing.T) {
21 for _, test := range testProtos {
22 for _, want := range test.decodeTo {
23 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
Damien Neil96c229a2019-04-03 12:17:24 -070024 opts := proto.MarshalOptions{
25 AllowPartial: test.partial,
26 }
27 wire, err := opts.Marshal(want)
Damien Neil99f24c32019-03-13 17:06:42 -070028 if err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070029 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, marshalText(want))
30 }
31
32 size := proto.Size(want)
33 if size != len(wire) {
34 t.Errorf("Size and marshal disagree: Size(m)=%v; len(Marshal(m))=%v\nMessage:\n%v", size, len(wire), marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070035 }
36
Joe Tsai378c1322019-04-25 23:48:08 -070037 got := want.ProtoReflect().New().Interface()
Damien Neil96c229a2019-04-03 12:17:24 -070038 uopts := proto.UnmarshalOptions{
39 AllowPartial: test.partial,
40 }
41 if err := uopts.Unmarshal(wire, got); err != nil {
Joe Tsai8d30bbe2019-05-16 15:53:25 -070042 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070043 return
44 }
Damien Neile6f060f2019-04-23 17:11:02 -070045 if !proto.Equal(got, want) {
Joe Tsai8d30bbe2019-05-16 15:53:25 -070046 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", marshalText(got), marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070047 }
48 })
49 }
50 }
51}
52
53func TestEncodeDeterministic(t *testing.T) {
54 for _, test := range testProtos {
55 for _, want := range test.decodeTo {
56 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
Damien Neil96c229a2019-04-03 12:17:24 -070057 opts := proto.MarshalOptions{
58 Deterministic: true,
59 AllowPartial: test.partial,
60 }
61 wire, err := opts.Marshal(want)
Damien Neil99f24c32019-03-13 17:06:42 -070062 if err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070063 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070064 }
Damien Neil96c229a2019-04-03 12:17:24 -070065 wire2, err := opts.Marshal(want)
Damien Neil99f24c32019-03-13 17:06:42 -070066 if err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070067 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070068 }
Damien Neil99f24c32019-03-13 17:06:42 -070069 if !bytes.Equal(wire, wire2) {
70 t.Fatalf("deterministic marshal returned varying results:\n%v", cmp.Diff(wire, wire2))
71 }
72
Joe Tsai378c1322019-04-25 23:48:08 -070073 got := want.ProtoReflect().New().Interface()
Damien Neil96c229a2019-04-03 12:17:24 -070074 uopts := proto.UnmarshalOptions{
75 AllowPartial: test.partial,
76 }
77 if err := uopts.Unmarshal(wire, got); err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070078 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070079 return
80 }
Damien Neile6f060f2019-04-23 17:11:02 -070081 if !proto.Equal(got, want) {
Damien Neil61e93c72019-03-27 09:23:20 -070082 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", marshalText(got), marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070083 }
84 })
85 }
86 }
87}
Damien Neil96c229a2019-04-03 12:17:24 -070088
Damien Neilbc310b52019-04-11 11:46:55 -070089func TestEncodeInvalidUTF8(t *testing.T) {
90 for _, test := range invalidUTF8TestProtos {
91 for _, want := range test.decodeTo {
92 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
Damien Neil8c86fc52019-06-19 09:28:29 -070093 _, err := proto.Marshal(want)
94 if err == nil {
Damien Neilbc310b52019-04-11 11:46:55 -070095 t.Errorf("Marshal did not return expected error for invalid UTF8: %v\nMessage:\n%v", err, marshalText(want))
96 }
Damien Neilbc310b52019-04-11 11:46:55 -070097 })
98 }
99 }
100}
101
Joe Tsaic51e2e02019-07-13 00:44:41 -0700102func TestEncodeNoEnforceUTF8(t *testing.T) {
103 for _, test := range noEnforceUTF8TestProtos {
104 for _, want := range test.decodeTo {
105 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
106 _, err := proto.Marshal(want)
107 switch {
Joe Tsai1799d112019-08-08 13:31:59 -0700108 case flags.ProtoLegacy && err != nil:
Joe Tsaic51e2e02019-07-13 00:44:41 -0700109 t.Errorf("Marshal returned unexpected error: %v\nMessage:\n%v", err, marshalText(want))
Joe Tsai1799d112019-08-08 13:31:59 -0700110 case !flags.ProtoLegacy && err == nil:
Joe Tsaic51e2e02019-07-13 00:44:41 -0700111 t.Errorf("Marshal did not return expected error for invalid UTF8: %v\nMessage:\n%v", err, marshalText(want))
112 }
113 })
114 }
115 }
116}
117
Damien Neil96c229a2019-04-03 12:17:24 -0700118func TestEncodeRequiredFieldChecks(t *testing.T) {
119 for _, test := range testProtos {
120 if !test.partial {
121 continue
122 }
123 for _, m := range test.decodeTo {
124 t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
125 _, err := proto.Marshal(m)
126 if err == nil {
127 t.Fatalf("Marshal succeeded (want error)\nMessage:\n%v", marshalText(m))
128 }
129 })
130 }
131 }
132}
Damien Neil3016b732019-04-07 12:43:10 -0700133
Joe Tsai9b22b932019-08-08 19:23:32 -0700134func TestEncodeAppend(t *testing.T) {
Damien Neil3016b732019-04-07 12:43:10 -0700135 want := []byte("prefix")
136 got := append([]byte(nil), want...)
137 got, err := proto.MarshalOptions{}.MarshalAppend(got, &test3pb.TestAllTypes{
138 OptionalString: "value",
139 })
140 if err != nil {
141 t.Fatal(err)
142 }
143 if !bytes.HasPrefix(got, want) {
144 t.Fatalf("MarshalAppend modified prefix: got %v, want prefix %v", got, want)
145 }
146}
Joe Tsai9b22b932019-08-08 19:23:32 -0700147
148func 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}
Damien Neil1e5516a2019-09-27 14:31:10 -0700158
159func TestMarshalAppendAllocations(t *testing.T) {
160 m := &test3pb.TestAllTypes{OptionalInt32: 1}
161 size := proto.Size(m)
162 const count = 1000
163 b := make([]byte, size)
164 // AllocsPerRun returns an integral value.
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}