blob: fbfe7c6e7ef4972ba8b4bb5410347f12a94c1aa1 [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
32}
33
Joe Tsai378c1322019-04-25 23:48:08 -070034// TestMessage runs the provided m through a series of tests
35// exercising the protobuf reflection API.
Damien Neild91246e2019-06-21 08:36:26 -070036func TestMessage(t testing.TB, m proto.Message, opts MessageOptions) {
Joe Tsai378c1322019-04-25 23:48:08 -070037 md := m.ProtoReflect().Descriptor()
38 m1 := m.ProtoReflect().New()
Damien Neil5ec58b92019-04-30 11:36:39 -070039 for i := 0; i < md.Fields().Len(); i++ {
40 fd := md.Fields().Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -070041 testField(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070042 }
Damien Neild91246e2019-06-21 08:36:26 -070043 if opts.ExtensionTypes == nil {
44 preg.GlobalTypes.RangeExtensionsByMessage(md.FullName(), func(e pref.ExtensionType) bool {
45 opts.ExtensionTypes = append(opts.ExtensionTypes, e)
46 return true
47 })
48 }
49 for _, xt := range opts.ExtensionTypes {
Damien Neil79bfdbe2019-08-28 11:08:22 -070050 testField(t, m1, xt.TypeDescriptor())
Damien Neild91246e2019-06-21 08:36:26 -070051 }
Damien Neil5ec58b92019-04-30 11:36:39 -070052 for i := 0; i < md.Oneofs().Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070053 testOneof(t, m1, md.Oneofs().Get(i))
Damien Neil5ec58b92019-04-30 11:36:39 -070054 }
Damien Neild91246e2019-06-21 08:36:26 -070055 testUnknown(t, m1)
Damien Neil5ec58b92019-04-30 11:36:39 -070056
57 // Test round-trip marshal/unmarshal.
Joe Tsai378c1322019-04-25 23:48:08 -070058 m2 := m.ProtoReflect().New().Interface()
59 populateMessage(m2.ProtoReflect(), 1, nil)
Damien Neil92f76182019-08-02 16:58:08 -070060 b, err := (proto.MarshalOptions{AllowPartial: true}).Marshal(m2)
Damien Neil5ec58b92019-04-30 11:36:39 -070061 if err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070062 t.Errorf("Marshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070063 }
Joe Tsai378c1322019-04-25 23:48:08 -070064 m3 := m.ProtoReflect().New().Interface()
Damien Neil92f76182019-08-02 16:58:08 -070065 if err := (proto.UnmarshalOptions{AllowPartial: true}).Unmarshal(b, m3); err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070066 t.Errorf("Unmarshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070067 }
Joe Tsai378c1322019-04-25 23:48:08 -070068 if !proto.Equal(m2, m3) {
69 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 -070070 }
71}
72
73func marshalText(m proto.Message) string {
Damien Neil5c5b5312019-05-14 12:44:37 -070074 b, _ := prototext.MarshalOptions{Indent: " "}.Marshal(m)
Damien Neil5ec58b92019-04-30 11:36:39 -070075 return string(b)
76}
77
Joe Tsai378c1322019-04-25 23:48:08 -070078// testField exercises set/get/has/clear of a field.
Damien Neil5ec58b92019-04-30 11:36:39 -070079func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -070080 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -070081 num := fd.Number()
Damien Neil5ec58b92019-04-30 11:36:39 -070082
Damien Neild91246e2019-06-21 08:36:26 -070083 switch {
84 case fd.IsList():
85 testFieldList(t, m, fd)
86 case fd.IsMap():
87 testFieldMap(t, m, fd)
Damien Neilf5274512019-08-05 10:48:38 -070088 case fd.Message() != nil:
89 default:
90 if got, want := m.NewField(fd), fd.Default(); !valueEqual(got, want) {
91 t.Errorf("Message.NewField(%v) = %v, want default value %v", name, formatValue(got), formatValue(want))
92 }
93 if fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind {
94 testFieldFloat(t, m, fd)
95 }
Damien Neild91246e2019-06-21 08:36:26 -070096 }
97
Damien Neil5ec58b92019-04-30 11:36:39 -070098 // Set to a non-zero value, the zero value, different non-zero values.
99 for _, n := range []seed{1, 0, minVal, maxVal} {
100 v := newValue(m, fd, n, nil)
Joe Tsai378c1322019-04-25 23:48:08 -0700101 m.Set(fd, v)
Damien Neil5ec58b92019-04-30 11:36:39 -0700102 wantHas := true
103 if n == 0 {
104 if fd.Syntax() == pref.Proto3 && fd.Message() == nil {
105 wantHas = false
106 }
107 if fd.Cardinality() == pref.Repeated {
108 wantHas = false
109 }
Damien Neild91246e2019-06-21 08:36:26 -0700110 if fd.IsExtension() {
111 wantHas = true
112 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700113 if fd.ContainingOneof() != nil {
Damien Neil5ec58b92019-04-30 11:36:39 -0700114 wantHas = true
115 }
116 }
Damien Neilf5274512019-08-05 10:48:38 -0700117 if fd.Syntax() == pref.Proto3 && fd.Cardinality() != pref.Repeated && fd.ContainingOneof() == nil && fd.Kind() == pref.EnumKind && v.Enum() == 0 {
118 wantHas = false
119 }
Joe Tsai378c1322019-04-25 23:48:08 -0700120 if got, want := m.Has(fd), wantHas; got != want {
121 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 -0700122 }
Joe Tsai378c1322019-04-25 23:48:08 -0700123 if got, want := m.Get(fd), v; !valueEqual(got, want) {
124 t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700125 }
Damien Neild91246e2019-06-21 08:36:26 -0700126 found := false
127 m.Range(func(d pref.FieldDescriptor, got pref.Value) bool {
128 if fd != d {
129 return true
130 }
131 found = true
132 if want := v; !valueEqual(got, want) {
133 t.Errorf("after setting %q:\nMessage.Range got value %v, want %v", name, formatValue(got), formatValue(want))
134 }
135 return true
136 })
137 if got, want := wantHas, found; got != want {
138 t.Errorf("after setting %q:\nMessageRange saw field: %v, want %v", name, got, want)
139 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700140 }
141
Joe Tsai378c1322019-04-25 23:48:08 -0700142 m.Clear(fd)
143 if got, want := m.Has(fd), false; got != want {
144 t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700145 }
146 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700147 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700148 if got := m.Get(fd); got.List().Len() != 0 {
149 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700150 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700151 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700152 if got := m.Get(fd); got.Map().Len() != 0 {
153 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700154 }
Joe Tsai378c1322019-04-25 23:48:08 -0700155 case fd.Message() == nil:
156 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
157 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 -0700158 }
159 }
Damien Neild91246e2019-06-21 08:36:26 -0700160
161 // Set to the wrong type.
162 v := pref.ValueOf("")
163 if fd.Kind() == pref.StringKind {
164 v = pref.ValueOf(int32(0))
165 }
166 if !panics(func() {
167 m.Set(fd, v)
168 }) {
169 t.Errorf("setting %v to %T succeeds, want panic", name, v.Interface())
170 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700171}
172
173// testFieldMap tests set/get/has/clear of entries in a map field.
174func testFieldMap(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700175 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700176 num := fd.Number()
177
Damien Neilf5274512019-08-05 10:48:38 -0700178 // New values.
Joe Tsai378c1322019-04-25 23:48:08 -0700179 m.Clear(fd) // start with an empty map
Damien Neilf5274512019-08-05 10:48:38 -0700180 mapv := m.Get(fd).Map()
181 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
182 t.Errorf("message.Get(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
183 }
184 mapv = m.Mutable(fd).Map() // mutable map
185 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
186 t.Errorf("message.Mutable(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
187 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700188
189 // Add values.
190 want := make(testMap)
191 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700192 if got, want := m.Has(fd), i > 0; got != want {
193 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 -0700194 }
195
196 k := newMapKey(fd, n)
197 v := newMapValue(fd, mapv, n, nil)
198 mapv.Set(k, v)
199 want.Set(k, v)
Joe Tsai378c1322019-04-25 23:48:08 -0700200 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
201 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 -0700202 }
203 }
204
205 // Set values.
206 want.Range(func(k pref.MapKey, v pref.Value) bool {
207 nv := newMapValue(fd, mapv, 10, nil)
208 mapv.Set(k, nv)
209 want.Set(k, nv)
Joe Tsai378c1322019-04-25 23:48:08 -0700210 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
211 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 -0700212 }
213 return true
214 })
215
216 // Clear values.
217 want.Range(func(k pref.MapKey, v pref.Value) bool {
218 mapv.Clear(k)
219 want.Clear(k)
Joe Tsai378c1322019-04-25 23:48:08 -0700220 if got, want := m.Has(fd), want.Len() > 0; got != want {
221 t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700222 }
Joe Tsai378c1322019-04-25 23:48:08 -0700223 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
224 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 -0700225 }
226 return true
227 })
228
229 // Non-existent map keys.
230 missingKey := newMapKey(fd, 1)
231 if got, want := mapv.Has(missingKey), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700232 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 -0700233 }
234 if got, want := mapv.Get(missingKey).IsValid(), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700235 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 -0700236 }
237 mapv.Clear(missingKey) // noop
238}
239
240type testMap map[interface{}]pref.Value
241
242func (m testMap) Get(k pref.MapKey) pref.Value { return m[k.Interface()] }
243func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
244func (m testMap) Has(k pref.MapKey) bool { return m.Get(k).IsValid() }
245func (m testMap) Clear(k pref.MapKey) { delete(m, k.Interface()) }
246func (m testMap) Len() int { return len(m) }
247func (m testMap) NewMessage() pref.Message { panic("unimplemented") }
Damien Neilf5274512019-08-05 10:48:38 -0700248func (m testMap) NewValue() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700249func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
250 for k, v := range m {
251 if !f(pref.ValueOf(k).MapKey(), v) {
252 return
253 }
254 }
255}
256
257// testFieldList exercises set/get/append/truncate of values in a list.
258func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700259 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700260 num := fd.Number()
261
262 m.Clear(fd) // start with an empty list
Damien Neilf5274512019-08-05 10:48:38 -0700263 list := m.Get(fd).List()
264 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
265 t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
266 }
267 list = m.Mutable(fd).List() // mutable list
268 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
269 t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
270 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700271
272 // Append values.
273 var want pref.List = &testList{}
274 for i, n := range []seed{1, 0, minVal, maxVal} {
Damien Neild91246e2019-06-21 08:36:26 -0700275 if got, want := m.Has(fd), i > 0 || fd.IsExtension(); got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700276 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 -0700277 }
278 v := newListElement(fd, list, n, nil)
279 want.Append(v)
280 list.Append(v)
281
Joe Tsai378c1322019-04-25 23:48:08 -0700282 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
283 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 -0700284 }
285 }
286
287 // Set values.
288 for i := 0; i < want.Len(); i++ {
289 v := newListElement(fd, list, seed(i+10), nil)
290 want.Set(i, v)
291 list.Set(i, v)
Joe Tsai378c1322019-04-25 23:48:08 -0700292 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
293 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 -0700294 }
295 }
296
297 // Truncate.
298 for want.Len() > 0 {
299 n := want.Len() - 1
300 want.Truncate(n)
301 list.Truncate(n)
Damien Neild91246e2019-06-21 08:36:26 -0700302 if got, want := m.Has(fd), want.Len() > 0 || fd.IsExtension(); got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700303 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 -0700304 }
Joe Tsai378c1322019-04-25 23:48:08 -0700305 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
306 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 -0700307 }
308 }
309}
310
311type testList struct {
312 a []pref.Value
313}
314
315func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
316func (l *testList) Get(n int) pref.Value { return l.a[n] }
317func (l *testList) Len() int { return len(l.a) }
318func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
319func (l *testList) Truncate(n int) { l.a = l.a[:n] }
320func (l *testList) NewMessage() pref.Message { panic("unimplemented") }
Damien Neilf5274512019-08-05 10:48:38 -0700321func (l *testList) NewElement() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700322
323// testFieldFloat exercises some interesting floating-point scalar field values.
324func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700325 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700326 num := fd.Number()
327
Damien Neil5ec58b92019-04-30 11:36:39 -0700328 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
329 var val pref.Value
330 if fd.Kind() == pref.FloatKind {
331 val = pref.ValueOf(float32(v))
332 } else {
333 val = pref.ValueOf(v)
334 }
Joe Tsai378c1322019-04-25 23:48:08 -0700335 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700336 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700337 if got, want := m.Has(fd), true; got != want {
338 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 -0700339 }
Joe Tsai378c1322019-04-25 23:48:08 -0700340 if got, want := m.Get(fd), val; !valueEqual(got, want) {
341 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700342 }
343 }
344}
345
346// testOneof tests the behavior of fields in a oneof.
347func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neila3456c92019-04-30 11:36:49 -0700348 for _, mutable := range []bool{false, true} {
349 for i := 0; i < od.Fields().Len(); i++ {
350 fda := od.Fields().Get(i)
351 if mutable {
352 // Set fields by requesting a mutable reference.
353 if !fda.IsMap() && !fda.IsList() && fda.Message() == nil {
354 continue
355 }
356 _ = m.Mutable(fda)
357 } else {
358 // Set fields explicitly.
359 m.Set(fda, newValue(m, fda, 1, nil))
360 }
361 if got, want := m.WhichOneof(od), fda; got != want {
362 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
363 }
364 for j := 0; j < od.Fields().Len(); j++ {
365 fdb := od.Fields().Get(j)
366 if got, want := m.Has(fdb), i == j; got != want {
367 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
368 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700369 }
370 }
371 }
372}
373
Damien Neild91246e2019-06-21 08:36:26 -0700374// testUnknown tests the behavior of unknown fields.
375func testUnknown(t testing.TB, m pref.Message) {
376 var b []byte
377 b = wire.AppendTag(b, 1000, wire.VarintType)
378 b = wire.AppendVarint(b, 1001)
379 m.SetUnknown(pref.RawFields(b))
380 if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) {
381 t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want)
382 }
383}
384
Damien Neil5ec58b92019-04-30 11:36:39 -0700385func formatValue(v pref.Value) string {
386 switch v := v.Interface().(type) {
387 case pref.List:
388 var buf bytes.Buffer
389 buf.WriteString("list[")
390 for i := 0; i < v.Len(); i++ {
391 if i > 0 {
392 buf.WriteString(" ")
393 }
394 buf.WriteString(formatValue(v.Get(i)))
395 }
396 buf.WriteString("]")
397 return buf.String()
398 case pref.Map:
399 var buf bytes.Buffer
400 buf.WriteString("map[")
401 var keys []pref.MapKey
402 v.Range(func(k pref.MapKey, v pref.Value) bool {
403 keys = append(keys, k)
404 return true
405 })
406 sort.Slice(keys, func(i, j int) bool {
407 return keys[i].String() < keys[j].String()
408 })
409 for i, k := range keys {
410 if i > 0 {
411 buf.WriteString(" ")
412 }
413 buf.WriteString(formatValue(k.Value()))
414 buf.WriteString(":")
415 buf.WriteString(formatValue(v.Get(k)))
416 }
417 buf.WriteString("]")
418 return buf.String()
419 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700420 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700421 if err != nil {
422 return fmt.Sprintf("<%v>", err)
423 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700424 return fmt.Sprintf("%v{%v}", v.Descriptor().FullName(), string(b))
Damien Neil5ec58b92019-04-30 11:36:39 -0700425 case string:
426 return fmt.Sprintf("%q", v)
427 default:
428 return fmt.Sprint(v)
429 }
430}
431
432func valueEqual(a, b pref.Value) bool {
433 ai, bi := a.Interface(), b.Interface()
434 switch ai.(type) {
435 case pref.Message:
436 return proto.Equal(
437 a.Message().Interface(),
438 b.Message().Interface(),
439 )
440 case pref.List:
441 lista, listb := a.List(), b.List()
442 if lista.Len() != listb.Len() {
443 return false
444 }
445 for i := 0; i < lista.Len(); i++ {
446 if !valueEqual(lista.Get(i), listb.Get(i)) {
447 return false
448 }
449 }
450 return true
451 case pref.Map:
452 mapa, mapb := a.Map(), b.Map()
453 if mapa.Len() != mapb.Len() {
454 return false
455 }
456 equal := true
457 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
458 if !valueEqual(v, mapb.Get(k)) {
459 equal = false
460 return false
461 }
462 return true
463 })
464 return equal
465 case []byte:
466 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700467 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700468 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700469 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
470 case float64:
471 // NaNs are equal, but must be the same NaN.
472 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700473 default:
474 return ai == bi
475 }
476}
477
478// A seed is used to vary the content of a value.
479//
480// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
481// is unpopulated.
482//
483// A seed of minVal or maxVal is the least or greatest value of the value type.
484type seed int
485
486const (
487 minVal seed = -1
488 maxVal seed = -2
489)
490
Damien Neilf5274512019-08-05 10:48:38 -0700491// newSeed creates new seed values from a base, for example to create seeds for the
492// elements in a list. If the input seed is minVal or maxVal, so is the output.
493func newSeed(n seed, adjust ...int) seed {
494 switch n {
495 case minVal, maxVal:
496 return n
497 }
498 for _, a := range adjust {
499 n = 10*n + seed(a)
500 }
501 return n
502}
503
Damien Neil5ec58b92019-04-30 11:36:39 -0700504// newValue returns a new value assignable to a field.
505//
506// The stack parameter is used to avoid infinite recursion when populating circular
507// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700508func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700509 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700510 case fd.IsList():
Damien Neilf5274512019-08-05 10:48:38 -0700511 list := m.NewField(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700512 if n == 0 {
513 return pref.ValueOf(list)
514 }
515 list.Append(newListElement(fd, list, 0, stack))
516 list.Append(newListElement(fd, list, minVal, stack))
517 list.Append(newListElement(fd, list, maxVal, stack))
518 list.Append(newListElement(fd, list, n, stack))
519 return pref.ValueOf(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700520 case fd.IsMap():
Damien Neilf5274512019-08-05 10:48:38 -0700521 mapv := m.NewField(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700522 if n == 0 {
523 return pref.ValueOf(mapv)
524 }
525 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
526 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
527 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
Damien Neilf5274512019-08-05 10:48:38 -0700528 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700529 return pref.ValueOf(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700530 case fd.Message() != nil:
Damien Neilf5274512019-08-05 10:48:38 -0700531 return populateMessage(m.NewField(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700532 default:
533 return newScalarValue(fd, n)
534 }
535}
536
Joe Tsai0fc49f82019-05-01 12:29:25 -0700537func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700538 if fd.Message() == nil {
539 return newScalarValue(fd, n)
540 }
Damien Neilf5274512019-08-05 10:48:38 -0700541 return populateMessage(list.NewElement().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700542}
543
544func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700545 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700546 return newScalarValue(kd, n).MapKey()
547}
548
Joe Tsai0fc49f82019-05-01 12:29:25 -0700549func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700550 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700551 if vd.Message() == nil {
552 return newScalarValue(vd, n)
553 }
Damien Neilf5274512019-08-05 10:48:38 -0700554 return populateMessage(mapv.NewValue().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700555}
556
557func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
558 switch fd.Kind() {
559 case pref.BoolKind:
560 return pref.ValueOf(n != 0)
561 case pref.EnumKind:
Damien Neilf5274512019-08-05 10:48:38 -0700562 vals := fd.Enum().Values()
563 var i int
564 switch n {
565 case minVal:
566 i = 0
567 case maxVal:
568 i = vals.Len() - 1
569 default:
570 i = int(n) % vals.Len()
571 }
572 return pref.ValueOf(vals.Get(i).Number())
Damien Neil5ec58b92019-04-30 11:36:39 -0700573 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
574 switch n {
575 case minVal:
576 return pref.ValueOf(int32(math.MinInt32))
577 case maxVal:
578 return pref.ValueOf(int32(math.MaxInt32))
579 default:
580 return pref.ValueOf(int32(n))
581 }
582 case pref.Uint32Kind, pref.Fixed32Kind:
583 switch n {
584 case minVal:
585 // Only use 0 for the zero value.
586 return pref.ValueOf(uint32(1))
587 case maxVal:
588 return pref.ValueOf(uint32(math.MaxInt32))
589 default:
590 return pref.ValueOf(uint32(n))
591 }
592 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
593 switch n {
594 case minVal:
595 return pref.ValueOf(int64(math.MinInt64))
596 case maxVal:
597 return pref.ValueOf(int64(math.MaxInt64))
598 default:
599 return pref.ValueOf(int64(n))
600 }
601 case pref.Uint64Kind, pref.Fixed64Kind:
602 switch n {
603 case minVal:
604 // Only use 0 for the zero value.
605 return pref.ValueOf(uint64(1))
606 case maxVal:
607 return pref.ValueOf(uint64(math.MaxInt64))
608 default:
609 return pref.ValueOf(uint64(n))
610 }
611 case pref.FloatKind:
612 switch n {
613 case minVal:
614 return pref.ValueOf(float32(math.SmallestNonzeroFloat32))
615 case maxVal:
616 return pref.ValueOf(float32(math.MaxFloat32))
617 default:
618 return pref.ValueOf(1.5 * float32(n))
619 }
620 case pref.DoubleKind:
621 switch n {
622 case minVal:
623 return pref.ValueOf(float64(math.SmallestNonzeroFloat64))
624 case maxVal:
625 return pref.ValueOf(float64(math.MaxFloat64))
626 default:
627 return pref.ValueOf(1.5 * float64(n))
628 }
629 case pref.StringKind:
630 if n == 0 {
631 return pref.ValueOf("")
632 }
633 return pref.ValueOf(fmt.Sprintf("%d", n))
634 case pref.BytesKind:
635 if n == 0 {
636 return pref.ValueOf([]byte(nil))
637 }
638 return pref.ValueOf([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
639 }
640 panic("unhandled kind")
641}
642
Joe Tsai0fc49f82019-05-01 12:29:25 -0700643func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700644 if n == 0 {
645 return pref.ValueOf(m)
646 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700647 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700648 for _, x := range stack {
649 if md == x {
650 return pref.ValueOf(m)
651 }
652 }
653 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700654 for i := 0; i < md.Fields().Len(); i++ {
655 fd := md.Fields().Get(i)
656 if fd.IsWeak() {
657 continue
658 }
Damien Neilf5274512019-08-05 10:48:38 -0700659 m.Set(fd, newValue(m, fd, newSeed(n, i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700660 }
661 return pref.ValueOf(m)
662}
Damien Neild91246e2019-06-21 08:36:26 -0700663
664func panics(f func()) (didPanic bool) {
665 defer func() {
666 if err := recover(); err != nil {
667 didPanic = true
668 }
669 }()
670 f()
671 return false
672}