blob: 437c216d0b82f8c3bdc7ceb266bc7dfe0da286fc [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.
Joe Tsai84177c92019-09-17 13:38:48 -0700191 v := pref.ValueOfString("")
Damien Neild91246e2019-06-21 08:36:26 -0700192 if fd.Kind() == pref.StringKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700193 v = pref.ValueOfInt32(0)
Damien Neild91246e2019-06-21 08:36:26 -0700194 }
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 Tsai84177c92019-09-17 13:38:48 -0700229 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700230 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 Tsai84177c92019-09-17 13:38:48 -0700239 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700240 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 Tsai84177c92019-09-17 13:38:48 -0700252 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700253 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) }
Damien Neilf5274512019-08-05 10:48:38 -0700276func (m testMap) NewValue() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700277func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
278 for k, v := range m {
279 if !f(pref.ValueOf(k).MapKey(), v) {
280 return
281 }
282 }
283}
284
285// testFieldList exercises set/get/append/truncate of values in a list.
286func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700287 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700288 num := fd.Number()
289
290 m.Clear(fd) // start with an empty list
Damien Neilf5274512019-08-05 10:48:38 -0700291 list := m.Get(fd).List()
292 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
293 t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
294 }
295 list = m.Mutable(fd).List() // mutable list
296 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
297 t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
298 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700299
300 // Append values.
301 var want pref.List = &testList{}
302 for i, n := range []seed{1, 0, minVal, maxVal} {
Damien Neild91246e2019-06-21 08:36:26 -0700303 if got, want := m.Has(fd), i > 0 || fd.IsExtension(); got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700304 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 -0700305 }
306 v := newListElement(fd, list, n, nil)
307 want.Append(v)
308 list.Append(v)
309
Joe Tsai84177c92019-09-17 13:38:48 -0700310 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700311 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 -0700312 }
313 }
314
315 // Set values.
316 for i := 0; i < want.Len(); i++ {
317 v := newListElement(fd, list, seed(i+10), nil)
318 want.Set(i, v)
319 list.Set(i, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700320 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700321 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 -0700322 }
323 }
324
325 // Truncate.
326 for want.Len() > 0 {
327 n := want.Len() - 1
328 want.Truncate(n)
329 list.Truncate(n)
Damien Neild91246e2019-06-21 08:36:26 -0700330 if got, want := m.Has(fd), want.Len() > 0 || fd.IsExtension(); got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700331 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 -0700332 }
Joe Tsai84177c92019-09-17 13:38:48 -0700333 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700334 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 -0700335 }
336 }
337}
338
339type testList struct {
340 a []pref.Value
341}
342
Damien Neil2eaed362019-09-05 10:08:32 -0700343func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
344func (l *testList) Get(n int) pref.Value { return l.a[n] }
345func (l *testList) Len() int { return len(l.a) }
346func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
347func (l *testList) Truncate(n int) { l.a = l.a[:n] }
348func (l *testList) NewElement() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700349
350// testFieldFloat exercises some interesting floating-point scalar field values.
351func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700352 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700353 num := fd.Number()
354
Damien Neil5ec58b92019-04-30 11:36:39 -0700355 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
356 var val pref.Value
357 if fd.Kind() == pref.FloatKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700358 val = pref.ValueOfFloat32(float32(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700359 } else {
Joe Tsai84177c92019-09-17 13:38:48 -0700360 val = pref.ValueOfFloat64(float64(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700361 }
Joe Tsai378c1322019-04-25 23:48:08 -0700362 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700363 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700364 if got, want := m.Has(fd), true; got != want {
365 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 -0700366 }
Joe Tsai378c1322019-04-25 23:48:08 -0700367 if got, want := m.Get(fd), val; !valueEqual(got, want) {
368 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700369 }
370 }
371}
372
373// testOneof tests the behavior of fields in a oneof.
374func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neila3456c92019-04-30 11:36:49 -0700375 for _, mutable := range []bool{false, true} {
376 for i := 0; i < od.Fields().Len(); i++ {
377 fda := od.Fields().Get(i)
378 if mutable {
379 // Set fields by requesting a mutable reference.
380 if !fda.IsMap() && !fda.IsList() && fda.Message() == nil {
381 continue
382 }
383 _ = m.Mutable(fda)
384 } else {
385 // Set fields explicitly.
386 m.Set(fda, newValue(m, fda, 1, nil))
387 }
388 if got, want := m.WhichOneof(od), fda; got != want {
389 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
390 }
391 for j := 0; j < od.Fields().Len(); j++ {
392 fdb := od.Fields().Get(j)
393 if got, want := m.Has(fdb), i == j; got != want {
394 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
395 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700396 }
397 }
398 }
399}
400
Damien Neild91246e2019-06-21 08:36:26 -0700401// testUnknown tests the behavior of unknown fields.
402func testUnknown(t testing.TB, m pref.Message) {
403 var b []byte
404 b = wire.AppendTag(b, 1000, wire.VarintType)
405 b = wire.AppendVarint(b, 1001)
406 m.SetUnknown(pref.RawFields(b))
407 if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) {
408 t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want)
409 }
410}
411
Damien Neil5ec58b92019-04-30 11:36:39 -0700412func formatValue(v pref.Value) string {
413 switch v := v.Interface().(type) {
414 case pref.List:
415 var buf bytes.Buffer
416 buf.WriteString("list[")
417 for i := 0; i < v.Len(); i++ {
418 if i > 0 {
419 buf.WriteString(" ")
420 }
421 buf.WriteString(formatValue(v.Get(i)))
422 }
423 buf.WriteString("]")
424 return buf.String()
425 case pref.Map:
426 var buf bytes.Buffer
427 buf.WriteString("map[")
428 var keys []pref.MapKey
429 v.Range(func(k pref.MapKey, v pref.Value) bool {
430 keys = append(keys, k)
431 return true
432 })
433 sort.Slice(keys, func(i, j int) bool {
434 return keys[i].String() < keys[j].String()
435 })
436 for i, k := range keys {
437 if i > 0 {
438 buf.WriteString(" ")
439 }
440 buf.WriteString(formatValue(k.Value()))
441 buf.WriteString(":")
442 buf.WriteString(formatValue(v.Get(k)))
443 }
444 buf.WriteString("]")
445 return buf.String()
446 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700447 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700448 if err != nil {
449 return fmt.Sprintf("<%v>", err)
450 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700451 return fmt.Sprintf("%v{%v}", v.Descriptor().FullName(), string(b))
Damien Neil5ec58b92019-04-30 11:36:39 -0700452 case string:
453 return fmt.Sprintf("%q", v)
454 default:
455 return fmt.Sprint(v)
456 }
457}
458
459func valueEqual(a, b pref.Value) bool {
460 ai, bi := a.Interface(), b.Interface()
461 switch ai.(type) {
462 case pref.Message:
463 return proto.Equal(
464 a.Message().Interface(),
465 b.Message().Interface(),
466 )
467 case pref.List:
468 lista, listb := a.List(), b.List()
469 if lista.Len() != listb.Len() {
470 return false
471 }
472 for i := 0; i < lista.Len(); i++ {
473 if !valueEqual(lista.Get(i), listb.Get(i)) {
474 return false
475 }
476 }
477 return true
478 case pref.Map:
479 mapa, mapb := a.Map(), b.Map()
480 if mapa.Len() != mapb.Len() {
481 return false
482 }
483 equal := true
484 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
485 if !valueEqual(v, mapb.Get(k)) {
486 equal = false
487 return false
488 }
489 return true
490 })
491 return equal
492 case []byte:
493 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700494 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700495 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700496 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
497 case float64:
498 // NaNs are equal, but must be the same NaN.
499 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700500 default:
501 return ai == bi
502 }
503}
504
505// A seed is used to vary the content of a value.
506//
507// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
508// is unpopulated.
509//
510// A seed of minVal or maxVal is the least or greatest value of the value type.
511type seed int
512
513const (
514 minVal seed = -1
515 maxVal seed = -2
516)
517
Damien Neilf5274512019-08-05 10:48:38 -0700518// newSeed creates new seed values from a base, for example to create seeds for the
519// elements in a list. If the input seed is minVal or maxVal, so is the output.
520func newSeed(n seed, adjust ...int) seed {
521 switch n {
522 case minVal, maxVal:
523 return n
524 }
525 for _, a := range adjust {
526 n = 10*n + seed(a)
527 }
528 return n
529}
530
Damien Neil5ec58b92019-04-30 11:36:39 -0700531// newValue returns a new value assignable to a field.
532//
533// The stack parameter is used to avoid infinite recursion when populating circular
534// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700535func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700536 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700537 case fd.IsList():
Joe Tsaiac31a352019-05-13 14:32:56 -0700538 if n == 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700539 return m.New().Get(fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700540 }
Damien Neil290ceea2019-07-15 13:39:43 -0700541 list := m.NewField(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700542 list.Append(newListElement(fd, list, 0, stack))
543 list.Append(newListElement(fd, list, minVal, stack))
544 list.Append(newListElement(fd, list, maxVal, stack))
545 list.Append(newListElement(fd, list, n, stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700546 return pref.ValueOfList(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700547 case fd.IsMap():
Damien Neil5ec58b92019-04-30 11:36:39 -0700548 if n == 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700549 return m.New().Get(fd)
Damien Neil5ec58b92019-04-30 11:36:39 -0700550 }
Damien Neil290ceea2019-07-15 13:39:43 -0700551 mapv := m.NewField(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700552 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
553 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
554 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
Damien Neilf5274512019-08-05 10:48:38 -0700555 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700556 return pref.ValueOfMap(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700557 case fd.Message() != nil:
Damien Neil290ceea2019-07-15 13:39:43 -0700558 //if n == 0 {
559 // return m.New().Get(fd)
560 //}
Damien Neilf5274512019-08-05 10:48:38 -0700561 return populateMessage(m.NewField(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700562 default:
563 return newScalarValue(fd, n)
564 }
565}
566
Joe Tsai0fc49f82019-05-01 12:29:25 -0700567func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700568 if fd.Message() == nil {
569 return newScalarValue(fd, n)
570 }
Damien Neilf5274512019-08-05 10:48:38 -0700571 return populateMessage(list.NewElement().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700572}
573
574func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700575 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700576 return newScalarValue(kd, n).MapKey()
577}
578
Joe Tsai0fc49f82019-05-01 12:29:25 -0700579func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700580 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700581 if vd.Message() == nil {
582 return newScalarValue(vd, n)
583 }
Damien Neilf5274512019-08-05 10:48:38 -0700584 return populateMessage(mapv.NewValue().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700585}
586
587func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
588 switch fd.Kind() {
589 case pref.BoolKind:
Joe Tsai84177c92019-09-17 13:38:48 -0700590 return pref.ValueOfBool(n != 0)
Damien Neil5ec58b92019-04-30 11:36:39 -0700591 case pref.EnumKind:
Damien Neilf5274512019-08-05 10:48:38 -0700592 vals := fd.Enum().Values()
593 var i int
594 switch n {
595 case minVal:
596 i = 0
597 case maxVal:
598 i = vals.Len() - 1
599 default:
600 i = int(n) % vals.Len()
601 }
Joe Tsai84177c92019-09-17 13:38:48 -0700602 return pref.ValueOfEnum(vals.Get(i).Number())
Damien Neil5ec58b92019-04-30 11:36:39 -0700603 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
604 switch n {
605 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700606 return pref.ValueOfInt32(math.MinInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700607 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700608 return pref.ValueOfInt32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700609 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700610 return pref.ValueOfInt32(int32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700611 }
612 case pref.Uint32Kind, pref.Fixed32Kind:
613 switch n {
614 case minVal:
615 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700616 return pref.ValueOfUint32(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700617 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700618 return pref.ValueOfUint32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700619 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700620 return pref.ValueOfUint32(uint32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700621 }
622 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
623 switch n {
624 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700625 return pref.ValueOfInt64(math.MinInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700626 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700627 return pref.ValueOfInt64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700628 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700629 return pref.ValueOfInt64(int64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700630 }
631 case pref.Uint64Kind, pref.Fixed64Kind:
632 switch n {
633 case minVal:
634 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700635 return pref.ValueOfUint64(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700636 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700637 return pref.ValueOfUint64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700638 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700639 return pref.ValueOfUint64(uint64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700640 }
641 case pref.FloatKind:
642 switch n {
643 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700644 return pref.ValueOfFloat32(math.SmallestNonzeroFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700645 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700646 return pref.ValueOfFloat32(math.MaxFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700647 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700648 return pref.ValueOfFloat32(1.5 * float32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700649 }
650 case pref.DoubleKind:
651 switch n {
652 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700653 return pref.ValueOfFloat64(math.SmallestNonzeroFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700654 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700655 return pref.ValueOfFloat64(math.MaxFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700656 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700657 return pref.ValueOfFloat64(1.5 * float64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700658 }
659 case pref.StringKind:
660 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700661 return pref.ValueOfString("")
Damien Neil5ec58b92019-04-30 11:36:39 -0700662 }
Joe Tsai84177c92019-09-17 13:38:48 -0700663 return pref.ValueOfString(fmt.Sprintf("%d", n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700664 case pref.BytesKind:
665 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700666 return pref.ValueOfBytes(nil)
Damien Neil5ec58b92019-04-30 11:36:39 -0700667 }
Joe Tsai84177c92019-09-17 13:38:48 -0700668 return pref.ValueOfBytes([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
Damien Neil5ec58b92019-04-30 11:36:39 -0700669 }
670 panic("unhandled kind")
671}
672
Joe Tsai0fc49f82019-05-01 12:29:25 -0700673func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700674 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700675 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700676 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700677 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700678 for _, x := range stack {
679 if md == x {
Joe Tsai84177c92019-09-17 13:38:48 -0700680 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700681 }
682 }
683 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700684 for i := 0; i < md.Fields().Len(); i++ {
685 fd := md.Fields().Get(i)
686 if fd.IsWeak() {
687 continue
688 }
Damien Neilf5274512019-08-05 10:48:38 -0700689 m.Set(fd, newValue(m, fd, newSeed(n, i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700690 }
Joe Tsai84177c92019-09-17 13:38:48 -0700691 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700692}
Damien Neild91246e2019-06-21 08:36:26 -0700693
694func panics(f func()) (didPanic bool) {
695 defer func() {
696 if err := recover(); err != nil {
697 didPanic = true
698 }
699 }()
700 f()
701 return false
702}