blob: 20d20c95b58b12f589c39794bb566f766d17fdba [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 read-only properties of unpopulated composite values.
23// 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 Tsai378c1322019-04-25 23:48:08 -070043 md := m.ProtoReflect().Descriptor()
44 m1 := m.ProtoReflect().New()
Damien Neil5ec58b92019-04-30 11:36:39 -070045 for i := 0; i < md.Fields().Len(); i++ {
46 fd := md.Fields().Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -070047 testField(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070048 }
Damien Neild91246e2019-06-21 08:36:26 -070049 if opts.ExtensionTypes == nil {
50 preg.GlobalTypes.RangeExtensionsByMessage(md.FullName(), func(e pref.ExtensionType) bool {
51 opts.ExtensionTypes = append(opts.ExtensionTypes, e)
52 return true
53 })
54 }
55 for _, xt := range opts.ExtensionTypes {
Damien Neil79bfdbe2019-08-28 11:08:22 -070056 testField(t, m1, xt.TypeDescriptor())
Damien Neild91246e2019-06-21 08:36:26 -070057 }
Damien Neil5ec58b92019-04-30 11:36:39 -070058 for i := 0; i < md.Oneofs().Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070059 testOneof(t, m1, md.Oneofs().Get(i))
Damien Neil5ec58b92019-04-30 11:36:39 -070060 }
Damien Neild91246e2019-06-21 08:36:26 -070061 testUnknown(t, m1)
Damien Neil5ec58b92019-04-30 11:36:39 -070062
63 // Test round-trip marshal/unmarshal.
Joe Tsai378c1322019-04-25 23:48:08 -070064 m2 := m.ProtoReflect().New().Interface()
65 populateMessage(m2.ProtoReflect(), 1, nil)
Damien Neil290ceea2019-07-15 13:39:43 -070066 for _, xt := range opts.ExtensionTypes {
67 m2.ProtoReflect().Set(xt.TypeDescriptor(), newValue(m2.ProtoReflect(), xt.TypeDescriptor(), 1, nil))
68 }
69 b, err := proto.MarshalOptions{
70 AllowPartial: true,
71 }.Marshal(m2)
Damien Neil5ec58b92019-04-30 11:36:39 -070072 if err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070073 t.Errorf("Marshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070074 }
Joe Tsai378c1322019-04-25 23:48:08 -070075 m3 := m.ProtoReflect().New().Interface()
Damien Neil290ceea2019-07-15 13:39:43 -070076 if err := (proto.UnmarshalOptions{
77 AllowPartial: true,
78 Resolver: opts.Resolver,
79 }.Unmarshal(b, m3)); err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070080 t.Errorf("Unmarshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070081 }
Joe Tsai378c1322019-04-25 23:48:08 -070082 if !proto.Equal(m2, m3) {
83 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 -070084 }
85}
86
87func marshalText(m proto.Message) string {
Damien Neil5c5b5312019-05-14 12:44:37 -070088 b, _ := prototext.MarshalOptions{Indent: " "}.Marshal(m)
Damien Neil5ec58b92019-04-30 11:36:39 -070089 return string(b)
90}
91
Joe Tsai378c1322019-04-25 23:48:08 -070092// testField exercises set/get/has/clear of a field.
Damien Neil5ec58b92019-04-30 11:36:39 -070093func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -070094 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -070095 num := fd.Number()
Damien Neil5ec58b92019-04-30 11:36:39 -070096
Damien Neild91246e2019-06-21 08:36:26 -070097 switch {
98 case fd.IsList():
99 testFieldList(t, m, fd)
100 case fd.IsMap():
101 testFieldMap(t, m, fd)
Damien Neilf5274512019-08-05 10:48:38 -0700102 case fd.Message() != nil:
103 default:
104 if got, want := m.NewField(fd), fd.Default(); !valueEqual(got, want) {
105 t.Errorf("Message.NewField(%v) = %v, want default value %v", name, formatValue(got), formatValue(want))
106 }
107 if fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind {
108 testFieldFloat(t, m, fd)
109 }
Damien Neild91246e2019-06-21 08:36:26 -0700110 }
111
Damien Neil5ec58b92019-04-30 11:36:39 -0700112 // Set to a non-zero value, the zero value, different non-zero values.
113 for _, n := range []seed{1, 0, minVal, maxVal} {
114 v := newValue(m, fd, n, nil)
Joe Tsai378c1322019-04-25 23:48:08 -0700115 m.Set(fd, v)
Damien Neil5ec58b92019-04-30 11:36:39 -0700116 wantHas := true
117 if n == 0 {
118 if fd.Syntax() == pref.Proto3 && fd.Message() == nil {
119 wantHas = false
120 }
121 if fd.Cardinality() == pref.Repeated {
122 wantHas = false
123 }
Damien Neild91246e2019-06-21 08:36:26 -0700124 if fd.IsExtension() {
125 wantHas = true
126 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700127 if fd.ContainingOneof() != nil {
Damien Neil5ec58b92019-04-30 11:36:39 -0700128 wantHas = true
129 }
130 }
Damien Neilf5274512019-08-05 10:48:38 -0700131 if fd.Syntax() == pref.Proto3 && fd.Cardinality() != pref.Repeated && fd.ContainingOneof() == nil && fd.Kind() == pref.EnumKind && v.Enum() == 0 {
132 wantHas = false
133 }
Joe Tsai378c1322019-04-25 23:48:08 -0700134 if got, want := m.Has(fd), wantHas; got != want {
135 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 -0700136 }
Joe Tsai378c1322019-04-25 23:48:08 -0700137 if got, want := m.Get(fd), v; !valueEqual(got, want) {
138 t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700139 }
Damien Neild91246e2019-06-21 08:36:26 -0700140 found := false
141 m.Range(func(d pref.FieldDescriptor, got pref.Value) bool {
142 if fd != d {
143 return true
144 }
145 found = true
146 if want := v; !valueEqual(got, want) {
147 t.Errorf("after setting %q:\nMessage.Range got value %v, want %v", name, formatValue(got), formatValue(want))
148 }
149 return true
150 })
151 if got, want := wantHas, found; got != want {
152 t.Errorf("after setting %q:\nMessageRange saw field: %v, want %v", name, got, want)
153 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700154 }
155
Joe Tsai378c1322019-04-25 23:48:08 -0700156 m.Clear(fd)
157 if got, want := m.Has(fd), false; got != want {
158 t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700159 }
160 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700161 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700162 if got := m.Get(fd); got.List().Len() != 0 {
163 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700164 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700165 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700166 if got := m.Get(fd); got.Map().Len() != 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700167 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty map", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700168 }
Joe Tsai378c1322019-04-25 23:48:08 -0700169 case fd.Message() == nil:
170 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
171 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 -0700172 }
173 }
Damien Neild91246e2019-06-21 08:36:26 -0700174
Damien Neil290ceea2019-07-15 13:39:43 -0700175 // Set to the default value.
176 switch {
177 case fd.IsList() || fd.IsMap():
178 m.Set(fd, m.Get(fd))
179 if got, want := m.Has(fd), fd.IsExtension() || fd.ContainingOneof() != nil; got != want {
180 t.Errorf("after setting %q to default:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
181 }
182 case fd.Message() == nil:
183 m.Set(fd, m.Get(fd))
184 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
185 t.Errorf("after setting %q to default:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want))
186 }
187 }
188 m.Clear(fd)
189
Damien Neild91246e2019-06-21 08:36:26 -0700190 // Set to the wrong type.
191 v := pref.ValueOf("")
192 if fd.Kind() == pref.StringKind {
193 v = pref.ValueOf(int32(0))
194 }
195 if !panics(func() {
196 m.Set(fd, v)
197 }) {
198 t.Errorf("setting %v to %T succeeds, want panic", name, v.Interface())
199 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700200}
201
202// testFieldMap tests set/get/has/clear of entries in a map field.
203func testFieldMap(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700204 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700205 num := fd.Number()
206
Damien Neilf5274512019-08-05 10:48:38 -0700207 // New values.
Joe Tsai378c1322019-04-25 23:48:08 -0700208 m.Clear(fd) // start with an empty map
Damien Neilf5274512019-08-05 10:48:38 -0700209 mapv := m.Get(fd).Map()
210 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
211 t.Errorf("message.Get(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
212 }
213 mapv = m.Mutable(fd).Map() // mutable map
214 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
215 t.Errorf("message.Mutable(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
216 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700217
218 // Add values.
219 want := make(testMap)
220 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700221 if got, want := m.Has(fd), i > 0; got != want {
222 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 -0700223 }
224
225 k := newMapKey(fd, n)
226 v := newMapValue(fd, mapv, n, nil)
227 mapv.Set(k, v)
228 want.Set(k, v)
Joe Tsai378c1322019-04-25 23:48:08 -0700229 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
230 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 -0700231 }
232 }
233
234 // Set values.
235 want.Range(func(k pref.MapKey, v pref.Value) bool {
236 nv := newMapValue(fd, mapv, 10, nil)
237 mapv.Set(k, nv)
238 want.Set(k, nv)
Joe Tsai378c1322019-04-25 23:48:08 -0700239 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
240 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 -0700241 }
242 return true
243 })
244
245 // Clear values.
246 want.Range(func(k pref.MapKey, v pref.Value) bool {
247 mapv.Clear(k)
248 want.Clear(k)
Joe Tsai378c1322019-04-25 23:48:08 -0700249 if got, want := m.Has(fd), want.Len() > 0; got != want {
250 t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700251 }
Joe Tsai378c1322019-04-25 23:48:08 -0700252 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
253 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 -0700254 }
255 return true
256 })
257
258 // Non-existent map keys.
259 missingKey := newMapKey(fd, 1)
260 if got, want := mapv.Has(missingKey), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700261 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 -0700262 }
263 if got, want := mapv.Get(missingKey).IsValid(), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700264 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 -0700265 }
266 mapv.Clear(missingKey) // noop
267}
268
269type testMap map[interface{}]pref.Value
270
271func (m testMap) Get(k pref.MapKey) pref.Value { return m[k.Interface()] }
272func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
273func (m testMap) Has(k pref.MapKey) bool { return m.Get(k).IsValid() }
274func (m testMap) Clear(k pref.MapKey) { delete(m, k.Interface()) }
275func (m testMap) Len() int { return len(m) }
276func (m testMap) NewMessage() pref.Message { panic("unimplemented") }
Damien Neilf5274512019-08-05 10:48:38 -0700277func (m testMap) NewValue() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700278func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
279 for k, v := range m {
280 if !f(pref.ValueOf(k).MapKey(), v) {
281 return
282 }
283 }
284}
285
286// testFieldList exercises set/get/append/truncate of values in a list.
287func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700288 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700289 num := fd.Number()
290
291 m.Clear(fd) // start with an empty list
Damien Neilf5274512019-08-05 10:48:38 -0700292 list := m.Get(fd).List()
293 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
294 t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
295 }
296 list = m.Mutable(fd).List() // mutable list
297 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
298 t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
299 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700300
301 // Append values.
302 var want pref.List = &testList{}
303 for i, n := range []seed{1, 0, minVal, maxVal} {
Damien Neild91246e2019-06-21 08:36:26 -0700304 if got, want := m.Has(fd), i > 0 || fd.IsExtension(); got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700305 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 -0700306 }
307 v := newListElement(fd, list, n, nil)
308 want.Append(v)
309 list.Append(v)
310
Joe Tsai378c1322019-04-25 23:48:08 -0700311 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
312 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 -0700313 }
314 }
315
316 // Set values.
317 for i := 0; i < want.Len(); i++ {
318 v := newListElement(fd, list, seed(i+10), nil)
319 want.Set(i, v)
320 list.Set(i, v)
Joe Tsai378c1322019-04-25 23:48:08 -0700321 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
322 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 -0700323 }
324 }
325
326 // Truncate.
327 for want.Len() > 0 {
328 n := want.Len() - 1
329 want.Truncate(n)
330 list.Truncate(n)
Damien Neild91246e2019-06-21 08:36:26 -0700331 if got, want := m.Has(fd), want.Len() > 0 || fd.IsExtension(); got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700332 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 -0700333 }
Joe Tsai378c1322019-04-25 23:48:08 -0700334 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
335 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 -0700336 }
337 }
338}
339
340type testList struct {
341 a []pref.Value
342}
343
344func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
345func (l *testList) Get(n int) pref.Value { return l.a[n] }
346func (l *testList) Len() int { return len(l.a) }
347func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
348func (l *testList) Truncate(n int) { l.a = l.a[:n] }
349func (l *testList) NewMessage() pref.Message { panic("unimplemented") }
Damien Neilf5274512019-08-05 10:48:38 -0700350func (l *testList) NewElement() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700351
352// testFieldFloat exercises some interesting floating-point scalar field values.
353func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700354 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700355 num := fd.Number()
356
Damien Neil5ec58b92019-04-30 11:36:39 -0700357 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
358 var val pref.Value
359 if fd.Kind() == pref.FloatKind {
360 val = pref.ValueOf(float32(v))
361 } else {
362 val = pref.ValueOf(v)
363 }
Joe Tsai378c1322019-04-25 23:48:08 -0700364 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700365 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700366 if got, want := m.Has(fd), true; got != want {
367 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 -0700368 }
Joe Tsai378c1322019-04-25 23:48:08 -0700369 if got, want := m.Get(fd), val; !valueEqual(got, want) {
370 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700371 }
372 }
373}
374
375// testOneof tests the behavior of fields in a oneof.
376func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neila3456c92019-04-30 11:36:49 -0700377 for _, mutable := range []bool{false, true} {
378 for i := 0; i < od.Fields().Len(); i++ {
379 fda := od.Fields().Get(i)
380 if mutable {
381 // Set fields by requesting a mutable reference.
382 if !fda.IsMap() && !fda.IsList() && fda.Message() == nil {
383 continue
384 }
385 _ = m.Mutable(fda)
386 } else {
387 // Set fields explicitly.
388 m.Set(fda, newValue(m, fda, 1, nil))
389 }
390 if got, want := m.WhichOneof(od), fda; got != want {
391 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
392 }
393 for j := 0; j < od.Fields().Len(); j++ {
394 fdb := od.Fields().Get(j)
395 if got, want := m.Has(fdb), i == j; got != want {
396 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
397 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700398 }
399 }
400 }
401}
402
Damien Neild91246e2019-06-21 08:36:26 -0700403// testUnknown tests the behavior of unknown fields.
404func testUnknown(t testing.TB, m pref.Message) {
405 var b []byte
406 b = wire.AppendTag(b, 1000, wire.VarintType)
407 b = wire.AppendVarint(b, 1001)
408 m.SetUnknown(pref.RawFields(b))
409 if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) {
410 t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want)
411 }
412}
413
Damien Neil5ec58b92019-04-30 11:36:39 -0700414func formatValue(v pref.Value) string {
415 switch v := v.Interface().(type) {
416 case pref.List:
417 var buf bytes.Buffer
418 buf.WriteString("list[")
419 for i := 0; i < v.Len(); i++ {
420 if i > 0 {
421 buf.WriteString(" ")
422 }
423 buf.WriteString(formatValue(v.Get(i)))
424 }
425 buf.WriteString("]")
426 return buf.String()
427 case pref.Map:
428 var buf bytes.Buffer
429 buf.WriteString("map[")
430 var keys []pref.MapKey
431 v.Range(func(k pref.MapKey, v pref.Value) bool {
432 keys = append(keys, k)
433 return true
434 })
435 sort.Slice(keys, func(i, j int) bool {
436 return keys[i].String() < keys[j].String()
437 })
438 for i, k := range keys {
439 if i > 0 {
440 buf.WriteString(" ")
441 }
442 buf.WriteString(formatValue(k.Value()))
443 buf.WriteString(":")
444 buf.WriteString(formatValue(v.Get(k)))
445 }
446 buf.WriteString("]")
447 return buf.String()
448 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700449 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700450 if err != nil {
451 return fmt.Sprintf("<%v>", err)
452 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700453 return fmt.Sprintf("%v{%v}", v.Descriptor().FullName(), string(b))
Damien Neil5ec58b92019-04-30 11:36:39 -0700454 case string:
455 return fmt.Sprintf("%q", v)
456 default:
457 return fmt.Sprint(v)
458 }
459}
460
461func valueEqual(a, b pref.Value) bool {
462 ai, bi := a.Interface(), b.Interface()
463 switch ai.(type) {
464 case pref.Message:
465 return proto.Equal(
466 a.Message().Interface(),
467 b.Message().Interface(),
468 )
469 case pref.List:
470 lista, listb := a.List(), b.List()
471 if lista.Len() != listb.Len() {
472 return false
473 }
474 for i := 0; i < lista.Len(); i++ {
475 if !valueEqual(lista.Get(i), listb.Get(i)) {
476 return false
477 }
478 }
479 return true
480 case pref.Map:
481 mapa, mapb := a.Map(), b.Map()
482 if mapa.Len() != mapb.Len() {
483 return false
484 }
485 equal := true
486 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
487 if !valueEqual(v, mapb.Get(k)) {
488 equal = false
489 return false
490 }
491 return true
492 })
493 return equal
494 case []byte:
495 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700496 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700497 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700498 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
499 case float64:
500 // NaNs are equal, but must be the same NaN.
501 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700502 default:
503 return ai == bi
504 }
505}
506
507// A seed is used to vary the content of a value.
508//
509// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
510// is unpopulated.
511//
512// A seed of minVal or maxVal is the least or greatest value of the value type.
513type seed int
514
515const (
516 minVal seed = -1
517 maxVal seed = -2
518)
519
Damien Neilf5274512019-08-05 10:48:38 -0700520// newSeed creates new seed values from a base, for example to create seeds for the
521// elements in a list. If the input seed is minVal or maxVal, so is the output.
522func newSeed(n seed, adjust ...int) seed {
523 switch n {
524 case minVal, maxVal:
525 return n
526 }
527 for _, a := range adjust {
528 n = 10*n + seed(a)
529 }
530 return n
531}
532
Damien Neil5ec58b92019-04-30 11:36:39 -0700533// newValue returns a new value assignable to a field.
534//
535// The stack parameter is used to avoid infinite recursion when populating circular
536// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700537func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700538 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700539 case fd.IsList():
Joe Tsaiac31a352019-05-13 14:32:56 -0700540 if n == 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700541 return m.New().Get(fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700542 }
Damien Neil290ceea2019-07-15 13:39:43 -0700543 list := m.NewField(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700544 list.Append(newListElement(fd, list, 0, stack))
545 list.Append(newListElement(fd, list, minVal, stack))
546 list.Append(newListElement(fd, list, maxVal, stack))
547 list.Append(newListElement(fd, list, n, stack))
548 return pref.ValueOf(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700549 case fd.IsMap():
Damien Neil5ec58b92019-04-30 11:36:39 -0700550 if n == 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700551 return m.New().Get(fd)
Damien Neil5ec58b92019-04-30 11:36:39 -0700552 }
Damien Neil290ceea2019-07-15 13:39:43 -0700553 mapv := m.NewField(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700554 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
555 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
556 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
Damien Neilf5274512019-08-05 10:48:38 -0700557 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700558 return pref.ValueOf(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700559 case fd.Message() != nil:
Damien Neil290ceea2019-07-15 13:39:43 -0700560 //if n == 0 {
561 // return m.New().Get(fd)
562 //}
Damien Neilf5274512019-08-05 10:48:38 -0700563 return populateMessage(m.NewField(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700564 default:
565 return newScalarValue(fd, n)
566 }
567}
568
Joe Tsai0fc49f82019-05-01 12:29:25 -0700569func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700570 if fd.Message() == nil {
571 return newScalarValue(fd, n)
572 }
Damien Neilf5274512019-08-05 10:48:38 -0700573 return populateMessage(list.NewElement().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700574}
575
576func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700577 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700578 return newScalarValue(kd, n).MapKey()
579}
580
Joe Tsai0fc49f82019-05-01 12:29:25 -0700581func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700582 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700583 if vd.Message() == nil {
584 return newScalarValue(vd, n)
585 }
Damien Neilf5274512019-08-05 10:48:38 -0700586 return populateMessage(mapv.NewValue().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700587}
588
589func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
590 switch fd.Kind() {
591 case pref.BoolKind:
592 return pref.ValueOf(n != 0)
593 case pref.EnumKind:
Damien Neilf5274512019-08-05 10:48:38 -0700594 vals := fd.Enum().Values()
595 var i int
596 switch n {
597 case minVal:
598 i = 0
599 case maxVal:
600 i = vals.Len() - 1
601 default:
602 i = int(n) % vals.Len()
603 }
604 return pref.ValueOf(vals.Get(i).Number())
Damien Neil5ec58b92019-04-30 11:36:39 -0700605 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
606 switch n {
607 case minVal:
608 return pref.ValueOf(int32(math.MinInt32))
609 case maxVal:
610 return pref.ValueOf(int32(math.MaxInt32))
611 default:
612 return pref.ValueOf(int32(n))
613 }
614 case pref.Uint32Kind, pref.Fixed32Kind:
615 switch n {
616 case minVal:
617 // Only use 0 for the zero value.
618 return pref.ValueOf(uint32(1))
619 case maxVal:
620 return pref.ValueOf(uint32(math.MaxInt32))
621 default:
622 return pref.ValueOf(uint32(n))
623 }
624 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
625 switch n {
626 case minVal:
627 return pref.ValueOf(int64(math.MinInt64))
628 case maxVal:
629 return pref.ValueOf(int64(math.MaxInt64))
630 default:
631 return pref.ValueOf(int64(n))
632 }
633 case pref.Uint64Kind, pref.Fixed64Kind:
634 switch n {
635 case minVal:
636 // Only use 0 for the zero value.
637 return pref.ValueOf(uint64(1))
638 case maxVal:
639 return pref.ValueOf(uint64(math.MaxInt64))
640 default:
641 return pref.ValueOf(uint64(n))
642 }
643 case pref.FloatKind:
644 switch n {
645 case minVal:
646 return pref.ValueOf(float32(math.SmallestNonzeroFloat32))
647 case maxVal:
648 return pref.ValueOf(float32(math.MaxFloat32))
649 default:
650 return pref.ValueOf(1.5 * float32(n))
651 }
652 case pref.DoubleKind:
653 switch n {
654 case minVal:
655 return pref.ValueOf(float64(math.SmallestNonzeroFloat64))
656 case maxVal:
657 return pref.ValueOf(float64(math.MaxFloat64))
658 default:
659 return pref.ValueOf(1.5 * float64(n))
660 }
661 case pref.StringKind:
662 if n == 0 {
663 return pref.ValueOf("")
664 }
665 return pref.ValueOf(fmt.Sprintf("%d", n))
666 case pref.BytesKind:
667 if n == 0 {
668 return pref.ValueOf([]byte(nil))
669 }
670 return pref.ValueOf([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
671 }
672 panic("unhandled kind")
673}
674
Joe Tsai0fc49f82019-05-01 12:29:25 -0700675func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700676 if n == 0 {
677 return pref.ValueOf(m)
678 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700679 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700680 for _, x := range stack {
681 if md == x {
682 return pref.ValueOf(m)
683 }
684 }
685 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700686 for i := 0; i < md.Fields().Len(); i++ {
687 fd := md.Fields().Get(i)
688 if fd.IsWeak() {
689 continue
690 }
Damien Neilf5274512019-08-05 10:48:38 -0700691 m.Set(fd, newValue(m, fd, newSeed(n, i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700692 }
693 return pref.ValueOf(m)
694}
Damien Neild91246e2019-06-21 08:36:26 -0700695
696func panics(f func()) (didPanic bool) {
697 defer func() {
698 if err := recover(); err != nil {
699 didPanic = true
700 }
701 }()
702 f()
703 return false
704}