blob: 040fddb759af2f7628273bd3c1a7bdcadfec9bbe [file] [log] [blame]
Damien Neil5ec58b92019-04-30 11:36:39 -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
5// Package prototest exercises protobuf reflection.
6package prototest
7
8import (
9 "bytes"
10 "fmt"
11 "math"
12 "sort"
13 "testing"
14
Damien Neild91246e2019-06-21 08:36:26 -070015 "google.golang.org/protobuf/encoding/prototext"
16 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neile89e6242019-05-13 23:55:40 -070017 "google.golang.org/protobuf/proto"
18 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neild91246e2019-06-21 08:36:26 -070019 preg "google.golang.org/protobuf/reflect/protoregistry"
Damien Neil5ec58b92019-04-30 11:36:39 -070020)
21
Joe Tsai378c1322019-04-25 23:48:08 -070022// TODO: Test invalid field descriptors or oneof descriptors.
23// TODO: This should test the functionality that can be provided by fast-paths.
Damien Neil5ec58b92019-04-30 11:36:39 -070024
Damien Neild91246e2019-06-21 08:36:26 -070025// MessageOptions configure message tests.
26type MessageOptions struct {
27 // ExtensionTypes is a list of types to test with.
28 //
29 // If nil, TestMessage will look for extension types in the global registry.
30 ExtensionTypes []pref.ExtensionType
Damien Neil290ceea2019-07-15 13:39:43 -070031
32 // Resolver is used for looking up types when unmarshaling extension fields.
33 // If nil, this defaults to using protoregistry.GlobalTypes.
34 Resolver interface {
35 preg.ExtensionTypeResolver
36 }
Damien Neild91246e2019-06-21 08:36:26 -070037}
38
Joe Tsai378c1322019-04-25 23:48:08 -070039// TestMessage runs the provided m through a series of tests
40// exercising the protobuf reflection API.
Damien Neild91246e2019-06-21 08:36:26 -070041func TestMessage(t testing.TB, m proto.Message, opts MessageOptions) {
Joe Tsai378c1322019-04-25 23:48:08 -070042 md := m.ProtoReflect().Descriptor()
43 m1 := m.ProtoReflect().New()
Damien Neil5ec58b92019-04-30 11:36:39 -070044 for i := 0; i < md.Fields().Len(); i++ {
45 fd := md.Fields().Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -070046 testField(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070047 }
Damien Neild91246e2019-06-21 08:36:26 -070048 if opts.ExtensionTypes == nil {
49 preg.GlobalTypes.RangeExtensionsByMessage(md.FullName(), func(e pref.ExtensionType) bool {
50 opts.ExtensionTypes = append(opts.ExtensionTypes, e)
51 return true
52 })
53 }
54 for _, xt := range opts.ExtensionTypes {
Damien Neil79bfdbe2019-08-28 11:08:22 -070055 testField(t, m1, xt.TypeDescriptor())
Damien Neild91246e2019-06-21 08:36:26 -070056 }
Damien Neil5ec58b92019-04-30 11:36:39 -070057 for i := 0; i < md.Oneofs().Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070058 testOneof(t, m1, md.Oneofs().Get(i))
Damien Neil5ec58b92019-04-30 11:36:39 -070059 }
Damien Neild91246e2019-06-21 08:36:26 -070060 testUnknown(t, m1)
Damien Neil5ec58b92019-04-30 11:36:39 -070061
62 // Test round-trip marshal/unmarshal.
Joe Tsai378c1322019-04-25 23:48:08 -070063 m2 := m.ProtoReflect().New().Interface()
64 populateMessage(m2.ProtoReflect(), 1, nil)
Damien Neil290ceea2019-07-15 13:39:43 -070065 for _, xt := range opts.ExtensionTypes {
66 m2.ProtoReflect().Set(xt.TypeDescriptor(), newValue(m2.ProtoReflect(), xt.TypeDescriptor(), 1, nil))
67 }
68 b, err := proto.MarshalOptions{
69 AllowPartial: true,
70 }.Marshal(m2)
Damien Neil5ec58b92019-04-30 11:36:39 -070071 if err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070072 t.Errorf("Marshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070073 }
Joe Tsai378c1322019-04-25 23:48:08 -070074 m3 := m.ProtoReflect().New().Interface()
Damien Neil290ceea2019-07-15 13:39:43 -070075 if err := (proto.UnmarshalOptions{
76 AllowPartial: true,
77 Resolver: opts.Resolver,
78 }.Unmarshal(b, m3)); err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070079 t.Errorf("Unmarshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070080 }
Joe Tsai378c1322019-04-25 23:48:08 -070081 if !proto.Equal(m2, m3) {
82 t.Errorf("round-trip marshal/unmarshal did not preserve message\nOriginal:\n%v\nNew:\n%v", marshalText(m2), marshalText(m3))
Damien Neil5ec58b92019-04-30 11:36:39 -070083 }
84}
85
86func marshalText(m proto.Message) string {
Damien Neil5c5b5312019-05-14 12:44:37 -070087 b, _ := prototext.MarshalOptions{Indent: " "}.Marshal(m)
Damien Neil5ec58b92019-04-30 11:36:39 -070088 return string(b)
89}
90
Joe Tsai378c1322019-04-25 23:48:08 -070091// testField exercises set/get/has/clear of a field.
Damien Neil5ec58b92019-04-30 11:36:39 -070092func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -070093 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -070094 num := fd.Number()
Damien Neil5ec58b92019-04-30 11:36:39 -070095
Damien Neild91246e2019-06-21 08:36:26 -070096 switch {
97 case fd.IsList():
98 testFieldList(t, m, fd)
99 case fd.IsMap():
100 testFieldMap(t, m, fd)
Damien Neilf5274512019-08-05 10:48:38 -0700101 case fd.Message() != nil:
102 default:
103 if got, want := m.NewField(fd), fd.Default(); !valueEqual(got, want) {
104 t.Errorf("Message.NewField(%v) = %v, want default value %v", name, formatValue(got), formatValue(want))
105 }
106 if fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind {
107 testFieldFloat(t, m, fd)
108 }
Damien Neild91246e2019-06-21 08:36:26 -0700109 }
110
Damien Neil5ec58b92019-04-30 11:36:39 -0700111 // Set to a non-zero value, the zero value, different non-zero values.
112 for _, n := range []seed{1, 0, minVal, maxVal} {
113 v := newValue(m, fd, n, nil)
Joe Tsai378c1322019-04-25 23:48:08 -0700114 m.Set(fd, v)
Damien Neil5ec58b92019-04-30 11:36:39 -0700115 wantHas := true
116 if n == 0 {
117 if fd.Syntax() == pref.Proto3 && fd.Message() == nil {
118 wantHas = false
119 }
Damien Neild91246e2019-06-21 08:36:26 -0700120 if fd.IsExtension() {
121 wantHas = true
122 }
Damien Neila0a54b82019-11-01 15:18:36 -0700123 if fd.Cardinality() == pref.Repeated {
124 wantHas = false
125 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700126 if fd.ContainingOneof() != nil {
Damien Neil5ec58b92019-04-30 11:36:39 -0700127 wantHas = true
128 }
129 }
Damien Neilf5274512019-08-05 10:48:38 -0700130 if fd.Syntax() == pref.Proto3 && fd.Cardinality() != pref.Repeated && fd.ContainingOneof() == nil && fd.Kind() == pref.EnumKind && v.Enum() == 0 {
131 wantHas = false
132 }
Joe Tsai378c1322019-04-25 23:48:08 -0700133 if got, want := m.Has(fd), wantHas; got != want {
134 t.Errorf("after setting %q to %v:\nMessage.Has(%v) = %v, want %v", name, formatValue(v), num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700135 }
Joe Tsai378c1322019-04-25 23:48:08 -0700136 if got, want := m.Get(fd), v; !valueEqual(got, want) {
137 t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700138 }
Damien Neild91246e2019-06-21 08:36:26 -0700139 found := false
140 m.Range(func(d pref.FieldDescriptor, got pref.Value) bool {
141 if fd != d {
142 return true
143 }
144 found = true
145 if want := v; !valueEqual(got, want) {
146 t.Errorf("after setting %q:\nMessage.Range got value %v, want %v", name, formatValue(got), formatValue(want))
147 }
148 return true
149 })
150 if got, want := wantHas, found; got != want {
151 t.Errorf("after setting %q:\nMessageRange saw field: %v, want %v", name, got, want)
152 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700153 }
154
Joe Tsai378c1322019-04-25 23:48:08 -0700155 m.Clear(fd)
156 if got, want := m.Has(fd), false; got != want {
157 t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700158 }
159 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700160 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700161 if got := m.Get(fd); got.List().Len() != 0 {
162 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700163 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700164 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700165 if got := m.Get(fd); got.Map().Len() != 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700166 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty map", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700167 }
Joe Tsai378c1322019-04-25 23:48:08 -0700168 case fd.Message() == nil:
169 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
170 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700171 }
172 }
Damien Neild91246e2019-06-21 08:36:26 -0700173
Damien Neil290ceea2019-07-15 13:39:43 -0700174 // Set to the default value.
175 switch {
176 case fd.IsList() || fd.IsMap():
Damien Neil9f1165c2019-11-26 13:31:38 -0800177 m.Set(fd, m.Mutable(fd))
Damien Neila0a54b82019-11-01 15:18:36 -0700178 if got, want := m.Has(fd), (fd.IsExtension() && fd.Cardinality() != pref.Repeated) || fd.ContainingOneof() != nil; got != want {
Damien Neil290ceea2019-07-15 13:39:43 -0700179 t.Errorf("after setting %q to default:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
180 }
181 case fd.Message() == nil:
182 m.Set(fd, m.Get(fd))
183 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
184 t.Errorf("after setting %q to default:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want))
185 }
186 }
187 m.Clear(fd)
188
Damien Neild91246e2019-06-21 08:36:26 -0700189 // Set to the wrong type.
Joe Tsai84177c92019-09-17 13:38:48 -0700190 v := pref.ValueOfString("")
Damien Neild91246e2019-06-21 08:36:26 -0700191 if fd.Kind() == pref.StringKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700192 v = pref.ValueOfInt32(0)
Damien Neild91246e2019-06-21 08:36:26 -0700193 }
194 if !panics(func() {
195 m.Set(fd, v)
196 }) {
197 t.Errorf("setting %v to %T succeeds, want panic", name, v.Interface())
198 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700199}
200
201// testFieldMap tests set/get/has/clear of entries in a map field.
202func testFieldMap(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700203 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700204 num := fd.Number()
205
Damien Neilf5274512019-08-05 10:48:38 -0700206 // New values.
Joe Tsai378c1322019-04-25 23:48:08 -0700207 m.Clear(fd) // start with an empty map
Damien Neilf5274512019-08-05 10:48:38 -0700208 mapv := m.Get(fd).Map()
Damien Neil9f1165c2019-11-26 13:31:38 -0800209 if mapv.IsValid() {
210 t.Errorf("after clearing field: message.Get(%v).IsValid() = true, want false", name)
211 }
Damien Neilf5274512019-08-05 10:48:38 -0700212 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
213 t.Errorf("message.Get(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
214 }
Damien Neil9f1165c2019-11-26 13:31:38 -0800215 if !panics(func() {
216 m.Set(fd, pref.ValueOfMap(mapv))
217 }) {
218 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
219 }
220 if !panics(func() {
221 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, nil))
222 }) {
223 t.Errorf("message.Get(%v).Set(...) of invalid map does not panic", name)
224 }
Damien Neilf5274512019-08-05 10:48:38 -0700225 mapv = m.Mutable(fd).Map() // mutable map
Damien Neil9f1165c2019-11-26 13:31:38 -0800226 if !mapv.IsValid() {
227 t.Errorf("message.Mutable(%v).IsValid() = false, want true", name)
228 }
Damien Neilf5274512019-08-05 10:48:38 -0700229 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
230 t.Errorf("message.Mutable(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
231 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700232
233 // Add values.
234 want := make(testMap)
235 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700236 if got, want := m.Has(fd), i > 0; got != want {
237 t.Errorf("after inserting %d elements to %q:\nMessage.Has(%v) = %v, want %v", i, name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700238 }
239
240 k := newMapKey(fd, n)
241 v := newMapValue(fd, mapv, n, nil)
242 mapv.Set(k, v)
243 want.Set(k, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700244 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700245 t.Errorf("after inserting %d elements to %q:\nMessage.Get(%v) = %v, want %v", i, name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700246 }
247 }
248
249 // Set values.
250 want.Range(func(k pref.MapKey, v pref.Value) bool {
251 nv := newMapValue(fd, mapv, 10, nil)
252 mapv.Set(k, nv)
253 want.Set(k, nv)
Joe Tsai84177c92019-09-17 13:38:48 -0700254 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700255 t.Errorf("after setting element %v of %q:\nMessage.Get(%v) = %v, want %v", formatValue(k.Value()), name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700256 }
257 return true
258 })
259
260 // Clear values.
261 want.Range(func(k pref.MapKey, v pref.Value) bool {
262 mapv.Clear(k)
263 want.Clear(k)
Joe Tsai378c1322019-04-25 23:48:08 -0700264 if got, want := m.Has(fd), want.Len() > 0; got != want {
265 t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700266 }
Joe Tsai84177c92019-09-17 13:38:48 -0700267 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700268 t.Errorf("after clearing elements of %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700269 }
270 return true
271 })
Damien Neil9f1165c2019-11-26 13:31:38 -0800272 if mapv := m.Get(fd).Map(); mapv.IsValid() {
273 t.Errorf("after clearing all elements: message.Get(%v).IsValid() = true, want false %v", name, formatValue(pref.ValueOfMap(mapv)))
274 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700275
276 // Non-existent map keys.
277 missingKey := newMapKey(fd, 1)
278 if got, want := mapv.Has(missingKey), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700279 t.Errorf("non-existent map key in %q: Map.Has(%v) = %v, want %v", name, formatValue(missingKey.Value()), got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700280 }
281 if got, want := mapv.Get(missingKey).IsValid(), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700282 t.Errorf("non-existent map key in %q: Map.Get(%v).IsValid() = %v, want %v", name, formatValue(missingKey.Value()), got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700283 }
284 mapv.Clear(missingKey) // noop
285}
286
287type testMap map[interface{}]pref.Value
288
289func (m testMap) Get(k pref.MapKey) pref.Value { return m[k.Interface()] }
290func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
291func (m testMap) Has(k pref.MapKey) bool { return m.Get(k).IsValid() }
292func (m testMap) Clear(k pref.MapKey) { delete(m, k.Interface()) }
293func (m testMap) Len() int { return len(m) }
Damien Neilf5274512019-08-05 10:48:38 -0700294func (m testMap) NewValue() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700295func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
296 for k, v := range m {
297 if !f(pref.ValueOf(k).MapKey(), v) {
298 return
299 }
300 }
301}
Damien Neil82886da2019-11-26 13:27:24 -0800302func (m testMap) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700303
304// testFieldList exercises set/get/append/truncate of values in a list.
305func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700306 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700307 num := fd.Number()
308
309 m.Clear(fd) // start with an empty list
Damien Neilf5274512019-08-05 10:48:38 -0700310 list := m.Get(fd).List()
Damien Neil9f1165c2019-11-26 13:31:38 -0800311 if list.IsValid() {
312 t.Errorf("message.Get(%v).IsValid() = true, want false", name)
313 }
314 if !panics(func() {
315 m.Set(fd, pref.ValueOfList(list))
316 }) {
317 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
318 }
319 if !panics(func() {
320 list.Append(newListElement(fd, list, 0, nil))
321 }) {
322 t.Errorf("message.Get(%v).Append(...) of invalid list does not panic", name)
323 }
Damien Neilf5274512019-08-05 10:48:38 -0700324 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
325 t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
326 }
327 list = m.Mutable(fd).List() // mutable list
Damien Neil9f1165c2019-11-26 13:31:38 -0800328 if !list.IsValid() {
329 t.Errorf("message.Get(%v).IsValid() = false, want true", name)
330 }
Damien Neilf5274512019-08-05 10:48:38 -0700331 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
332 t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
333 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700334
335 // Append values.
336 var want pref.List = &testList{}
337 for i, n := range []seed{1, 0, minVal, maxVal} {
Damien Neila0a54b82019-11-01 15:18:36 -0700338 if got, want := m.Has(fd), i > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700339 t.Errorf("after appending %d elements to %q:\nMessage.Has(%v) = %v, want %v", i, name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700340 }
341 v := newListElement(fd, list, n, nil)
342 want.Append(v)
343 list.Append(v)
344
Joe Tsai84177c92019-09-17 13:38:48 -0700345 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700346 t.Errorf("after appending %d elements to %q:\nMessage.Get(%v) = %v, want %v", i+1, name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700347 }
348 }
349
350 // Set values.
351 for i := 0; i < want.Len(); i++ {
352 v := newListElement(fd, list, seed(i+10), nil)
353 want.Set(i, v)
354 list.Set(i, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700355 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700356 t.Errorf("after setting element %d of %q:\nMessage.Get(%v) = %v, want %v", i, name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700357 }
358 }
359
360 // Truncate.
361 for want.Len() > 0 {
362 n := want.Len() - 1
363 want.Truncate(n)
364 list.Truncate(n)
Damien Neila0a54b82019-11-01 15:18:36 -0700365 if got, want := m.Has(fd), want.Len() > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700366 t.Errorf("after truncating %q to %d:\nMessage.Has(%v) = %v, want %v", name, n, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700367 }
Joe Tsai84177c92019-09-17 13:38:48 -0700368 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700369 t.Errorf("after truncating %q to %d:\nMessage.Get(%v) = %v, want %v", name, n, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700370 }
371 }
372}
373
374type testList struct {
375 a []pref.Value
376}
377
Damien Neil2eaed362019-09-05 10:08:32 -0700378func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
379func (l *testList) Get(n int) pref.Value { return l.a[n] }
380func (l *testList) Len() int { return len(l.a) }
381func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
382func (l *testList) Truncate(n int) { l.a = l.a[:n] }
383func (l *testList) NewElement() pref.Value { panic("unimplemented") }
Damien Neil82886da2019-11-26 13:27:24 -0800384func (l *testList) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700385
386// testFieldFloat exercises some interesting floating-point scalar field values.
387func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700388 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700389 num := fd.Number()
390
Damien Neil5ec58b92019-04-30 11:36:39 -0700391 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
392 var val pref.Value
393 if fd.Kind() == pref.FloatKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700394 val = pref.ValueOfFloat32(float32(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700395 } else {
Joe Tsai84177c92019-09-17 13:38:48 -0700396 val = pref.ValueOfFloat64(float64(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700397 }
Joe Tsai378c1322019-04-25 23:48:08 -0700398 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700399 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700400 if got, want := m.Has(fd), true; got != want {
401 t.Errorf("after setting %v to %v: Message.Has(%v) = %v, want %v", name, v, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700402 }
Joe Tsai378c1322019-04-25 23:48:08 -0700403 if got, want := m.Get(fd), val; !valueEqual(got, want) {
404 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700405 }
406 }
407}
408
409// testOneof tests the behavior of fields in a oneof.
410func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neila3456c92019-04-30 11:36:49 -0700411 for _, mutable := range []bool{false, true} {
412 for i := 0; i < od.Fields().Len(); i++ {
413 fda := od.Fields().Get(i)
414 if mutable {
415 // Set fields by requesting a mutable reference.
416 if !fda.IsMap() && !fda.IsList() && fda.Message() == nil {
417 continue
418 }
419 _ = m.Mutable(fda)
420 } else {
421 // Set fields explicitly.
422 m.Set(fda, newValue(m, fda, 1, nil))
423 }
424 if got, want := m.WhichOneof(od), fda; got != want {
425 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
426 }
427 for j := 0; j < od.Fields().Len(); j++ {
428 fdb := od.Fields().Get(j)
429 if got, want := m.Has(fdb), i == j; got != want {
430 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
431 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700432 }
433 }
434 }
435}
436
Damien Neild91246e2019-06-21 08:36:26 -0700437// testUnknown tests the behavior of unknown fields.
438func testUnknown(t testing.TB, m pref.Message) {
439 var b []byte
440 b = wire.AppendTag(b, 1000, wire.VarintType)
441 b = wire.AppendVarint(b, 1001)
442 m.SetUnknown(pref.RawFields(b))
443 if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) {
444 t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want)
445 }
446}
447
Damien Neil5ec58b92019-04-30 11:36:39 -0700448func formatValue(v pref.Value) string {
449 switch v := v.Interface().(type) {
450 case pref.List:
451 var buf bytes.Buffer
452 buf.WriteString("list[")
453 for i := 0; i < v.Len(); i++ {
454 if i > 0 {
455 buf.WriteString(" ")
456 }
457 buf.WriteString(formatValue(v.Get(i)))
458 }
459 buf.WriteString("]")
460 return buf.String()
461 case pref.Map:
462 var buf bytes.Buffer
463 buf.WriteString("map[")
464 var keys []pref.MapKey
465 v.Range(func(k pref.MapKey, v pref.Value) bool {
466 keys = append(keys, k)
467 return true
468 })
469 sort.Slice(keys, func(i, j int) bool {
470 return keys[i].String() < keys[j].String()
471 })
472 for i, k := range keys {
473 if i > 0 {
474 buf.WriteString(" ")
475 }
476 buf.WriteString(formatValue(k.Value()))
477 buf.WriteString(":")
478 buf.WriteString(formatValue(v.Get(k)))
479 }
480 buf.WriteString("]")
481 return buf.String()
482 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700483 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700484 if err != nil {
485 return fmt.Sprintf("<%v>", err)
486 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700487 return fmt.Sprintf("%v{%v}", v.Descriptor().FullName(), string(b))
Damien Neil5ec58b92019-04-30 11:36:39 -0700488 case string:
489 return fmt.Sprintf("%q", v)
490 default:
491 return fmt.Sprint(v)
492 }
493}
494
495func valueEqual(a, b pref.Value) bool {
496 ai, bi := a.Interface(), b.Interface()
497 switch ai.(type) {
498 case pref.Message:
499 return proto.Equal(
500 a.Message().Interface(),
501 b.Message().Interface(),
502 )
503 case pref.List:
504 lista, listb := a.List(), b.List()
505 if lista.Len() != listb.Len() {
506 return false
507 }
508 for i := 0; i < lista.Len(); i++ {
509 if !valueEqual(lista.Get(i), listb.Get(i)) {
510 return false
511 }
512 }
513 return true
514 case pref.Map:
515 mapa, mapb := a.Map(), b.Map()
516 if mapa.Len() != mapb.Len() {
517 return false
518 }
519 equal := true
520 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
521 if !valueEqual(v, mapb.Get(k)) {
522 equal = false
523 return false
524 }
525 return true
526 })
527 return equal
528 case []byte:
529 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700530 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700531 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700532 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
533 case float64:
534 // NaNs are equal, but must be the same NaN.
535 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700536 default:
537 return ai == bi
538 }
539}
540
541// A seed is used to vary the content of a value.
542//
543// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
544// is unpopulated.
545//
546// A seed of minVal or maxVal is the least or greatest value of the value type.
547type seed int
548
549const (
550 minVal seed = -1
551 maxVal seed = -2
552)
553
Damien Neilf5274512019-08-05 10:48:38 -0700554// newSeed creates new seed values from a base, for example to create seeds for the
555// elements in a list. If the input seed is minVal or maxVal, so is the output.
556func newSeed(n seed, adjust ...int) seed {
557 switch n {
558 case minVal, maxVal:
559 return n
560 }
561 for _, a := range adjust {
562 n = 10*n + seed(a)
563 }
564 return n
565}
566
Damien Neil5ec58b92019-04-30 11:36:39 -0700567// newValue returns a new value assignable to a field.
568//
569// The stack parameter is used to avoid infinite recursion when populating circular
570// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700571func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700572 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700573 case fd.IsList():
Joe Tsaiac31a352019-05-13 14:32:56 -0700574 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800575 return m.New().Mutable(fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700576 }
Damien Neil290ceea2019-07-15 13:39:43 -0700577 list := m.NewField(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700578 list.Append(newListElement(fd, list, 0, stack))
579 list.Append(newListElement(fd, list, minVal, stack))
580 list.Append(newListElement(fd, list, maxVal, stack))
581 list.Append(newListElement(fd, list, n, stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700582 return pref.ValueOfList(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700583 case fd.IsMap():
Damien Neil5ec58b92019-04-30 11:36:39 -0700584 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800585 return m.New().Mutable(fd)
Damien Neil5ec58b92019-04-30 11:36:39 -0700586 }
Damien Neil290ceea2019-07-15 13:39:43 -0700587 mapv := m.NewField(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700588 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
589 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
590 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
Damien Neilf5274512019-08-05 10:48:38 -0700591 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700592 return pref.ValueOfMap(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700593 case fd.Message() != nil:
Damien Neil290ceea2019-07-15 13:39:43 -0700594 //if n == 0 {
595 // return m.New().Get(fd)
596 //}
Damien Neilf5274512019-08-05 10:48:38 -0700597 return populateMessage(m.NewField(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700598 default:
599 return newScalarValue(fd, n)
600 }
601}
602
Joe Tsai0fc49f82019-05-01 12:29:25 -0700603func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700604 if fd.Message() == nil {
605 return newScalarValue(fd, n)
606 }
Damien Neilf5274512019-08-05 10:48:38 -0700607 return populateMessage(list.NewElement().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700608}
609
610func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700611 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700612 return newScalarValue(kd, n).MapKey()
613}
614
Joe Tsai0fc49f82019-05-01 12:29:25 -0700615func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700616 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700617 if vd.Message() == nil {
618 return newScalarValue(vd, n)
619 }
Damien Neilf5274512019-08-05 10:48:38 -0700620 return populateMessage(mapv.NewValue().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700621}
622
623func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
624 switch fd.Kind() {
625 case pref.BoolKind:
Joe Tsai84177c92019-09-17 13:38:48 -0700626 return pref.ValueOfBool(n != 0)
Damien Neil5ec58b92019-04-30 11:36:39 -0700627 case pref.EnumKind:
Damien Neilf5274512019-08-05 10:48:38 -0700628 vals := fd.Enum().Values()
629 var i int
630 switch n {
631 case minVal:
632 i = 0
633 case maxVal:
634 i = vals.Len() - 1
635 default:
636 i = int(n) % vals.Len()
637 }
Joe Tsai84177c92019-09-17 13:38:48 -0700638 return pref.ValueOfEnum(vals.Get(i).Number())
Damien Neil5ec58b92019-04-30 11:36:39 -0700639 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
640 switch n {
641 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700642 return pref.ValueOfInt32(math.MinInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700643 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700644 return pref.ValueOfInt32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700645 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700646 return pref.ValueOfInt32(int32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700647 }
648 case pref.Uint32Kind, pref.Fixed32Kind:
649 switch n {
650 case minVal:
651 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700652 return pref.ValueOfUint32(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700653 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700654 return pref.ValueOfUint32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700655 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700656 return pref.ValueOfUint32(uint32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700657 }
658 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
659 switch n {
660 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700661 return pref.ValueOfInt64(math.MinInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700662 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700663 return pref.ValueOfInt64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700664 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700665 return pref.ValueOfInt64(int64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700666 }
667 case pref.Uint64Kind, pref.Fixed64Kind:
668 switch n {
669 case minVal:
670 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700671 return pref.ValueOfUint64(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700672 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700673 return pref.ValueOfUint64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700674 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700675 return pref.ValueOfUint64(uint64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700676 }
677 case pref.FloatKind:
678 switch n {
679 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700680 return pref.ValueOfFloat32(math.SmallestNonzeroFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700681 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700682 return pref.ValueOfFloat32(math.MaxFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700683 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700684 return pref.ValueOfFloat32(1.5 * float32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700685 }
686 case pref.DoubleKind:
687 switch n {
688 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700689 return pref.ValueOfFloat64(math.SmallestNonzeroFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700690 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700691 return pref.ValueOfFloat64(math.MaxFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700692 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700693 return pref.ValueOfFloat64(1.5 * float64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700694 }
695 case pref.StringKind:
696 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700697 return pref.ValueOfString("")
Damien Neil5ec58b92019-04-30 11:36:39 -0700698 }
Joe Tsai84177c92019-09-17 13:38:48 -0700699 return pref.ValueOfString(fmt.Sprintf("%d", n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700700 case pref.BytesKind:
701 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700702 return pref.ValueOfBytes(nil)
Damien Neil5ec58b92019-04-30 11:36:39 -0700703 }
Joe Tsai84177c92019-09-17 13:38:48 -0700704 return pref.ValueOfBytes([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
Damien Neil5ec58b92019-04-30 11:36:39 -0700705 }
706 panic("unhandled kind")
707}
708
Joe Tsai0fc49f82019-05-01 12:29:25 -0700709func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700710 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700711 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700712 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700713 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700714 for _, x := range stack {
715 if md == x {
Joe Tsai84177c92019-09-17 13:38:48 -0700716 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700717 }
718 }
719 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700720 for i := 0; i < md.Fields().Len(); i++ {
721 fd := md.Fields().Get(i)
722 if fd.IsWeak() {
723 continue
724 }
Damien Neilf5274512019-08-05 10:48:38 -0700725 m.Set(fd, newValue(m, fd, newSeed(n, i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700726 }
Joe Tsai84177c92019-09-17 13:38:48 -0700727 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700728}
Damien Neild91246e2019-06-21 08:36:26 -0700729
730func panics(f func()) (didPanic bool) {
731 defer func() {
732 if err := recover(); err != nil {
733 didPanic = true
734 }
735 }()
736 f()
737 return false
738}