blob: c104605fae513015e27e80b14ef89afd42fb2aba [file] [log] [blame]
Damien Neil5ec58b92019-04-30 11:36:39 -07001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package prototest exercises protobuf reflection.
6package prototest
7
8import (
9 "bytes"
10 "fmt"
11 "math"
Joe Tsaib7695fa2020-01-04 09:09:04 -080012 "reflect"
Damien Neil5ec58b92019-04-30 11:36:39 -070013 "sort"
Joe Tsai1a290e92020-06-05 15:31:25 -070014 "strings"
Damien Neil5ec58b92019-04-30 11:36:39 -070015 "testing"
16
Damien Neild91246e2019-06-21 08:36:26 -070017 "google.golang.org/protobuf/encoding/prototext"
Joe Tsaicd108d02020-02-14 18:08:02 -080018 "google.golang.org/protobuf/encoding/protowire"
Damien Neile89e6242019-05-13 23:55:40 -070019 "google.golang.org/protobuf/proto"
Joe Tsai1a290e92020-06-05 15:31:25 -070020 "google.golang.org/protobuf/reflect/protoreflect"
Damien Neile89e6242019-05-13 23:55:40 -070021 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neil56786dc2020-02-11 16:43:13 -080022 "google.golang.org/protobuf/reflect/protoregistry"
Damien Neil5ec58b92019-04-30 11:36:39 -070023)
24
Joe Tsai378c1322019-04-25 23:48:08 -070025// TODO: Test invalid field descriptors or oneof descriptors.
26// TODO: This should test the functionality that can be provided by fast-paths.
Damien Neil5ec58b92019-04-30 11:36:39 -070027
Damien Neil56786dc2020-02-11 16:43:13 -080028// Message tests a message implemention.
29type Message struct {
30 // Resolver is used to determine the list of extension fields to test with.
Damien Neil290ceea2019-07-15 13:39:43 -070031 // If nil, this defaults to using protoregistry.GlobalTypes.
32 Resolver interface {
Damien Neil56786dc2020-02-11 16:43:13 -080033 FindExtensionByName(field pref.FullName) (pref.ExtensionType, error)
34 FindExtensionByNumber(message pref.FullName, field pref.FieldNumber) (pref.ExtensionType, error)
35 RangeExtensionsByMessage(message pref.FullName, f func(pref.ExtensionType) bool)
Damien Neil290ceea2019-07-15 13:39:43 -070036 }
Damien Neild91246e2019-06-21 08:36:26 -070037}
38
Damien Neil56786dc2020-02-11 16:43:13 -080039// Test performs tests on a MessageType implementation.
40func (test Message) Test(t testing.TB, mt pref.MessageType) {
41 testType(t, mt)
Joe Tsai93bccf72020-02-10 11:14:03 -080042
Damien Neil56786dc2020-02-11 16:43:13 -080043 md := mt.Descriptor()
44 m1 := mt.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 Neil56786dc2020-02-11 16:43:13 -080049 if test.Resolver == nil {
50 test.Resolver = protoregistry.GlobalTypes
Damien Neild91246e2019-06-21 08:36:26 -070051 }
Damien Neil56786dc2020-02-11 16:43:13 -080052 var extTypes []pref.ExtensionType
53 test.Resolver.RangeExtensionsByMessage(md.FullName(), func(e pref.ExtensionType) bool {
54 extTypes = append(extTypes, e)
55 return true
56 })
57 for _, xt := range extTypes {
Damien Neil79bfdbe2019-08-28 11:08:22 -070058 testField(t, m1, xt.TypeDescriptor())
Damien Neild91246e2019-06-21 08:36:26 -070059 }
Damien Neil5ec58b92019-04-30 11:36:39 -070060 for i := 0; i < md.Oneofs().Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070061 testOneof(t, m1, md.Oneofs().Get(i))
Damien Neil5ec58b92019-04-30 11:36:39 -070062 }
Damien Neild91246e2019-06-21 08:36:26 -070063 testUnknown(t, m1)
Damien Neil5ec58b92019-04-30 11:36:39 -070064
65 // Test round-trip marshal/unmarshal.
Damien Neil56786dc2020-02-11 16:43:13 -080066 m2 := mt.New().Interface()
Joe Tsai378c1322019-04-25 23:48:08 -070067 populateMessage(m2.ProtoReflect(), 1, nil)
Damien Neil56786dc2020-02-11 16:43:13 -080068 for _, xt := range extTypes {
Damien Neil290ceea2019-07-15 13:39:43 -070069 m2.ProtoReflect().Set(xt.TypeDescriptor(), newValue(m2.ProtoReflect(), xt.TypeDescriptor(), 1, nil))
70 }
71 b, err := proto.MarshalOptions{
72 AllowPartial: true,
73 }.Marshal(m2)
Damien Neil5ec58b92019-04-30 11:36:39 -070074 if err != nil {
Joe Tsai74b14602020-01-06 15:44:09 -080075 t.Errorf("Marshal() = %v, want nil\n%v", err, prototext.Format(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070076 }
Damien Neil56786dc2020-02-11 16:43:13 -080077 m3 := mt.New().Interface()
Damien Neil290ceea2019-07-15 13:39:43 -070078 if err := (proto.UnmarshalOptions{
79 AllowPartial: true,
Damien Neil56786dc2020-02-11 16:43:13 -080080 Resolver: test.Resolver,
Damien Neil290ceea2019-07-15 13:39:43 -070081 }.Unmarshal(b, m3)); err != nil {
Joe Tsai74b14602020-01-06 15:44:09 -080082 t.Errorf("Unmarshal() = %v, want nil\n%v", err, prototext.Format(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070083 }
Joe Tsai378c1322019-04-25 23:48:08 -070084 if !proto.Equal(m2, m3) {
Joe Tsai74b14602020-01-06 15:44:09 -080085 t.Errorf("round-trip marshal/unmarshal did not preserve message\nOriginal:\n%v\nNew:\n%v", prototext.Format(m2), prototext.Format(m3))
Damien Neil5ec58b92019-04-30 11:36:39 -070086 }
87}
88
Damien Neil56786dc2020-02-11 16:43:13 -080089func testType(t testing.TB, mt pref.MessageType) {
90 m := mt.New().Interface()
Joe Tsaib7695fa2020-01-04 09:09:04 -080091 want := reflect.TypeOf(m)
92 if got := reflect.TypeOf(m.ProtoReflect().Interface()); got != want {
93 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Interface()): %v != %v", got, want)
94 }
95 if got := reflect.TypeOf(m.ProtoReflect().New().Interface()); got != want {
96 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().New().Interface()): %v != %v", got, want)
97 }
98 if got := reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()); got != want {
99 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()): %v != %v", got, want)
100 }
Joe Tsai1a290e92020-06-05 15:31:25 -0700101 if mt, ok := mt.(pref.MessageFieldTypes); ok {
102 testFieldTypes(t, mt)
103 }
104}
105
106func testFieldTypes(t testing.TB, mt pref.MessageFieldTypes) {
107 descName := func(d pref.Descriptor) pref.FullName {
108 if d == nil {
109 return "<nil>"
110 }
111 return d.FullName()
112 }
113 typeName := func(mt pref.MessageType) pref.FullName {
114 if mt == nil {
115 return "<nil>"
116 }
117 return mt.Descriptor().FullName()
118 }
119 adjustExpr := func(idx int, expr string) string {
120 expr = strings.Replace(expr, "fd.", "md.Fields().Get(i).", -1)
121 expr = strings.Replace(expr, "(fd)", "(md.Fields().Get(i))", -1)
122 expr = strings.Replace(expr, "mti.", "mt.Message(i).", -1)
123 expr = strings.Replace(expr, "(i)", fmt.Sprintf("(%d)", idx), -1)
124 return expr
125 }
126 checkEnumDesc := func(idx int, gotExpr, wantExpr string, got, want protoreflect.EnumDescriptor) {
127 if got != want {
128 t.Errorf("descriptor mismatch: %v != %v: %v != %v", adjustExpr(idx, gotExpr), adjustExpr(idx, wantExpr), descName(got), descName(want))
129 }
130 }
131 checkMessageDesc := func(idx int, gotExpr, wantExpr string, got, want protoreflect.MessageDescriptor) {
132 if got != want {
133 t.Errorf("descriptor mismatch: %v != %v: %v != %v", adjustExpr(idx, gotExpr), adjustExpr(idx, wantExpr), descName(got), descName(want))
134 }
135 }
136 checkMessageType := func(idx int, gotExpr, wantExpr string, got, want protoreflect.MessageType) {
137 if got != want {
138 t.Errorf("type mismatch: %v != %v: %v != %v", adjustExpr(idx, gotExpr), adjustExpr(idx, wantExpr), typeName(got), typeName(want))
139 }
140 }
141
142 fds := mt.Descriptor().Fields()
143 m := mt.New()
144 for i := 0; i < fds.Len(); i++ {
145 fd := fds.Get(i)
146 switch {
147 case fd.IsList():
148 if fd.Enum() != nil {
149 checkEnumDesc(i,
150 "mt.Enum(i).Descriptor()", "fd.Enum()",
151 mt.Enum(i).Descriptor(), fd.Enum())
152 }
153 if fd.Message() != nil {
154 checkMessageDesc(i,
155 "mt.Message(i).Descriptor()", "fd.Message()",
156 mt.Message(i).Descriptor(), fd.Message())
157 checkMessageType(i,
158 "mt.Message(i)", "m.NewField(fd).List().NewElement().Message().Type()",
159 mt.Message(i), m.NewField(fd).List().NewElement().Message().Type())
160 }
161 case fd.IsMap():
162 mti := mt.Message(i)
163 if m := mti.New(); m != nil {
164 checkMessageDesc(i,
165 "m.Descriptor()", "fd.Message()",
166 m.Descriptor(), fd.Message())
167 }
168 if m := mti.Zero(); m != nil {
169 checkMessageDesc(i,
170 "m.Descriptor()", "fd.Message()",
171 m.Descriptor(), fd.Message())
172 }
173 checkMessageDesc(i,
174 "mti.Descriptor()", "fd.Message()",
175 mti.Descriptor(), fd.Message())
176 if mti := mti.(pref.MessageFieldTypes); mti != nil {
177 if fd.MapValue().Enum() != nil {
178 checkEnumDesc(i,
179 "mti.Enum(fd.MapValue().Index()).Descriptor()", "fd.MapValue().Enum()",
180 mti.Enum(fd.MapValue().Index()).Descriptor(), fd.MapValue().Enum())
181 }
182 if fd.MapValue().Message() != nil {
183 checkMessageDesc(i,
184 "mti.Message(fd.MapValue().Index()).Descriptor()", "fd.MapValue().Message()",
185 mti.Message(fd.MapValue().Index()).Descriptor(), fd.MapValue().Message())
186 checkMessageType(i,
187 "mti.Message(fd.MapValue().Index())", "m.NewField(fd).Map().NewValue().Message().Type()",
188 mti.Message(fd.MapValue().Index()), m.NewField(fd).Map().NewValue().Message().Type())
189 }
190 }
191 default:
192 if fd.Enum() != nil {
193 checkEnumDesc(i,
194 "mt.Enum(i).Descriptor()", "fd.Enum()",
195 mt.Enum(i).Descriptor(), fd.Enum())
196 }
197 if fd.Message() != nil {
198 checkMessageDesc(i,
199 "mt.Message(i).Descriptor()", "fd.Message()",
200 mt.Message(i).Descriptor(), fd.Message())
201 checkMessageType(i,
202 "mt.Message(i)", "m.NewField(fd).Message().Type()",
203 mt.Message(i), m.NewField(fd).Message().Type())
204 }
205 }
206 }
Joe Tsaib7695fa2020-01-04 09:09:04 -0800207}
208
Joe Tsai378c1322019-04-25 23:48:08 -0700209// testField exercises set/get/has/clear of a field.
Damien Neil5ec58b92019-04-30 11:36:39 -0700210func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700211 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700212 num := fd.Number()
Damien Neil5ec58b92019-04-30 11:36:39 -0700213
Damien Neild91246e2019-06-21 08:36:26 -0700214 switch {
215 case fd.IsList():
216 testFieldList(t, m, fd)
217 case fd.IsMap():
218 testFieldMap(t, m, fd)
Damien Neilf5274512019-08-05 10:48:38 -0700219 case fd.Message() != nil:
220 default:
221 if got, want := m.NewField(fd), fd.Default(); !valueEqual(got, want) {
222 t.Errorf("Message.NewField(%v) = %v, want default value %v", name, formatValue(got), formatValue(want))
223 }
224 if fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind {
225 testFieldFloat(t, m, fd)
226 }
Damien Neild91246e2019-06-21 08:36:26 -0700227 }
228
Damien Neil5ec58b92019-04-30 11:36:39 -0700229 // Set to a non-zero value, the zero value, different non-zero values.
230 for _, n := range []seed{1, 0, minVal, maxVal} {
231 v := newValue(m, fd, n, nil)
Joe Tsai378c1322019-04-25 23:48:08 -0700232 m.Set(fd, v)
Damien Neil5ec58b92019-04-30 11:36:39 -0700233 wantHas := true
234 if n == 0 {
235 if fd.Syntax() == pref.Proto3 && fd.Message() == nil {
236 wantHas = false
237 }
Damien Neild91246e2019-06-21 08:36:26 -0700238 if fd.IsExtension() {
239 wantHas = true
240 }
Damien Neila0a54b82019-11-01 15:18:36 -0700241 if fd.Cardinality() == pref.Repeated {
242 wantHas = false
243 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700244 if fd.ContainingOneof() != nil {
Damien Neil5ec58b92019-04-30 11:36:39 -0700245 wantHas = true
246 }
247 }
Damien Neilf5274512019-08-05 10:48:38 -0700248 if fd.Syntax() == pref.Proto3 && fd.Cardinality() != pref.Repeated && fd.ContainingOneof() == nil && fd.Kind() == pref.EnumKind && v.Enum() == 0 {
249 wantHas = false
250 }
Joe Tsai378c1322019-04-25 23:48:08 -0700251 if got, want := m.Has(fd), wantHas; got != want {
252 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 -0700253 }
Joe Tsai378c1322019-04-25 23:48:08 -0700254 if got, want := m.Get(fd), v; !valueEqual(got, want) {
255 t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700256 }
Damien Neild91246e2019-06-21 08:36:26 -0700257 found := false
258 m.Range(func(d pref.FieldDescriptor, got pref.Value) bool {
259 if fd != d {
260 return true
261 }
262 found = true
263 if want := v; !valueEqual(got, want) {
264 t.Errorf("after setting %q:\nMessage.Range got value %v, want %v", name, formatValue(got), formatValue(want))
265 }
266 return true
267 })
268 if got, want := wantHas, found; got != want {
269 t.Errorf("after setting %q:\nMessageRange saw field: %v, want %v", name, got, want)
270 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700271 }
272
Joe Tsai378c1322019-04-25 23:48:08 -0700273 m.Clear(fd)
274 if got, want := m.Has(fd), false; got != want {
275 t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700276 }
277 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700278 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700279 if got := m.Get(fd); got.List().Len() != 0 {
280 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700281 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700282 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700283 if got := m.Get(fd); got.Map().Len() != 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700284 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty map", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700285 }
Joe Tsai378c1322019-04-25 23:48:08 -0700286 case fd.Message() == nil:
287 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
288 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 -0700289 }
290 }
Damien Neild91246e2019-06-21 08:36:26 -0700291
Damien Neil290ceea2019-07-15 13:39:43 -0700292 // Set to the default value.
293 switch {
294 case fd.IsList() || fd.IsMap():
Damien Neil9f1165c2019-11-26 13:31:38 -0800295 m.Set(fd, m.Mutable(fd))
Damien Neila0a54b82019-11-01 15:18:36 -0700296 if got, want := m.Has(fd), (fd.IsExtension() && fd.Cardinality() != pref.Repeated) || fd.ContainingOneof() != nil; got != want {
Damien Neil290ceea2019-07-15 13:39:43 -0700297 t.Errorf("after setting %q to default:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
298 }
299 case fd.Message() == nil:
300 m.Set(fd, m.Get(fd))
301 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
302 t.Errorf("after setting %q to default:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want))
303 }
304 }
305 m.Clear(fd)
306
Damien Neild91246e2019-06-21 08:36:26 -0700307 // Set to the wrong type.
Joe Tsai84177c92019-09-17 13:38:48 -0700308 v := pref.ValueOfString("")
Damien Neild91246e2019-06-21 08:36:26 -0700309 if fd.Kind() == pref.StringKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700310 v = pref.ValueOfInt32(0)
Damien Neild91246e2019-06-21 08:36:26 -0700311 }
312 if !panics(func() {
313 m.Set(fd, v)
314 }) {
315 t.Errorf("setting %v to %T succeeds, want panic", name, v.Interface())
316 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700317}
318
319// testFieldMap tests set/get/has/clear of entries in a map field.
320func testFieldMap(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700321 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700322 num := fd.Number()
323
Damien Neilf5274512019-08-05 10:48:38 -0700324 // New values.
Joe Tsai378c1322019-04-25 23:48:08 -0700325 m.Clear(fd) // start with an empty map
Damien Neilf5274512019-08-05 10:48:38 -0700326 mapv := m.Get(fd).Map()
Damien Neil9f1165c2019-11-26 13:31:38 -0800327 if mapv.IsValid() {
328 t.Errorf("after clearing field: message.Get(%v).IsValid() = true, want false", name)
329 }
Damien Neilf5274512019-08-05 10:48:38 -0700330 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
331 t.Errorf("message.Get(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
332 }
Damien Neil9f1165c2019-11-26 13:31:38 -0800333 if !panics(func() {
334 m.Set(fd, pref.ValueOfMap(mapv))
335 }) {
336 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
337 }
338 if !panics(func() {
339 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, nil))
340 }) {
341 t.Errorf("message.Get(%v).Set(...) of invalid map does not panic", name)
342 }
Damien Neilf5274512019-08-05 10:48:38 -0700343 mapv = m.Mutable(fd).Map() // mutable map
Damien Neil9f1165c2019-11-26 13:31:38 -0800344 if !mapv.IsValid() {
345 t.Errorf("message.Mutable(%v).IsValid() = false, want true", name)
346 }
Damien Neilf5274512019-08-05 10:48:38 -0700347 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
348 t.Errorf("message.Mutable(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
349 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700350
351 // Add values.
352 want := make(testMap)
353 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700354 if got, want := m.Has(fd), i > 0; got != want {
355 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 -0700356 }
357
358 k := newMapKey(fd, n)
359 v := newMapValue(fd, mapv, n, nil)
360 mapv.Set(k, v)
361 want.Set(k, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700362 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700363 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 -0700364 }
365 }
366
367 // Set values.
368 want.Range(func(k pref.MapKey, v pref.Value) bool {
369 nv := newMapValue(fd, mapv, 10, nil)
370 mapv.Set(k, nv)
371 want.Set(k, nv)
Joe Tsai84177c92019-09-17 13:38:48 -0700372 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700373 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 -0700374 }
375 return true
376 })
377
378 // Clear values.
379 want.Range(func(k pref.MapKey, v pref.Value) bool {
380 mapv.Clear(k)
381 want.Clear(k)
Joe Tsai378c1322019-04-25 23:48:08 -0700382 if got, want := m.Has(fd), want.Len() > 0; got != want {
383 t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700384 }
Joe Tsai84177c92019-09-17 13:38:48 -0700385 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700386 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 -0700387 }
388 return true
389 })
Damien Neil9f1165c2019-11-26 13:31:38 -0800390 if mapv := m.Get(fd).Map(); mapv.IsValid() {
391 t.Errorf("after clearing all elements: message.Get(%v).IsValid() = true, want false %v", name, formatValue(pref.ValueOfMap(mapv)))
392 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700393
394 // Non-existent map keys.
395 missingKey := newMapKey(fd, 1)
396 if got, want := mapv.Has(missingKey), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700397 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 -0700398 }
399 if got, want := mapv.Get(missingKey).IsValid(), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700400 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 -0700401 }
402 mapv.Clear(missingKey) // noop
Damien Neil3dbd95a2020-02-19 10:48:36 -0800403
404 // Mutable.
405 if fd.MapValue().Message() == nil {
406 if !panics(func() {
407 mapv.Mutable(newMapKey(fd, 1))
408 }) {
409 t.Errorf("Mutable on %q succeeds, want panic", name)
410 }
411 } else {
412 k := newMapKey(fd, 1)
413 v := mapv.Mutable(k)
414 if got, want := mapv.Len(), 1; got != want {
415 t.Errorf("after Mutable on %q, Map.Len() = %v, want %v", name, got, want)
416 }
417 populateMessage(v.Message(), 1, nil)
418 if !valueEqual(mapv.Get(k), v) {
419 t.Errorf("after Mutable on %q, changing new mutable value does not change map entry", name)
420 }
421 mapv.Clear(k)
422 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700423}
424
425type testMap map[interface{}]pref.Value
426
Damien Neil3dbd95a2020-02-19 10:48:36 -0800427func (m testMap) Get(k pref.MapKey) pref.Value { return m[k.Interface()] }
428func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
429func (m testMap) Has(k pref.MapKey) bool { return m.Get(k).IsValid() }
430func (m testMap) Clear(k pref.MapKey) { delete(m, k.Interface()) }
431func (m testMap) Mutable(k pref.MapKey) pref.Value { panic("unimplemented") }
432func (m testMap) Len() int { return len(m) }
433func (m testMap) NewValue() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700434func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
435 for k, v := range m {
436 if !f(pref.ValueOf(k).MapKey(), v) {
437 return
438 }
439 }
440}
Damien Neil82886da2019-11-26 13:27:24 -0800441func (m testMap) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700442
443// testFieldList exercises set/get/append/truncate of values in a list.
444func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700445 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700446 num := fd.Number()
447
448 m.Clear(fd) // start with an empty list
Damien Neilf5274512019-08-05 10:48:38 -0700449 list := m.Get(fd).List()
Damien Neil9f1165c2019-11-26 13:31:38 -0800450 if list.IsValid() {
451 t.Errorf("message.Get(%v).IsValid() = true, want false", name)
452 }
453 if !panics(func() {
454 m.Set(fd, pref.ValueOfList(list))
455 }) {
456 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
457 }
458 if !panics(func() {
459 list.Append(newListElement(fd, list, 0, nil))
460 }) {
461 t.Errorf("message.Get(%v).Append(...) of invalid list does not panic", name)
462 }
Damien Neilf5274512019-08-05 10:48:38 -0700463 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
464 t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
465 }
466 list = m.Mutable(fd).List() // mutable list
Damien Neil9f1165c2019-11-26 13:31:38 -0800467 if !list.IsValid() {
468 t.Errorf("message.Get(%v).IsValid() = false, want true", name)
469 }
Damien Neilf5274512019-08-05 10:48:38 -0700470 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
471 t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
472 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700473
474 // Append values.
475 var want pref.List = &testList{}
476 for i, n := range []seed{1, 0, minVal, maxVal} {
Damien Neila0a54b82019-11-01 15:18:36 -0700477 if got, want := m.Has(fd), i > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700478 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 -0700479 }
480 v := newListElement(fd, list, n, nil)
481 want.Append(v)
482 list.Append(v)
483
Joe Tsai84177c92019-09-17 13:38:48 -0700484 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700485 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 -0700486 }
487 }
488
489 // Set values.
490 for i := 0; i < want.Len(); i++ {
491 v := newListElement(fd, list, seed(i+10), nil)
492 want.Set(i, v)
493 list.Set(i, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700494 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700495 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 -0700496 }
497 }
498
499 // Truncate.
500 for want.Len() > 0 {
501 n := want.Len() - 1
502 want.Truncate(n)
503 list.Truncate(n)
Damien Neila0a54b82019-11-01 15:18:36 -0700504 if got, want := m.Has(fd), want.Len() > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700505 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 -0700506 }
Joe Tsai84177c92019-09-17 13:38:48 -0700507 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700508 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 -0700509 }
510 }
Damien Neil3dbd95a2020-02-19 10:48:36 -0800511
512 // AppendMutable.
513 if fd.Message() == nil {
514 if !panics(func() {
515 list.AppendMutable()
516 }) {
517 t.Errorf("AppendMutable on %q succeeds, want panic", name)
518 }
519 } else {
520 v := list.AppendMutable()
521 if got, want := list.Len(), 1; got != want {
522 t.Errorf("after AppendMutable on %q, list.Len() = %v, want %v", name, got, want)
523 }
524 populateMessage(v.Message(), 1, nil)
525 if !valueEqual(list.Get(0), v) {
526 t.Errorf("after AppendMutable on %q, changing new mutable value does not change list item 0", name)
527 }
528 want.Truncate(0)
529 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700530}
531
532type testList struct {
533 a []pref.Value
534}
535
Damien Neil3dbd95a2020-02-19 10:48:36 -0800536func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
537func (l *testList) AppendMutable() pref.Value { panic("unimplemented") }
538func (l *testList) Get(n int) pref.Value { return l.a[n] }
539func (l *testList) Len() int { return len(l.a) }
540func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
541func (l *testList) Truncate(n int) { l.a = l.a[:n] }
542func (l *testList) NewElement() pref.Value { panic("unimplemented") }
543func (l *testList) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700544
545// testFieldFloat exercises some interesting floating-point scalar field values.
546func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700547 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700548 num := fd.Number()
549
Damien Neil5ec58b92019-04-30 11:36:39 -0700550 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
551 var val pref.Value
552 if fd.Kind() == pref.FloatKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700553 val = pref.ValueOfFloat32(float32(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700554 } else {
Joe Tsai84177c92019-09-17 13:38:48 -0700555 val = pref.ValueOfFloat64(float64(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700556 }
Joe Tsai378c1322019-04-25 23:48:08 -0700557 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700558 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700559 if got, want := m.Has(fd), true; got != want {
560 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 -0700561 }
Joe Tsai378c1322019-04-25 23:48:08 -0700562 if got, want := m.Get(fd), val; !valueEqual(got, want) {
563 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700564 }
565 }
566}
567
568// testOneof tests the behavior of fields in a oneof.
569func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neila3456c92019-04-30 11:36:49 -0700570 for _, mutable := range []bool{false, true} {
571 for i := 0; i < od.Fields().Len(); i++ {
572 fda := od.Fields().Get(i)
573 if mutable {
574 // Set fields by requesting a mutable reference.
575 if !fda.IsMap() && !fda.IsList() && fda.Message() == nil {
576 continue
577 }
578 _ = m.Mutable(fda)
579 } else {
580 // Set fields explicitly.
581 m.Set(fda, newValue(m, fda, 1, nil))
582 }
583 if got, want := m.WhichOneof(od), fda; got != want {
584 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
585 }
586 for j := 0; j < od.Fields().Len(); j++ {
587 fdb := od.Fields().Get(j)
588 if got, want := m.Has(fdb), i == j; got != want {
589 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
590 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700591 }
592 }
593 }
594}
595
Damien Neild91246e2019-06-21 08:36:26 -0700596// testUnknown tests the behavior of unknown fields.
597func testUnknown(t testing.TB, m pref.Message) {
598 var b []byte
Joe Tsaicd108d02020-02-14 18:08:02 -0800599 b = protowire.AppendTag(b, 1000, protowire.VarintType)
600 b = protowire.AppendVarint(b, 1001)
Damien Neild91246e2019-06-21 08:36:26 -0700601 m.SetUnknown(pref.RawFields(b))
602 if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) {
603 t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want)
604 }
605}
606
Damien Neil5ec58b92019-04-30 11:36:39 -0700607func formatValue(v pref.Value) string {
608 switch v := v.Interface().(type) {
609 case pref.List:
610 var buf bytes.Buffer
611 buf.WriteString("list[")
612 for i := 0; i < v.Len(); i++ {
613 if i > 0 {
614 buf.WriteString(" ")
615 }
616 buf.WriteString(formatValue(v.Get(i)))
617 }
618 buf.WriteString("]")
619 return buf.String()
620 case pref.Map:
621 var buf bytes.Buffer
622 buf.WriteString("map[")
623 var keys []pref.MapKey
624 v.Range(func(k pref.MapKey, v pref.Value) bool {
625 keys = append(keys, k)
626 return true
627 })
628 sort.Slice(keys, func(i, j int) bool {
629 return keys[i].String() < keys[j].String()
630 })
631 for i, k := range keys {
632 if i > 0 {
633 buf.WriteString(" ")
634 }
635 buf.WriteString(formatValue(k.Value()))
636 buf.WriteString(":")
637 buf.WriteString(formatValue(v.Get(k)))
638 }
639 buf.WriteString("]")
640 return buf.String()
641 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700642 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700643 if err != nil {
644 return fmt.Sprintf("<%v>", err)
645 }
Emmanuel T Odeke26e8bcb2021-11-20 17:03:45 +0100646 return fmt.Sprintf("%v{%s}", v.Descriptor().FullName(), b)
Damien Neil5ec58b92019-04-30 11:36:39 -0700647 case string:
648 return fmt.Sprintf("%q", v)
649 default:
650 return fmt.Sprint(v)
651 }
652}
653
654func valueEqual(a, b pref.Value) bool {
655 ai, bi := a.Interface(), b.Interface()
656 switch ai.(type) {
657 case pref.Message:
658 return proto.Equal(
659 a.Message().Interface(),
660 b.Message().Interface(),
661 )
662 case pref.List:
663 lista, listb := a.List(), b.List()
664 if lista.Len() != listb.Len() {
665 return false
666 }
667 for i := 0; i < lista.Len(); i++ {
668 if !valueEqual(lista.Get(i), listb.Get(i)) {
669 return false
670 }
671 }
672 return true
673 case pref.Map:
674 mapa, mapb := a.Map(), b.Map()
675 if mapa.Len() != mapb.Len() {
676 return false
677 }
678 equal := true
679 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
680 if !valueEqual(v, mapb.Get(k)) {
681 equal = false
682 return false
683 }
684 return true
685 })
686 return equal
687 case []byte:
688 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700689 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700690 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700691 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
692 case float64:
693 // NaNs are equal, but must be the same NaN.
694 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700695 default:
696 return ai == bi
697 }
698}
699
700// A seed is used to vary the content of a value.
701//
702// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
703// is unpopulated.
704//
705// A seed of minVal or maxVal is the least or greatest value of the value type.
706type seed int
707
708const (
709 minVal seed = -1
710 maxVal seed = -2
711)
712
Damien Neilf5274512019-08-05 10:48:38 -0700713// newSeed creates new seed values from a base, for example to create seeds for the
714// elements in a list. If the input seed is minVal or maxVal, so is the output.
715func newSeed(n seed, adjust ...int) seed {
716 switch n {
717 case minVal, maxVal:
718 return n
719 }
720 for _, a := range adjust {
721 n = 10*n + seed(a)
722 }
723 return n
724}
725
Damien Neil5ec58b92019-04-30 11:36:39 -0700726// newValue returns a new value assignable to a field.
727//
728// The stack parameter is used to avoid infinite recursion when populating circular
729// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700730func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700731 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700732 case fd.IsList():
Joe Tsaiac31a352019-05-13 14:32:56 -0700733 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800734 return m.New().Mutable(fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700735 }
Damien Neil290ceea2019-07-15 13:39:43 -0700736 list := m.NewField(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700737 list.Append(newListElement(fd, list, 0, stack))
738 list.Append(newListElement(fd, list, minVal, stack))
739 list.Append(newListElement(fd, list, maxVal, stack))
740 list.Append(newListElement(fd, list, n, stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700741 return pref.ValueOfList(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700742 case fd.IsMap():
Damien Neil5ec58b92019-04-30 11:36:39 -0700743 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800744 return m.New().Mutable(fd)
Damien Neil5ec58b92019-04-30 11:36:39 -0700745 }
Damien Neil290ceea2019-07-15 13:39:43 -0700746 mapv := m.NewField(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700747 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
748 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
749 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
Damien Neilf5274512019-08-05 10:48:38 -0700750 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700751 return pref.ValueOfMap(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700752 case fd.Message() != nil:
Damien Neilf5274512019-08-05 10:48:38 -0700753 return populateMessage(m.NewField(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700754 default:
755 return newScalarValue(fd, n)
756 }
757}
758
Joe Tsai0fc49f82019-05-01 12:29:25 -0700759func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700760 if fd.Message() == nil {
761 return newScalarValue(fd, n)
762 }
Damien Neilf5274512019-08-05 10:48:38 -0700763 return populateMessage(list.NewElement().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700764}
765
766func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700767 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700768 return newScalarValue(kd, n).MapKey()
769}
770
Joe Tsai0fc49f82019-05-01 12:29:25 -0700771func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700772 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700773 if vd.Message() == nil {
774 return newScalarValue(vd, n)
775 }
Damien Neilf5274512019-08-05 10:48:38 -0700776 return populateMessage(mapv.NewValue().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700777}
778
779func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
780 switch fd.Kind() {
781 case pref.BoolKind:
Joe Tsai84177c92019-09-17 13:38:48 -0700782 return pref.ValueOfBool(n != 0)
Damien Neil5ec58b92019-04-30 11:36:39 -0700783 case pref.EnumKind:
Damien Neilf5274512019-08-05 10:48:38 -0700784 vals := fd.Enum().Values()
785 var i int
786 switch n {
787 case minVal:
788 i = 0
789 case maxVal:
790 i = vals.Len() - 1
791 default:
792 i = int(n) % vals.Len()
793 }
Joe Tsai84177c92019-09-17 13:38:48 -0700794 return pref.ValueOfEnum(vals.Get(i).Number())
Damien Neil5ec58b92019-04-30 11:36:39 -0700795 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
796 switch n {
797 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700798 return pref.ValueOfInt32(math.MinInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700799 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700800 return pref.ValueOfInt32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700801 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700802 return pref.ValueOfInt32(int32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700803 }
804 case pref.Uint32Kind, pref.Fixed32Kind:
805 switch n {
806 case minVal:
807 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700808 return pref.ValueOfUint32(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700809 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700810 return pref.ValueOfUint32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700811 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700812 return pref.ValueOfUint32(uint32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700813 }
814 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
815 switch n {
816 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700817 return pref.ValueOfInt64(math.MinInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700818 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700819 return pref.ValueOfInt64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700820 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700821 return pref.ValueOfInt64(int64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700822 }
823 case pref.Uint64Kind, pref.Fixed64Kind:
824 switch n {
825 case minVal:
826 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700827 return pref.ValueOfUint64(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700828 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700829 return pref.ValueOfUint64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700830 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700831 return pref.ValueOfUint64(uint64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700832 }
833 case pref.FloatKind:
834 switch n {
835 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700836 return pref.ValueOfFloat32(math.SmallestNonzeroFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700837 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700838 return pref.ValueOfFloat32(math.MaxFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700839 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700840 return pref.ValueOfFloat32(1.5 * float32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700841 }
842 case pref.DoubleKind:
843 switch n {
844 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700845 return pref.ValueOfFloat64(math.SmallestNonzeroFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700846 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700847 return pref.ValueOfFloat64(math.MaxFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700848 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700849 return pref.ValueOfFloat64(1.5 * float64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700850 }
851 case pref.StringKind:
852 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700853 return pref.ValueOfString("")
Damien Neil5ec58b92019-04-30 11:36:39 -0700854 }
Joe Tsai84177c92019-09-17 13:38:48 -0700855 return pref.ValueOfString(fmt.Sprintf("%d", n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700856 case pref.BytesKind:
857 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700858 return pref.ValueOfBytes(nil)
Damien Neil5ec58b92019-04-30 11:36:39 -0700859 }
Joe Tsai84177c92019-09-17 13:38:48 -0700860 return pref.ValueOfBytes([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
Damien Neil5ec58b92019-04-30 11:36:39 -0700861 }
862 panic("unhandled kind")
863}
864
Joe Tsai0fc49f82019-05-01 12:29:25 -0700865func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700866 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700867 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700868 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700869 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700870 for _, x := range stack {
871 if md == x {
Joe Tsai84177c92019-09-17 13:38:48 -0700872 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700873 }
874 }
875 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700876 for i := 0; i < md.Fields().Len(); i++ {
877 fd := md.Fields().Get(i)
878 if fd.IsWeak() {
879 continue
880 }
Damien Neilf5274512019-08-05 10:48:38 -0700881 m.Set(fd, newValue(m, fd, newSeed(n, i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700882 }
Joe Tsai84177c92019-09-17 13:38:48 -0700883 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700884}
Damien Neild91246e2019-06-21 08:36:26 -0700885
886func panics(f func()) (didPanic bool) {
887 defer func() {
888 if err := recover(); err != nil {
889 didPanic = true
890 }
891 }()
892 f()
893 return false
894}