blob: 1ca4e36c5bcc61ee730146e8dc4e2b6e79d56fbf [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 Neil5c5b5312019-05-14 12:44:37 -070015 prototext "google.golang.org/protobuf/encoding/prototext"
Damien Neile89e6242019-05-13 23:55:40 -070016 "google.golang.org/protobuf/proto"
17 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neil5ec58b92019-04-30 11:36:39 -070018)
19
Joe Tsai378c1322019-04-25 23:48:08 -070020// TODO: Test read-only properties of unpopulated composite values.
21// TODO: Test invalid field descriptors or oneof descriptors.
22// TODO: This should test the functionality that can be provided by fast-paths.
Damien Neil5ec58b92019-04-30 11:36:39 -070023
Joe Tsai378c1322019-04-25 23:48:08 -070024// TestMessage runs the provided m through a series of tests
25// exercising the protobuf reflection API.
26func TestMessage(t testing.TB, m proto.Message) {
27 md := m.ProtoReflect().Descriptor()
28 m1 := m.ProtoReflect().New()
Damien Neil5ec58b92019-04-30 11:36:39 -070029 for i := 0; i < md.Fields().Len(); i++ {
30 fd := md.Fields().Get(i)
31 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -070032 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -070033 testFieldList(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070034 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -070035 testFieldMap(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070036 case fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind:
Joe Tsai378c1322019-04-25 23:48:08 -070037 testFieldFloat(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070038 }
Joe Tsai378c1322019-04-25 23:48:08 -070039 testField(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070040 }
41 for i := 0; i < md.Oneofs().Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070042 testOneof(t, m1, md.Oneofs().Get(i))
Damien Neil5ec58b92019-04-30 11:36:39 -070043 }
44
45 // TODO: Extensions, unknown fields.
46
47 // Test round-trip marshal/unmarshal.
Joe Tsai378c1322019-04-25 23:48:08 -070048 m2 := m.ProtoReflect().New().Interface()
49 populateMessage(m2.ProtoReflect(), 1, nil)
50 b, err := proto.Marshal(m2)
Damien Neil5ec58b92019-04-30 11:36:39 -070051 if err != nil {
Joe Tsai378c1322019-04-25 23:48:08 -070052 t.Errorf("Marshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070053 }
Joe Tsai378c1322019-04-25 23:48:08 -070054 m3 := m.ProtoReflect().New().Interface()
55 if err := proto.Unmarshal(b, m3); err != nil {
56 t.Errorf("Unmarshal() = %v, want nil\n%v", err, marshalText(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070057 }
Joe Tsai378c1322019-04-25 23:48:08 -070058 if !proto.Equal(m2, m3) {
59 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 -070060 }
61}
62
63func marshalText(m proto.Message) string {
Damien Neil5c5b5312019-05-14 12:44:37 -070064 b, _ := prototext.MarshalOptions{Indent: " "}.Marshal(m)
Damien Neil5ec58b92019-04-30 11:36:39 -070065 return string(b)
66}
67
Joe Tsai378c1322019-04-25 23:48:08 -070068// testField exercises set/get/has/clear of a field.
Damien Neil5ec58b92019-04-30 11:36:39 -070069func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -070070 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -070071 num := fd.Number()
Damien Neil5ec58b92019-04-30 11:36:39 -070072
73 // Set to a non-zero value, the zero value, different non-zero values.
74 for _, n := range []seed{1, 0, minVal, maxVal} {
75 v := newValue(m, fd, n, nil)
Joe Tsai378c1322019-04-25 23:48:08 -070076 m.Set(fd, v)
Damien Neil5ec58b92019-04-30 11:36:39 -070077 wantHas := true
78 if n == 0 {
79 if fd.Syntax() == pref.Proto3 && fd.Message() == nil {
80 wantHas = false
81 }
82 if fd.Cardinality() == pref.Repeated {
83 wantHas = false
84 }
Joe Tsaiac31a352019-05-13 14:32:56 -070085 if fd.ContainingOneof() != nil {
Damien Neil5ec58b92019-04-30 11:36:39 -070086 wantHas = true
87 }
88 }
Joe Tsai378c1322019-04-25 23:48:08 -070089 if got, want := m.Has(fd), wantHas; got != want {
90 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 -070091 }
Joe Tsai378c1322019-04-25 23:48:08 -070092 if got, want := m.Get(fd), v; !valueEqual(got, want) {
93 t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -070094 }
95 }
96
Joe Tsai378c1322019-04-25 23:48:08 -070097 m.Clear(fd)
98 if got, want := m.Has(fd), false; got != want {
99 t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700100 }
101 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700102 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700103 if got := m.Get(fd); got.List().Len() != 0 {
104 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700105 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700106 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700107 if got := m.Get(fd); got.Map().Len() != 0 {
108 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700109 }
Joe Tsai378c1322019-04-25 23:48:08 -0700110 case fd.Message() == nil:
111 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
112 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 -0700113 }
114 }
115}
116
117// testFieldMap tests set/get/has/clear of entries in a map field.
118func testFieldMap(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700119 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700120 num := fd.Number()
121
122 m.Clear(fd) // start with an empty map
123 mapv := m.Mutable(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700124
125 // Add values.
126 want := make(testMap)
127 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700128 if got, want := m.Has(fd), i > 0; got != want {
129 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 -0700130 }
131
132 k := newMapKey(fd, n)
133 v := newMapValue(fd, mapv, n, nil)
134 mapv.Set(k, v)
135 want.Set(k, v)
Joe Tsai378c1322019-04-25 23:48:08 -0700136 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
137 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 -0700138 }
139 }
140
141 // Set values.
142 want.Range(func(k pref.MapKey, v pref.Value) bool {
143 nv := newMapValue(fd, mapv, 10, nil)
144 mapv.Set(k, nv)
145 want.Set(k, nv)
Joe Tsai378c1322019-04-25 23:48:08 -0700146 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
147 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 -0700148 }
149 return true
150 })
151
152 // Clear values.
153 want.Range(func(k pref.MapKey, v pref.Value) bool {
154 mapv.Clear(k)
155 want.Clear(k)
Joe Tsai378c1322019-04-25 23:48:08 -0700156 if got, want := m.Has(fd), want.Len() > 0; got != want {
157 t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700158 }
Joe Tsai378c1322019-04-25 23:48:08 -0700159 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
160 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 -0700161 }
162 return true
163 })
164
165 // Non-existent map keys.
166 missingKey := newMapKey(fd, 1)
167 if got, want := mapv.Has(missingKey), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700168 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 -0700169 }
170 if got, want := mapv.Get(missingKey).IsValid(), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700171 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 -0700172 }
173 mapv.Clear(missingKey) // noop
174}
175
176type testMap map[interface{}]pref.Value
177
178func (m testMap) Get(k pref.MapKey) pref.Value { return m[k.Interface()] }
179func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
180func (m testMap) Has(k pref.MapKey) bool { return m.Get(k).IsValid() }
181func (m testMap) Clear(k pref.MapKey) { delete(m, k.Interface()) }
182func (m testMap) Len() int { return len(m) }
183func (m testMap) NewMessage() pref.Message { panic("unimplemented") }
184func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
185 for k, v := range m {
186 if !f(pref.ValueOf(k).MapKey(), v) {
187 return
188 }
189 }
190}
191
192// testFieldList exercises set/get/append/truncate of values in a list.
193func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700194 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700195 num := fd.Number()
196
197 m.Clear(fd) // start with an empty list
198 list := m.Mutable(fd).List()
Damien Neil5ec58b92019-04-30 11:36:39 -0700199
200 // Append values.
201 var want pref.List = &testList{}
202 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700203 if got, want := m.Has(fd), i > 0; got != want {
204 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 -0700205 }
206 v := newListElement(fd, list, n, nil)
207 want.Append(v)
208 list.Append(v)
209
Joe Tsai378c1322019-04-25 23:48:08 -0700210 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
211 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 -0700212 }
213 }
214
215 // Set values.
216 for i := 0; i < want.Len(); i++ {
217 v := newListElement(fd, list, seed(i+10), nil)
218 want.Set(i, v)
219 list.Set(i, v)
Joe Tsai378c1322019-04-25 23:48:08 -0700220 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
221 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 -0700222 }
223 }
224
225 // Truncate.
226 for want.Len() > 0 {
227 n := want.Len() - 1
228 want.Truncate(n)
229 list.Truncate(n)
Joe Tsai378c1322019-04-25 23:48:08 -0700230 if got, want := m.Has(fd), want.Len() > 0; got != want {
231 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 -0700232 }
Joe Tsai378c1322019-04-25 23:48:08 -0700233 if got, want := m.Get(fd), pref.ValueOf(want); !valueEqual(got, want) {
234 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 -0700235 }
236 }
237}
238
239type testList struct {
240 a []pref.Value
241}
242
243func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
244func (l *testList) Get(n int) pref.Value { return l.a[n] }
245func (l *testList) Len() int { return len(l.a) }
246func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
247func (l *testList) Truncate(n int) { l.a = l.a[:n] }
248func (l *testList) NewMessage() pref.Message { panic("unimplemented") }
249
250// testFieldFloat exercises some interesting floating-point scalar field values.
251func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700252 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700253 num := fd.Number()
254
Damien Neil5ec58b92019-04-30 11:36:39 -0700255 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
256 var val pref.Value
257 if fd.Kind() == pref.FloatKind {
258 val = pref.ValueOf(float32(v))
259 } else {
260 val = pref.ValueOf(v)
261 }
Joe Tsai378c1322019-04-25 23:48:08 -0700262 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700263 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700264 if got, want := m.Has(fd), true; got != want {
265 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 -0700266 }
Joe Tsai378c1322019-04-25 23:48:08 -0700267 if got, want := m.Get(fd), val; !valueEqual(got, want) {
268 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700269 }
270 }
271}
272
273// testOneof tests the behavior of fields in a oneof.
274func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700275 for i := 0; i < od.Fields().Len(); i++ {
276 fda := od.Fields().Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -0700277 m.Set(fda, newValue(m, fda, 1, nil))
278 if got, want := m.WhichOneof(od), fda; got != want {
Damien Neil5ec58b92019-04-30 11:36:39 -0700279 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
280 }
281 for j := 0; j < od.Fields().Len(); j++ {
282 fdb := od.Fields().Get(j)
Joe Tsai378c1322019-04-25 23:48:08 -0700283 if got, want := m.Has(fdb), i == j; got != want {
Damien Neil5ec58b92019-04-30 11:36:39 -0700284 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
285 }
286 }
287 }
288}
289
290func formatValue(v pref.Value) string {
291 switch v := v.Interface().(type) {
292 case pref.List:
293 var buf bytes.Buffer
294 buf.WriteString("list[")
295 for i := 0; i < v.Len(); i++ {
296 if i > 0 {
297 buf.WriteString(" ")
298 }
299 buf.WriteString(formatValue(v.Get(i)))
300 }
301 buf.WriteString("]")
302 return buf.String()
303 case pref.Map:
304 var buf bytes.Buffer
305 buf.WriteString("map[")
306 var keys []pref.MapKey
307 v.Range(func(k pref.MapKey, v pref.Value) bool {
308 keys = append(keys, k)
309 return true
310 })
311 sort.Slice(keys, func(i, j int) bool {
312 return keys[i].String() < keys[j].String()
313 })
314 for i, k := range keys {
315 if i > 0 {
316 buf.WriteString(" ")
317 }
318 buf.WriteString(formatValue(k.Value()))
319 buf.WriteString(":")
320 buf.WriteString(formatValue(v.Get(k)))
321 }
322 buf.WriteString("]")
323 return buf.String()
324 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700325 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700326 if err != nil {
327 return fmt.Sprintf("<%v>", err)
328 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700329 return fmt.Sprintf("%v{%v}", v.Descriptor().FullName(), string(b))
Damien Neil5ec58b92019-04-30 11:36:39 -0700330 case string:
331 return fmt.Sprintf("%q", v)
332 default:
333 return fmt.Sprint(v)
334 }
335}
336
337func valueEqual(a, b pref.Value) bool {
338 ai, bi := a.Interface(), b.Interface()
339 switch ai.(type) {
340 case pref.Message:
341 return proto.Equal(
342 a.Message().Interface(),
343 b.Message().Interface(),
344 )
345 case pref.List:
346 lista, listb := a.List(), b.List()
347 if lista.Len() != listb.Len() {
348 return false
349 }
350 for i := 0; i < lista.Len(); i++ {
351 if !valueEqual(lista.Get(i), listb.Get(i)) {
352 return false
353 }
354 }
355 return true
356 case pref.Map:
357 mapa, mapb := a.Map(), b.Map()
358 if mapa.Len() != mapb.Len() {
359 return false
360 }
361 equal := true
362 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
363 if !valueEqual(v, mapb.Get(k)) {
364 equal = false
365 return false
366 }
367 return true
368 })
369 return equal
370 case []byte:
371 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700372 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700373 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700374 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
375 case float64:
376 // NaNs are equal, but must be the same NaN.
377 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700378 default:
379 return ai == bi
380 }
381}
382
383// A seed is used to vary the content of a value.
384//
385// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
386// is unpopulated.
387//
388// A seed of minVal or maxVal is the least or greatest value of the value type.
389type seed int
390
391const (
392 minVal seed = -1
393 maxVal seed = -2
394)
395
396// newValue returns a new value assignable to a field.
397//
398// The stack parameter is used to avoid infinite recursion when populating circular
399// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700400func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700401 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700402 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700403 list := m.New().Mutable(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700404 if n == 0 {
405 return pref.ValueOf(list)
406 }
407 list.Append(newListElement(fd, list, 0, stack))
408 list.Append(newListElement(fd, list, minVal, stack))
409 list.Append(newListElement(fd, list, maxVal, stack))
410 list.Append(newListElement(fd, list, n, stack))
411 return pref.ValueOf(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700412 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700413 mapv := m.New().Mutable(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700414 if n == 0 {
415 return pref.ValueOf(mapv)
416 }
417 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
418 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
419 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
420 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, 10*n, stack))
421 return pref.ValueOf(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700422 case fd.Message() != nil:
Joe Tsai378c1322019-04-25 23:48:08 -0700423 return populateMessage(m.Mutable(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700424 default:
425 return newScalarValue(fd, n)
426 }
427}
428
Joe Tsai0fc49f82019-05-01 12:29:25 -0700429func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700430 if fd.Message() == nil {
431 return newScalarValue(fd, n)
432 }
433 return populateMessage(list.NewMessage(), n, stack)
434}
435
436func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700437 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700438 return newScalarValue(kd, n).MapKey()
439}
440
Joe Tsai0fc49f82019-05-01 12:29:25 -0700441func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700442 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700443 if vd.Message() == nil {
444 return newScalarValue(vd, n)
445 }
446 return populateMessage(mapv.NewMessage(), n, stack)
447}
448
449func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
450 switch fd.Kind() {
451 case pref.BoolKind:
452 return pref.ValueOf(n != 0)
453 case pref.EnumKind:
Joe Tsai378c1322019-04-25 23:48:08 -0700454 // TODO: use actual value
Damien Neil5ec58b92019-04-30 11:36:39 -0700455 return pref.ValueOf(pref.EnumNumber(n))
456 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
457 switch n {
458 case minVal:
459 return pref.ValueOf(int32(math.MinInt32))
460 case maxVal:
461 return pref.ValueOf(int32(math.MaxInt32))
462 default:
463 return pref.ValueOf(int32(n))
464 }
465 case pref.Uint32Kind, pref.Fixed32Kind:
466 switch n {
467 case minVal:
468 // Only use 0 for the zero value.
469 return pref.ValueOf(uint32(1))
470 case maxVal:
471 return pref.ValueOf(uint32(math.MaxInt32))
472 default:
473 return pref.ValueOf(uint32(n))
474 }
475 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
476 switch n {
477 case minVal:
478 return pref.ValueOf(int64(math.MinInt64))
479 case maxVal:
480 return pref.ValueOf(int64(math.MaxInt64))
481 default:
482 return pref.ValueOf(int64(n))
483 }
484 case pref.Uint64Kind, pref.Fixed64Kind:
485 switch n {
486 case minVal:
487 // Only use 0 for the zero value.
488 return pref.ValueOf(uint64(1))
489 case maxVal:
490 return pref.ValueOf(uint64(math.MaxInt64))
491 default:
492 return pref.ValueOf(uint64(n))
493 }
494 case pref.FloatKind:
495 switch n {
496 case minVal:
497 return pref.ValueOf(float32(math.SmallestNonzeroFloat32))
498 case maxVal:
499 return pref.ValueOf(float32(math.MaxFloat32))
500 default:
501 return pref.ValueOf(1.5 * float32(n))
502 }
503 case pref.DoubleKind:
504 switch n {
505 case minVal:
506 return pref.ValueOf(float64(math.SmallestNonzeroFloat64))
507 case maxVal:
508 return pref.ValueOf(float64(math.MaxFloat64))
509 default:
510 return pref.ValueOf(1.5 * float64(n))
511 }
512 case pref.StringKind:
513 if n == 0 {
514 return pref.ValueOf("")
515 }
516 return pref.ValueOf(fmt.Sprintf("%d", n))
517 case pref.BytesKind:
518 if n == 0 {
519 return pref.ValueOf([]byte(nil))
520 }
521 return pref.ValueOf([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
522 }
523 panic("unhandled kind")
524}
525
Joe Tsai0fc49f82019-05-01 12:29:25 -0700526func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700527 if n == 0 {
528 return pref.ValueOf(m)
529 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700530 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700531 for _, x := range stack {
532 if md == x {
533 return pref.ValueOf(m)
534 }
535 }
536 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700537 for i := 0; i < md.Fields().Len(); i++ {
538 fd := md.Fields().Get(i)
539 if fd.IsWeak() {
540 continue
541 }
Joe Tsai378c1322019-04-25 23:48:08 -0700542 m.Set(fd, newValue(m, fd, 10*n+seed(i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700543 }
544 return pref.ValueOf(m)
545}