blob: cabe0b09e9ef4354b770781e5a01b0d539c9a460 [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"
Joe Tsaib7695fa2020-01-04 09:09:04 -080012 "reflect"
Damien Neil5ec58b92019-04-30 11:36:39 -070013 "sort"
14 "testing"
15
Damien Neild91246e2019-06-21 08:36:26 -070016 "google.golang.org/protobuf/encoding/prototext"
17 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neile89e6242019-05-13 23:55:40 -070018 "google.golang.org/protobuf/proto"
19 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neild91246e2019-06-21 08:36:26 -070020 preg "google.golang.org/protobuf/reflect/protoregistry"
Damien Neil5ec58b92019-04-30 11:36:39 -070021)
22
Joe Tsai378c1322019-04-25 23:48:08 -070023// TODO: Test invalid field descriptors or oneof descriptors.
24// TODO: This should test the functionality that can be provided by fast-paths.
Damien Neil5ec58b92019-04-30 11:36:39 -070025
Damien Neild91246e2019-06-21 08:36:26 -070026// MessageOptions configure message tests.
27type MessageOptions struct {
28 // ExtensionTypes is a list of types to test with.
29 //
30 // If nil, TestMessage will look for extension types in the global registry.
31 ExtensionTypes []pref.ExtensionType
Damien Neil290ceea2019-07-15 13:39:43 -070032
33 // Resolver is used for looking up types when unmarshaling extension fields.
34 // If nil, this defaults to using protoregistry.GlobalTypes.
35 Resolver interface {
36 preg.ExtensionTypeResolver
37 }
Damien Neild91246e2019-06-21 08:36:26 -070038}
39
Joe Tsai378c1322019-04-25 23:48:08 -070040// TestMessage runs the provided m through a series of tests
41// exercising the protobuf reflection API.
Damien Neild91246e2019-06-21 08:36:26 -070042func TestMessage(t testing.TB, m proto.Message, opts MessageOptions) {
Joe Tsaib7695fa2020-01-04 09:09:04 -080043 testType(t, m)
44
Joe Tsai378c1322019-04-25 23:48:08 -070045 md := m.ProtoReflect().Descriptor()
46 m1 := m.ProtoReflect().New()
Damien Neil5ec58b92019-04-30 11:36:39 -070047 for i := 0; i < md.Fields().Len(); i++ {
48 fd := md.Fields().Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -070049 testField(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070050 }
Damien Neild91246e2019-06-21 08:36:26 -070051 if opts.ExtensionTypes == nil {
52 preg.GlobalTypes.RangeExtensionsByMessage(md.FullName(), func(e pref.ExtensionType) bool {
53 opts.ExtensionTypes = append(opts.ExtensionTypes, e)
54 return true
55 })
56 }
57 for _, xt := range opts.ExtensionTypes {
Damien Neil79bfdbe2019-08-28 11:08:22 -070058 testField(t, m1, xt.TypeDescriptor())
Damien Neild91246e2019-06-21 08:36:26 -070059 }
Damien Neil5ec58b92019-04-30 11:36:39 -070060 for i := 0; i < md.Oneofs().Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070061 testOneof(t, m1, md.Oneofs().Get(i))
Damien Neil5ec58b92019-04-30 11:36:39 -070062 }
Damien Neild91246e2019-06-21 08:36:26 -070063 testUnknown(t, m1)
Damien Neil5ec58b92019-04-30 11:36:39 -070064
65 // Test round-trip marshal/unmarshal.
Joe Tsai378c1322019-04-25 23:48:08 -070066 m2 := m.ProtoReflect().New().Interface()
67 populateMessage(m2.ProtoReflect(), 1, nil)
Damien Neil290ceea2019-07-15 13:39:43 -070068 for _, xt := range opts.ExtensionTypes {
69 m2.ProtoReflect().Set(xt.TypeDescriptor(), newValue(m2.ProtoReflect(), xt.TypeDescriptor(), 1, nil))
70 }
71 b, err := proto.MarshalOptions{
72 AllowPartial: true,
73 }.Marshal(m2)
Damien Neil5ec58b92019-04-30 11:36:39 -070074 if err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070075 t.Errorf("Marshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070076 }
Joe Tsai378c1322019-04-25 23:48:08 -070077 m3 := m.ProtoReflect().New().Interface()
Damien Neil290ceea2019-07-15 13:39:43 -070078 if err := (proto.UnmarshalOptions{
79 AllowPartial: true,
80 Resolver: opts.Resolver,
81 }.Unmarshal(b, m3)); err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070082 t.Errorf("Unmarshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070083 }
Joe Tsai378c1322019-04-25 23:48:08 -070084 if !proto.Equal(m2, m3) {
85 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 -070086 }
87}
88
89func marshalText(m proto.Message) string {
Damien Neil5c5b5312019-05-14 12:44:37 -070090 b, _ := prototext.MarshalOptions{Indent: " "}.Marshal(m)
Damien Neil5ec58b92019-04-30 11:36:39 -070091 return string(b)
92}
93
Joe Tsaib7695fa2020-01-04 09:09:04 -080094func testType(t testing.TB, m proto.Message) {
95 want := reflect.TypeOf(m)
96 if got := reflect.TypeOf(m.ProtoReflect().Interface()); got != want {
97 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Interface()): %v != %v", got, want)
98 }
99 if got := reflect.TypeOf(m.ProtoReflect().New().Interface()); got != want {
100 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().New().Interface()): %v != %v", got, want)
101 }
102 if got := reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()); got != want {
103 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()): %v != %v", got, want)
104 }
105}
106
Joe Tsai378c1322019-04-25 23:48:08 -0700107// testField exercises set/get/has/clear of a field.
Damien Neil5ec58b92019-04-30 11:36:39 -0700108func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700109 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700110 num := fd.Number()
Damien Neil5ec58b92019-04-30 11:36:39 -0700111
Damien Neild91246e2019-06-21 08:36:26 -0700112 switch {
113 case fd.IsList():
114 testFieldList(t, m, fd)
115 case fd.IsMap():
116 testFieldMap(t, m, fd)
Damien Neilf5274512019-08-05 10:48:38 -0700117 case fd.Message() != nil:
118 default:
119 if got, want := m.NewField(fd), fd.Default(); !valueEqual(got, want) {
120 t.Errorf("Message.NewField(%v) = %v, want default value %v", name, formatValue(got), formatValue(want))
121 }
122 if fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind {
123 testFieldFloat(t, m, fd)
124 }
Damien Neild91246e2019-06-21 08:36:26 -0700125 }
126
Damien Neil5ec58b92019-04-30 11:36:39 -0700127 // Set to a non-zero value, the zero value, different non-zero values.
128 for _, n := range []seed{1, 0, minVal, maxVal} {
129 v := newValue(m, fd, n, nil)
Joe Tsai378c1322019-04-25 23:48:08 -0700130 m.Set(fd, v)
Damien Neil5ec58b92019-04-30 11:36:39 -0700131 wantHas := true
132 if n == 0 {
133 if fd.Syntax() == pref.Proto3 && fd.Message() == nil {
134 wantHas = false
135 }
Damien Neild91246e2019-06-21 08:36:26 -0700136 if fd.IsExtension() {
137 wantHas = true
138 }
Damien Neila0a54b82019-11-01 15:18:36 -0700139 if fd.Cardinality() == pref.Repeated {
140 wantHas = false
141 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700142 if fd.ContainingOneof() != nil {
Damien Neil5ec58b92019-04-30 11:36:39 -0700143 wantHas = true
144 }
145 }
Damien Neilf5274512019-08-05 10:48:38 -0700146 if fd.Syntax() == pref.Proto3 && fd.Cardinality() != pref.Repeated && fd.ContainingOneof() == nil && fd.Kind() == pref.EnumKind && v.Enum() == 0 {
147 wantHas = false
148 }
Joe Tsai378c1322019-04-25 23:48:08 -0700149 if got, want := m.Has(fd), wantHas; got != want {
150 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 -0700151 }
Joe Tsai378c1322019-04-25 23:48:08 -0700152 if got, want := m.Get(fd), v; !valueEqual(got, want) {
153 t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700154 }
Damien Neild91246e2019-06-21 08:36:26 -0700155 found := false
156 m.Range(func(d pref.FieldDescriptor, got pref.Value) bool {
157 if fd != d {
158 return true
159 }
160 found = true
161 if want := v; !valueEqual(got, want) {
162 t.Errorf("after setting %q:\nMessage.Range got value %v, want %v", name, formatValue(got), formatValue(want))
163 }
164 return true
165 })
166 if got, want := wantHas, found; got != want {
167 t.Errorf("after setting %q:\nMessageRange saw field: %v, want %v", name, got, want)
168 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700169 }
170
Joe Tsai378c1322019-04-25 23:48:08 -0700171 m.Clear(fd)
172 if got, want := m.Has(fd), false; got != want {
173 t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700174 }
175 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700176 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700177 if got := m.Get(fd); got.List().Len() != 0 {
178 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700179 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700180 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700181 if got := m.Get(fd); got.Map().Len() != 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700182 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty map", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700183 }
Joe Tsai378c1322019-04-25 23:48:08 -0700184 case fd.Message() == nil:
185 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
186 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 -0700187 }
188 }
Damien Neild91246e2019-06-21 08:36:26 -0700189
Damien Neil290ceea2019-07-15 13:39:43 -0700190 // Set to the default value.
191 switch {
192 case fd.IsList() || fd.IsMap():
Damien Neil9f1165c2019-11-26 13:31:38 -0800193 m.Set(fd, m.Mutable(fd))
Damien Neila0a54b82019-11-01 15:18:36 -0700194 if got, want := m.Has(fd), (fd.IsExtension() && fd.Cardinality() != pref.Repeated) || fd.ContainingOneof() != nil; got != want {
Damien Neil290ceea2019-07-15 13:39:43 -0700195 t.Errorf("after setting %q to default:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
196 }
197 case fd.Message() == nil:
198 m.Set(fd, m.Get(fd))
199 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
200 t.Errorf("after setting %q to default:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want))
201 }
202 }
203 m.Clear(fd)
204
Damien Neild91246e2019-06-21 08:36:26 -0700205 // Set to the wrong type.
Joe Tsai84177c92019-09-17 13:38:48 -0700206 v := pref.ValueOfString("")
Damien Neild91246e2019-06-21 08:36:26 -0700207 if fd.Kind() == pref.StringKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700208 v = pref.ValueOfInt32(0)
Damien Neild91246e2019-06-21 08:36:26 -0700209 }
210 if !panics(func() {
211 m.Set(fd, v)
212 }) {
213 t.Errorf("setting %v to %T succeeds, want panic", name, v.Interface())
214 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700215}
216
217// testFieldMap tests set/get/has/clear of entries in a map field.
218func testFieldMap(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700219 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700220 num := fd.Number()
221
Damien Neilf5274512019-08-05 10:48:38 -0700222 // New values.
Joe Tsai378c1322019-04-25 23:48:08 -0700223 m.Clear(fd) // start with an empty map
Damien Neilf5274512019-08-05 10:48:38 -0700224 mapv := m.Get(fd).Map()
Damien Neil9f1165c2019-11-26 13:31:38 -0800225 if mapv.IsValid() {
226 t.Errorf("after clearing field: message.Get(%v).IsValid() = true, want false", name)
227 }
Damien Neilf5274512019-08-05 10:48:38 -0700228 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
229 t.Errorf("message.Get(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
230 }
Damien Neil9f1165c2019-11-26 13:31:38 -0800231 if !panics(func() {
232 m.Set(fd, pref.ValueOfMap(mapv))
233 }) {
234 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
235 }
236 if !panics(func() {
237 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, nil))
238 }) {
239 t.Errorf("message.Get(%v).Set(...) of invalid map does not panic", name)
240 }
Damien Neilf5274512019-08-05 10:48:38 -0700241 mapv = m.Mutable(fd).Map() // mutable map
Damien Neil9f1165c2019-11-26 13:31:38 -0800242 if !mapv.IsValid() {
243 t.Errorf("message.Mutable(%v).IsValid() = false, want true", name)
244 }
Damien Neilf5274512019-08-05 10:48:38 -0700245 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
246 t.Errorf("message.Mutable(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
247 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700248
249 // Add values.
250 want := make(testMap)
251 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700252 if got, want := m.Has(fd), i > 0; got != want {
253 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 -0700254 }
255
256 k := newMapKey(fd, n)
257 v := newMapValue(fd, mapv, n, nil)
258 mapv.Set(k, v)
259 want.Set(k, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700260 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700261 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 -0700262 }
263 }
264
265 // Set values.
266 want.Range(func(k pref.MapKey, v pref.Value) bool {
267 nv := newMapValue(fd, mapv, 10, nil)
268 mapv.Set(k, nv)
269 want.Set(k, nv)
Joe Tsai84177c92019-09-17 13:38:48 -0700270 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700271 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 -0700272 }
273 return true
274 })
275
276 // Clear values.
277 want.Range(func(k pref.MapKey, v pref.Value) bool {
278 mapv.Clear(k)
279 want.Clear(k)
Joe Tsai378c1322019-04-25 23:48:08 -0700280 if got, want := m.Has(fd), want.Len() > 0; got != want {
281 t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700282 }
Joe Tsai84177c92019-09-17 13:38:48 -0700283 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700284 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 -0700285 }
286 return true
287 })
Damien Neil9f1165c2019-11-26 13:31:38 -0800288 if mapv := m.Get(fd).Map(); mapv.IsValid() {
289 t.Errorf("after clearing all elements: message.Get(%v).IsValid() = true, want false %v", name, formatValue(pref.ValueOfMap(mapv)))
290 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700291
292 // Non-existent map keys.
293 missingKey := newMapKey(fd, 1)
294 if got, want := mapv.Has(missingKey), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700295 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 -0700296 }
297 if got, want := mapv.Get(missingKey).IsValid(), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700298 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 -0700299 }
300 mapv.Clear(missingKey) // noop
301}
302
303type testMap map[interface{}]pref.Value
304
305func (m testMap) Get(k pref.MapKey) pref.Value { return m[k.Interface()] }
306func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
307func (m testMap) Has(k pref.MapKey) bool { return m.Get(k).IsValid() }
308func (m testMap) Clear(k pref.MapKey) { delete(m, k.Interface()) }
309func (m testMap) Len() int { return len(m) }
Damien Neilf5274512019-08-05 10:48:38 -0700310func (m testMap) NewValue() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700311func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
312 for k, v := range m {
313 if !f(pref.ValueOf(k).MapKey(), v) {
314 return
315 }
316 }
317}
Damien Neil82886da2019-11-26 13:27:24 -0800318func (m testMap) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700319
320// testFieldList exercises set/get/append/truncate of values in a list.
321func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700322 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700323 num := fd.Number()
324
325 m.Clear(fd) // start with an empty list
Damien Neilf5274512019-08-05 10:48:38 -0700326 list := m.Get(fd).List()
Damien Neil9f1165c2019-11-26 13:31:38 -0800327 if list.IsValid() {
328 t.Errorf("message.Get(%v).IsValid() = true, want false", name)
329 }
330 if !panics(func() {
331 m.Set(fd, pref.ValueOfList(list))
332 }) {
333 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
334 }
335 if !panics(func() {
336 list.Append(newListElement(fd, list, 0, nil))
337 }) {
338 t.Errorf("message.Get(%v).Append(...) of invalid list does not panic", name)
339 }
Damien Neilf5274512019-08-05 10:48:38 -0700340 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
341 t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
342 }
343 list = m.Mutable(fd).List() // mutable list
Damien Neil9f1165c2019-11-26 13:31:38 -0800344 if !list.IsValid() {
345 t.Errorf("message.Get(%v).IsValid() = false, want true", name)
346 }
Damien Neilf5274512019-08-05 10:48:38 -0700347 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
348 t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
349 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700350
351 // Append values.
352 var want pref.List = &testList{}
353 for i, n := range []seed{1, 0, minVal, maxVal} {
Damien Neila0a54b82019-11-01 15:18:36 -0700354 if got, want := m.Has(fd), i > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700355 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 -0700356 }
357 v := newListElement(fd, list, n, nil)
358 want.Append(v)
359 list.Append(v)
360
Joe Tsai84177c92019-09-17 13:38:48 -0700361 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700362 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 -0700363 }
364 }
365
366 // Set values.
367 for i := 0; i < want.Len(); i++ {
368 v := newListElement(fd, list, seed(i+10), nil)
369 want.Set(i, v)
370 list.Set(i, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700371 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700372 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 -0700373 }
374 }
375
376 // Truncate.
377 for want.Len() > 0 {
378 n := want.Len() - 1
379 want.Truncate(n)
380 list.Truncate(n)
Damien Neila0a54b82019-11-01 15:18:36 -0700381 if got, want := m.Has(fd), want.Len() > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700382 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 -0700383 }
Joe Tsai84177c92019-09-17 13:38:48 -0700384 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700385 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 -0700386 }
387 }
388}
389
390type testList struct {
391 a []pref.Value
392}
393
Damien Neil2eaed362019-09-05 10:08:32 -0700394func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
395func (l *testList) Get(n int) pref.Value { return l.a[n] }
396func (l *testList) Len() int { return len(l.a) }
397func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
398func (l *testList) Truncate(n int) { l.a = l.a[:n] }
399func (l *testList) NewElement() pref.Value { panic("unimplemented") }
Damien Neil82886da2019-11-26 13:27:24 -0800400func (l *testList) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700401
402// testFieldFloat exercises some interesting floating-point scalar field values.
403func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700404 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700405 num := fd.Number()
406
Damien Neil5ec58b92019-04-30 11:36:39 -0700407 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
408 var val pref.Value
409 if fd.Kind() == pref.FloatKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700410 val = pref.ValueOfFloat32(float32(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700411 } else {
Joe Tsai84177c92019-09-17 13:38:48 -0700412 val = pref.ValueOfFloat64(float64(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700413 }
Joe Tsai378c1322019-04-25 23:48:08 -0700414 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700415 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700416 if got, want := m.Has(fd), true; got != want {
417 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 -0700418 }
Joe Tsai378c1322019-04-25 23:48:08 -0700419 if got, want := m.Get(fd), val; !valueEqual(got, want) {
420 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700421 }
422 }
423}
424
425// testOneof tests the behavior of fields in a oneof.
426func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neila3456c92019-04-30 11:36:49 -0700427 for _, mutable := range []bool{false, true} {
428 for i := 0; i < od.Fields().Len(); i++ {
429 fda := od.Fields().Get(i)
430 if mutable {
431 // Set fields by requesting a mutable reference.
432 if !fda.IsMap() && !fda.IsList() && fda.Message() == nil {
433 continue
434 }
435 _ = m.Mutable(fda)
436 } else {
437 // Set fields explicitly.
438 m.Set(fda, newValue(m, fda, 1, nil))
439 }
440 if got, want := m.WhichOneof(od), fda; got != want {
441 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
442 }
443 for j := 0; j < od.Fields().Len(); j++ {
444 fdb := od.Fields().Get(j)
445 if got, want := m.Has(fdb), i == j; got != want {
446 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
447 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700448 }
449 }
450 }
451}
452
Damien Neild91246e2019-06-21 08:36:26 -0700453// testUnknown tests the behavior of unknown fields.
454func testUnknown(t testing.TB, m pref.Message) {
455 var b []byte
456 b = wire.AppendTag(b, 1000, wire.VarintType)
457 b = wire.AppendVarint(b, 1001)
458 m.SetUnknown(pref.RawFields(b))
459 if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) {
460 t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want)
461 }
462}
463
Damien Neil5ec58b92019-04-30 11:36:39 -0700464func formatValue(v pref.Value) string {
465 switch v := v.Interface().(type) {
466 case pref.List:
467 var buf bytes.Buffer
468 buf.WriteString("list[")
469 for i := 0; i < v.Len(); i++ {
470 if i > 0 {
471 buf.WriteString(" ")
472 }
473 buf.WriteString(formatValue(v.Get(i)))
474 }
475 buf.WriteString("]")
476 return buf.String()
477 case pref.Map:
478 var buf bytes.Buffer
479 buf.WriteString("map[")
480 var keys []pref.MapKey
481 v.Range(func(k pref.MapKey, v pref.Value) bool {
482 keys = append(keys, k)
483 return true
484 })
485 sort.Slice(keys, func(i, j int) bool {
486 return keys[i].String() < keys[j].String()
487 })
488 for i, k := range keys {
489 if i > 0 {
490 buf.WriteString(" ")
491 }
492 buf.WriteString(formatValue(k.Value()))
493 buf.WriteString(":")
494 buf.WriteString(formatValue(v.Get(k)))
495 }
496 buf.WriteString("]")
497 return buf.String()
498 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700499 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700500 if err != nil {
501 return fmt.Sprintf("<%v>", err)
502 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700503 return fmt.Sprintf("%v{%v}", v.Descriptor().FullName(), string(b))
Damien Neil5ec58b92019-04-30 11:36:39 -0700504 case string:
505 return fmt.Sprintf("%q", v)
506 default:
507 return fmt.Sprint(v)
508 }
509}
510
511func valueEqual(a, b pref.Value) bool {
512 ai, bi := a.Interface(), b.Interface()
513 switch ai.(type) {
514 case pref.Message:
515 return proto.Equal(
516 a.Message().Interface(),
517 b.Message().Interface(),
518 )
519 case pref.List:
520 lista, listb := a.List(), b.List()
521 if lista.Len() != listb.Len() {
522 return false
523 }
524 for i := 0; i < lista.Len(); i++ {
525 if !valueEqual(lista.Get(i), listb.Get(i)) {
526 return false
527 }
528 }
529 return true
530 case pref.Map:
531 mapa, mapb := a.Map(), b.Map()
532 if mapa.Len() != mapb.Len() {
533 return false
534 }
535 equal := true
536 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
537 if !valueEqual(v, mapb.Get(k)) {
538 equal = false
539 return false
540 }
541 return true
542 })
543 return equal
544 case []byte:
545 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700546 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700547 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700548 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
549 case float64:
550 // NaNs are equal, but must be the same NaN.
551 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700552 default:
553 return ai == bi
554 }
555}
556
557// A seed is used to vary the content of a value.
558//
559// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
560// is unpopulated.
561//
562// A seed of minVal or maxVal is the least or greatest value of the value type.
563type seed int
564
565const (
566 minVal seed = -1
567 maxVal seed = -2
568)
569
Damien Neilf5274512019-08-05 10:48:38 -0700570// newSeed creates new seed values from a base, for example to create seeds for the
571// elements in a list. If the input seed is minVal or maxVal, so is the output.
572func newSeed(n seed, adjust ...int) seed {
573 switch n {
574 case minVal, maxVal:
575 return n
576 }
577 for _, a := range adjust {
578 n = 10*n + seed(a)
579 }
580 return n
581}
582
Damien Neil5ec58b92019-04-30 11:36:39 -0700583// newValue returns a new value assignable to a field.
584//
585// The stack parameter is used to avoid infinite recursion when populating circular
586// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700587func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700588 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700589 case fd.IsList():
Joe Tsaiac31a352019-05-13 14:32:56 -0700590 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800591 return m.New().Mutable(fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700592 }
Damien Neil290ceea2019-07-15 13:39:43 -0700593 list := m.NewField(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700594 list.Append(newListElement(fd, list, 0, stack))
595 list.Append(newListElement(fd, list, minVal, stack))
596 list.Append(newListElement(fd, list, maxVal, stack))
597 list.Append(newListElement(fd, list, n, stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700598 return pref.ValueOfList(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700599 case fd.IsMap():
Damien Neil5ec58b92019-04-30 11:36:39 -0700600 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800601 return m.New().Mutable(fd)
Damien Neil5ec58b92019-04-30 11:36:39 -0700602 }
Damien Neil290ceea2019-07-15 13:39:43 -0700603 mapv := m.NewField(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700604 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
605 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
606 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
Damien Neilf5274512019-08-05 10:48:38 -0700607 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700608 return pref.ValueOfMap(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700609 case fd.Message() != nil:
Damien Neil290ceea2019-07-15 13:39:43 -0700610 //if n == 0 {
611 // return m.New().Get(fd)
612 //}
Damien Neilf5274512019-08-05 10:48:38 -0700613 return populateMessage(m.NewField(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700614 default:
615 return newScalarValue(fd, n)
616 }
617}
618
Joe Tsai0fc49f82019-05-01 12:29:25 -0700619func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700620 if fd.Message() == nil {
621 return newScalarValue(fd, n)
622 }
Damien Neilf5274512019-08-05 10:48:38 -0700623 return populateMessage(list.NewElement().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700624}
625
626func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700627 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700628 return newScalarValue(kd, n).MapKey()
629}
630
Joe Tsai0fc49f82019-05-01 12:29:25 -0700631func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700632 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700633 if vd.Message() == nil {
634 return newScalarValue(vd, n)
635 }
Damien Neilf5274512019-08-05 10:48:38 -0700636 return populateMessage(mapv.NewValue().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700637}
638
639func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
640 switch fd.Kind() {
641 case pref.BoolKind:
Joe Tsai84177c92019-09-17 13:38:48 -0700642 return pref.ValueOfBool(n != 0)
Damien Neil5ec58b92019-04-30 11:36:39 -0700643 case pref.EnumKind:
Damien Neilf5274512019-08-05 10:48:38 -0700644 vals := fd.Enum().Values()
645 var i int
646 switch n {
647 case minVal:
648 i = 0
649 case maxVal:
650 i = vals.Len() - 1
651 default:
652 i = int(n) % vals.Len()
653 }
Joe Tsai84177c92019-09-17 13:38:48 -0700654 return pref.ValueOfEnum(vals.Get(i).Number())
Damien Neil5ec58b92019-04-30 11:36:39 -0700655 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
656 switch n {
657 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700658 return pref.ValueOfInt32(math.MinInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700659 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700660 return pref.ValueOfInt32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700661 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700662 return pref.ValueOfInt32(int32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700663 }
664 case pref.Uint32Kind, pref.Fixed32Kind:
665 switch n {
666 case minVal:
667 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700668 return pref.ValueOfUint32(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700669 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700670 return pref.ValueOfUint32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700671 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700672 return pref.ValueOfUint32(uint32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700673 }
674 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
675 switch n {
676 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700677 return pref.ValueOfInt64(math.MinInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700678 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700679 return pref.ValueOfInt64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700680 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700681 return pref.ValueOfInt64(int64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700682 }
683 case pref.Uint64Kind, pref.Fixed64Kind:
684 switch n {
685 case minVal:
686 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700687 return pref.ValueOfUint64(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700688 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700689 return pref.ValueOfUint64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700690 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700691 return pref.ValueOfUint64(uint64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700692 }
693 case pref.FloatKind:
694 switch n {
695 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700696 return pref.ValueOfFloat32(math.SmallestNonzeroFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700697 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700698 return pref.ValueOfFloat32(math.MaxFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700699 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700700 return pref.ValueOfFloat32(1.5 * float32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700701 }
702 case pref.DoubleKind:
703 switch n {
704 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700705 return pref.ValueOfFloat64(math.SmallestNonzeroFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700706 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700707 return pref.ValueOfFloat64(math.MaxFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700708 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700709 return pref.ValueOfFloat64(1.5 * float64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700710 }
711 case pref.StringKind:
712 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700713 return pref.ValueOfString("")
Damien Neil5ec58b92019-04-30 11:36:39 -0700714 }
Joe Tsai84177c92019-09-17 13:38:48 -0700715 return pref.ValueOfString(fmt.Sprintf("%d", n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700716 case pref.BytesKind:
717 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700718 return pref.ValueOfBytes(nil)
Damien Neil5ec58b92019-04-30 11:36:39 -0700719 }
Joe Tsai84177c92019-09-17 13:38:48 -0700720 return pref.ValueOfBytes([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
Damien Neil5ec58b92019-04-30 11:36:39 -0700721 }
722 panic("unhandled kind")
723}
724
Joe Tsai0fc49f82019-05-01 12:29:25 -0700725func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700726 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700727 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700728 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700729 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700730 for _, x := range stack {
731 if md == x {
Joe Tsai84177c92019-09-17 13:38:48 -0700732 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700733 }
734 }
735 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700736 for i := 0; i < md.Fields().Len(); i++ {
737 fd := md.Fields().Get(i)
738 if fd.IsWeak() {
739 continue
740 }
Damien Neilf5274512019-08-05 10:48:38 -0700741 m.Set(fd, newValue(m, fd, newSeed(n, i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700742 }
Joe Tsai84177c92019-09-17 13:38:48 -0700743 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700744}
Damien Neild91246e2019-06-21 08:36:26 -0700745
746func panics(f func()) (didPanic bool) {
747 defer func() {
748 if err := recover(); err != nil {
749 didPanic = true
750 }
751 }()
752 f()
753 return false
754}