blob: 3f015b755e5ee3efa9e81b6d23ae0ac28fdf33c8 [file] [log] [blame]
Damien Neil99f24c32019-03-13 17:06:42 -07001package proto_test
2
3import (
4 "bytes"
5 "fmt"
6 "reflect"
7 "testing"
8
9 protoV1 "github.com/golang/protobuf/proto"
Damien Neil99f24c32019-03-13 17:06:42 -070010 "github.com/google/go-cmp/cmp"
Damien Neile89e6242019-05-13 23:55:40 -070011 "google.golang.org/protobuf/proto"
12 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neil3016b732019-04-07 12:43:10 -070013
Damien Neile89e6242019-05-13 23:55:40 -070014 test3pb "google.golang.org/protobuf/internal/testprotos/test3"
Damien Neil99f24c32019-03-13 17:06:42 -070015)
16
17func TestEncode(t *testing.T) {
18 for _, test := range testProtos {
19 for _, want := range test.decodeTo {
20 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
Damien Neil96c229a2019-04-03 12:17:24 -070021 opts := proto.MarshalOptions{
22 AllowPartial: test.partial,
23 }
24 wire, err := opts.Marshal(want)
Damien Neil99f24c32019-03-13 17:06:42 -070025 if err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070026 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, marshalText(want))
27 }
28
29 size := proto.Size(want)
30 if size != len(wire) {
31 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 -070032 }
33
Damien Neile6f060f2019-04-23 17:11:02 -070034 got := newMessage(want)
Damien Neil96c229a2019-04-03 12:17:24 -070035 uopts := proto.UnmarshalOptions{
36 AllowPartial: test.partial,
37 }
38 if err := uopts.Unmarshal(wire, got); err != nil {
Damien Neil99f24c32019-03-13 17:06:42 -070039 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, protoV1.MarshalTextString(want.(protoV1.Message)))
40 return
41 }
42
Damien Neil96c229a2019-04-03 12:17:24 -070043 if test.invalidExtensions {
44 // Equal doesn't work on messages containing invalid extension data.
45 return
46 }
Damien Neile6f060f2019-04-23 17:11:02 -070047 if !proto.Equal(got, want) {
Damien Neil99f24c32019-03-13 17:06:42 -070048 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", protoV1.MarshalTextString(got.(protoV1.Message)), protoV1.MarshalTextString(want.(protoV1.Message)))
49 }
50 })
51 }
52 }
53}
54
55func TestEncodeDeterministic(t *testing.T) {
56 for _, test := range testProtos {
57 for _, want := range test.decodeTo {
58 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
Damien Neil96c229a2019-04-03 12:17:24 -070059 opts := proto.MarshalOptions{
60 Deterministic: true,
61 AllowPartial: test.partial,
62 }
63 wire, err := opts.Marshal(want)
Damien Neil99f24c32019-03-13 17:06:42 -070064 if err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070065 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070066 }
Damien Neil96c229a2019-04-03 12:17:24 -070067 wire2, err := opts.Marshal(want)
Damien Neil99f24c32019-03-13 17:06:42 -070068 if err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070069 t.Fatalf("Marshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070070 }
Damien Neil99f24c32019-03-13 17:06:42 -070071 if !bytes.Equal(wire, wire2) {
72 t.Fatalf("deterministic marshal returned varying results:\n%v", cmp.Diff(wire, wire2))
73 }
74
Damien Neile6f060f2019-04-23 17:11:02 -070075 got := newMessage(want)
Damien Neil96c229a2019-04-03 12:17:24 -070076 uopts := proto.UnmarshalOptions{
77 AllowPartial: test.partial,
78 }
79 if err := uopts.Unmarshal(wire, got); err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070080 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070081 return
82 }
83
Damien Neil96c229a2019-04-03 12:17:24 -070084 if test.invalidExtensions {
85 // Equal doesn't work on messages containing invalid extension data.
86 return
87 }
Damien Neile6f060f2019-04-23 17:11:02 -070088 if !proto.Equal(got, want) {
Damien Neil61e93c72019-03-27 09:23:20 -070089 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", marshalText(got), marshalText(want))
Damien Neil99f24c32019-03-13 17:06:42 -070090 }
91 })
92 }
93 }
94}
Damien Neil96c229a2019-04-03 12:17:24 -070095
Damien Neilbc310b52019-04-11 11:46:55 -070096func TestEncodeInvalidUTF8(t *testing.T) {
97 for _, test := range invalidUTF8TestProtos {
98 for _, want := range test.decodeTo {
99 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
100 wire, err := proto.Marshal(want)
101 if !isErrInvalidUTF8(err) {
102 t.Errorf("Marshal did not return expected error for invalid UTF8: %v\nMessage:\n%v", err, marshalText(want))
103 }
Damien Neile6f060f2019-04-23 17:11:02 -0700104 got := newMessage(want)
Damien Neilbc310b52019-04-11 11:46:55 -0700105 if err := proto.Unmarshal(wire, got); !isErrInvalidUTF8(err) {
106 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, marshalText(want))
107 return
108 }
Damien Neile6f060f2019-04-23 17:11:02 -0700109 if !proto.Equal(got, want) {
Damien Neilbc310b52019-04-11 11:46:55 -0700110 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", marshalText(got), marshalText(want))
111 }
112 })
113 }
114 }
115}
116
Damien Neil96c229a2019-04-03 12:17:24 -0700117func TestEncodeRequiredFieldChecks(t *testing.T) {
118 for _, test := range testProtos {
119 if !test.partial {
120 continue
121 }
122 for _, m := range test.decodeTo {
123 t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
124 _, err := proto.Marshal(m)
125 if err == nil {
126 t.Fatalf("Marshal succeeded (want error)\nMessage:\n%v", marshalText(m))
127 }
128 })
129 }
130 }
131}
Damien Neil3016b732019-04-07 12:43:10 -0700132
133func TestMarshalAppend(t *testing.T) {
134 want := []byte("prefix")
135 got := append([]byte(nil), want...)
136 got, err := proto.MarshalOptions{}.MarshalAppend(got, &test3pb.TestAllTypes{
137 OptionalString: "value",
138 })
139 if err != nil {
140 t.Fatal(err)
141 }
142 if !bytes.HasPrefix(got, want) {
143 t.Fatalf("MarshalAppend modified prefix: got %v, want prefix %v", got, want)
144 }
145}
Damien Neile6f060f2019-04-23 17:11:02 -0700146
147// newMessage returns a new message with the same type and extension fields as m.
148func newMessage(m proto.Message) proto.Message {
149 n := reflect.New(reflect.TypeOf(m).Elem()).Interface().(proto.Message)
150 m.ProtoReflect().KnownFields().ExtensionTypes().Range(func(xt pref.ExtensionType) bool {
151 n.ProtoReflect().KnownFields().ExtensionTypes().Register(xt)
152 return true
153 })
154 return n
155}