blob: 02f07d480d048aa6cc2630e8445cc37f1fff4cdb [file] [log] [blame]
Damien Neilba23aa52018-12-07 14:38:17 -08001// Copyright 2018 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 Neil4be2fb42018-12-17 11:16:16 -08005package proto_test
Damien Neilba23aa52018-12-07 14:38:17 -08006
7import (
8 "fmt"
9 "reflect"
10 "testing"
11
Damien Neil5c5b5312019-05-14 12:44:37 -070012 "google.golang.org/protobuf/encoding/prototext"
Damien Neile89e6242019-05-13 23:55:40 -070013 "google.golang.org/protobuf/internal/encoding/pack"
Damien Neile89e6242019-05-13 23:55:40 -070014 "google.golang.org/protobuf/proto"
Joe Tsaic51e2e02019-07-13 00:44:41 -070015 "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsai19058432019-02-27 21:46:29 -080016
Damien Neile89e6242019-05-13 23:55:40 -070017 testpb "google.golang.org/protobuf/internal/testprotos/test"
18 test3pb "google.golang.org/protobuf/internal/testprotos/test3"
Damien Neilba23aa52018-12-07 14:38:17 -080019)
20
Damien Neilba23aa52018-12-07 14:38:17 -080021func TestDecode(t *testing.T) {
Damien Neild0b07492019-12-16 12:59:13 -080022 for _, test := range testValidMessages {
23 if len(test.decodeTo) == 0 {
24 t.Errorf("%v: no test message types", test.desc)
25 }
Damien Neilba23aa52018-12-07 14:38:17 -080026 for _, want := range test.decodeTo {
27 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
Damien Neil96c229a2019-04-03 12:17:24 -070028 opts := proto.UnmarshalOptions{
29 AllowPartial: test.partial,
30 }
Damien Neilba23aa52018-12-07 14:38:17 -080031 wire := append(([]byte)(nil), test.wire...)
Damien Neil4be2fb42018-12-17 11:16:16 -080032 got := reflect.New(reflect.TypeOf(want).Elem()).Interface().(proto.Message)
Damien Neil96c229a2019-04-03 12:17:24 -070033 if err := opts.Unmarshal(wire, got); err != nil {
Damien Neil61e93c72019-03-27 09:23:20 -070034 t.Errorf("Unmarshal error: %v\nMessage:\n%v", err, marshalText(want))
Damien Neilba23aa52018-12-07 14:38:17 -080035 return
36 }
37
38 // Aliasing check: Modifying the original wire bytes shouldn't
39 // affect the unmarshaled message.
40 for i := range wire {
41 wire[i] = 0
42 }
Joe Tsai96a44732020-01-03 19:52:28 -080043 if !proto.Equal(got, want) && got.ProtoReflect().IsValid() && want.ProtoReflect().IsValid() {
Damien Neil61e93c72019-03-27 09:23:20 -070044 t.Errorf("Unmarshal returned unexpected result; got:\n%v\nwant:\n%v", marshalText(got), marshalText(want))
Damien Neilba23aa52018-12-07 14:38:17 -080045 }
46 })
47 }
48 }
49}
50
Damien Neil96c229a2019-04-03 12:17:24 -070051func TestDecodeRequiredFieldChecks(t *testing.T) {
Damien Neild0b07492019-12-16 12:59:13 -080052 for _, test := range testValidMessages {
Damien Neil96c229a2019-04-03 12:17:24 -070053 if !test.partial {
54 continue
55 }
Damien Neil96c229a2019-04-03 12:17:24 -070056 for _, m := range test.decodeTo {
57 t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
58 got := reflect.New(reflect.TypeOf(m).Elem()).Interface().(proto.Message)
59 if err := proto.Unmarshal(test.wire, got); err == nil {
60 t.Fatalf("Unmarshal succeeded (want error)\nMessage:\n%v", marshalText(got))
61 }
62 })
63 }
64 }
65}
66
Damien Neild0b07492019-12-16 12:59:13 -080067func TestDecodeInvalidMessages(t *testing.T) {
68 for _, test := range testInvalidMessages {
69 if len(test.decodeTo) == 0 {
70 t.Errorf("%v: no test message types", test.desc)
Damien Neilbc310b52019-04-11 11:46:55 -070071 }
Joe Tsaic51e2e02019-07-13 00:44:41 -070072 for _, want := range test.decodeTo {
73 t.Run(fmt.Sprintf("%s (%T)", test.desc, want), func(t *testing.T) {
Damien Neild0b07492019-12-16 12:59:13 -080074 opts := proto.UnmarshalOptions{
75 AllowPartial: test.partial,
76 }
77 got := want.ProtoReflect().New().Interface()
78 if err := opts.Unmarshal(test.wire, got); err == nil {
79 t.Errorf("Unmarshal unexpectedly succeeded\ninput bytes: [%x]\nMessage:\n%v", test.wire, marshalText(got))
Joe Tsaic51e2e02019-07-13 00:44:41 -070080 }
81 })
82 }
83 }
84}
85
Damien Neil8003f082019-08-02 15:13:00 -070086func TestDecodeZeroLengthBytes(t *testing.T) {
87 // Verify that proto3 bytes fields don't give the mistaken
88 // impression that they preserve presence.
89 wire := pack.Message{
90 pack.Tag{15, pack.BytesType}, pack.Bytes(nil),
91 }.Marshal()
92 m := &test3pb.TestAllTypes{}
93 if err := proto.Unmarshal(wire, m); err != nil {
94 t.Fatal(err)
95 }
96 if m.OptionalBytes != nil {
97 t.Errorf("unmarshal zero-length proto3 bytes field: got %v, want nil", m.OptionalBytes)
98 }
99}
100
Joe Tsai9b22b932019-08-08 19:23:32 -0700101func TestDecodeOneofNilWrapper(t *testing.T) {
102 wire := pack.Message{
103 pack.Tag{111, pack.VarintType}, pack.Varint(1111),
104 }.Marshal()
105 m := &testpb.TestAllTypes{OneofField: (*testpb.TestAllTypes_OneofUint32)(nil)}
106 if err := proto.Unmarshal(wire, m); err != nil {
107 t.Fatal(err)
108 }
109 if got := m.GetOneofUint32(); got != 1111 {
110 t.Errorf("GetOneofUint32() = %v, want %v", got, 1111)
111 }
112}
113
Damien Neil5366f822019-12-05 14:54:35 -0800114func TestDecodeEmptyBytes(t *testing.T) {
115 // There's really nothing wrong with a nil entry in a [][]byte,
116 // but we take care to produce non-nil []bytes for zero-length
117 // byte strings, so test for it.
118 m := &testpb.TestAllTypes{}
119 b := pack.Message{
120 pack.Tag{45, pack.BytesType}, pack.Bytes(nil),
121 }.Marshal()
122 if err := proto.Unmarshal(b, m); err != nil {
123 t.Fatal(err)
124 }
125 if m.RepeatedBytes[0] == nil {
126 t.Errorf("unmarshaling repeated bytes field containing zero-length value: Got nil bytes, want non-nil")
127 }
128}
129
Damien Neil4be2fb42018-12-17 11:16:16 -0800130func build(m proto.Message, opts ...buildOpt) proto.Message {
Damien Neilba23aa52018-12-07 14:38:17 -0800131 for _, opt := range opts {
132 opt(m)
133 }
134 return m
135}
136
Damien Neil4be2fb42018-12-17 11:16:16 -0800137type buildOpt func(proto.Message)
Damien Neilba23aa52018-12-07 14:38:17 -0800138
Joe Tsai74615a32019-07-14 18:51:46 -0700139func unknown(raw protoreflect.RawFields) buildOpt {
Damien Neil4be2fb42018-12-17 11:16:16 -0800140 return func(m proto.Message) {
Joe Tsai378c1322019-04-25 23:48:08 -0700141 m.ProtoReflect().SetUnknown(raw)
Damien Neile6f060f2019-04-23 17:11:02 -0700142 }
143}
144
Damien Neilf1e905b2019-08-08 15:45:59 -0700145func extend(desc protoreflect.ExtensionType, value interface{}) buildOpt {
Damien Neil4be2fb42018-12-17 11:16:16 -0800146 return func(m proto.Message) {
Damien Neil92f76182019-08-02 16:58:08 -0700147 proto.SetExtension(m, desc, value)
Damien Neilba23aa52018-12-07 14:38:17 -0800148 }
149}
Damien Neil61e93c72019-03-27 09:23:20 -0700150
151func marshalText(m proto.Message) string {
Joe Tsaif2c4ddc2019-09-19 21:28:52 -0700152 if m == nil {
153 return "<nil>\n"
154 }
Joe Tsaicd4a31e2019-09-14 19:14:24 -0700155 b, _ := prototext.MarshalOptions{
156 AllowPartial: true,
157 EmitUnknown: true,
158 Indent: "\t",
159 }.Marshal(m)
Damien Neil61e93c72019-03-27 09:23:20 -0700160 return string(b)
161}