blob: 4fccb70376e69ee208c5f763be1399efab4a7f10 [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"
14 "testing"
15
Damien Neild91246e2019-06-21 08:36:26 -070016 "google.golang.org/protobuf/encoding/prototext"
17 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neile89e6242019-05-13 23:55:40 -070018 "google.golang.org/protobuf/proto"
19 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neil56786dc2020-02-11 16:43:13 -080020 "google.golang.org/protobuf/reflect/protoregistry"
Damien Neil5ec58b92019-04-30 11:36:39 -070021)
22
Joe Tsai378c1322019-04-25 23:48:08 -070023// 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 Neil56786dc2020-02-11 16:43:13 -080026// Message tests a message implemention.
27type Message struct {
28 // Resolver is used to determine the list of extension fields to test with.
Damien Neil290ceea2019-07-15 13:39:43 -070029 // If nil, this defaults to using protoregistry.GlobalTypes.
30 Resolver interface {
Damien Neil56786dc2020-02-11 16:43:13 -080031 FindExtensionByName(field pref.FullName) (pref.ExtensionType, error)
32 FindExtensionByNumber(message pref.FullName, field pref.FieldNumber) (pref.ExtensionType, error)
33 RangeExtensionsByMessage(message pref.FullName, f func(pref.ExtensionType) bool)
Damien Neil290ceea2019-07-15 13:39:43 -070034 }
Damien Neild91246e2019-06-21 08:36:26 -070035}
36
Damien Neil56786dc2020-02-11 16:43:13 -080037// Test performs tests on a MessageType implementation.
38func (test Message) Test(t testing.TB, mt pref.MessageType) {
39 testType(t, mt)
Joe Tsai93bccf72020-02-10 11:14:03 -080040
Damien Neil56786dc2020-02-11 16:43:13 -080041 md := mt.Descriptor()
42 m1 := mt.New()
Damien Neil5ec58b92019-04-30 11:36:39 -070043 for i := 0; i < md.Fields().Len(); i++ {
44 fd := md.Fields().Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -070045 testField(t, m1, fd)
Damien Neil5ec58b92019-04-30 11:36:39 -070046 }
Damien Neil56786dc2020-02-11 16:43:13 -080047 if test.Resolver == nil {
48 test.Resolver = protoregistry.GlobalTypes
Damien Neild91246e2019-06-21 08:36:26 -070049 }
Damien Neil56786dc2020-02-11 16:43:13 -080050 var extTypes []pref.ExtensionType
51 test.Resolver.RangeExtensionsByMessage(md.FullName(), func(e pref.ExtensionType) bool {
52 extTypes = append(extTypes, e)
53 return true
54 })
55 for _, xt := range extTypes {
Damien Neil79bfdbe2019-08-28 11:08:22 -070056 testField(t, m1, xt.TypeDescriptor())
Damien Neild91246e2019-06-21 08:36:26 -070057 }
Damien Neil5ec58b92019-04-30 11:36:39 -070058 for i := 0; i < md.Oneofs().Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070059 testOneof(t, m1, md.Oneofs().Get(i))
Damien Neil5ec58b92019-04-30 11:36:39 -070060 }
Damien Neild91246e2019-06-21 08:36:26 -070061 testUnknown(t, m1)
Damien Neil5ec58b92019-04-30 11:36:39 -070062
63 // Test round-trip marshal/unmarshal.
Damien Neil56786dc2020-02-11 16:43:13 -080064 m2 := mt.New().Interface()
Joe Tsai378c1322019-04-25 23:48:08 -070065 populateMessage(m2.ProtoReflect(), 1, nil)
Damien Neil56786dc2020-02-11 16:43:13 -080066 for _, xt := range extTypes {
Damien Neil290ceea2019-07-15 13:39:43 -070067 m2.ProtoReflect().Set(xt.TypeDescriptor(), newValue(m2.ProtoReflect(), xt.TypeDescriptor(), 1, nil))
68 }
69 b, err := proto.MarshalOptions{
70 AllowPartial: true,
71 }.Marshal(m2)
Damien Neil5ec58b92019-04-30 11:36:39 -070072 if err != nil {
Joe Tsai74b14602020-01-06 15:44:09 -080073 t.Errorf("Marshal() = %v, want nil\n%v", err, prototext.Format(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070074 }
Damien Neil56786dc2020-02-11 16:43:13 -080075 m3 := mt.New().Interface()
Damien Neil290ceea2019-07-15 13:39:43 -070076 if err := (proto.UnmarshalOptions{
77 AllowPartial: true,
Damien Neil56786dc2020-02-11 16:43:13 -080078 Resolver: test.Resolver,
Damien Neil290ceea2019-07-15 13:39:43 -070079 }.Unmarshal(b, m3)); err != nil {
Joe Tsai74b14602020-01-06 15:44:09 -080080 t.Errorf("Unmarshal() = %v, want nil\n%v", err, prototext.Format(m2))
Damien Neil5ec58b92019-04-30 11:36:39 -070081 }
Joe Tsai378c1322019-04-25 23:48:08 -070082 if !proto.Equal(m2, m3) {
Joe Tsai74b14602020-01-06 15:44:09 -080083 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 -070084 }
85}
86
Damien Neil56786dc2020-02-11 16:43:13 -080087func testType(t testing.TB, mt pref.MessageType) {
88 m := mt.New().Interface()
Joe Tsaib7695fa2020-01-04 09:09:04 -080089 want := reflect.TypeOf(m)
90 if got := reflect.TypeOf(m.ProtoReflect().Interface()); got != want {
91 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Interface()): %v != %v", got, want)
92 }
93 if got := reflect.TypeOf(m.ProtoReflect().New().Interface()); got != want {
94 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().New().Interface()): %v != %v", got, want)
95 }
96 if got := reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()); got != want {
97 t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()): %v != %v", got, want)
98 }
99}
100
Joe Tsai378c1322019-04-25 23:48:08 -0700101// testField exercises set/get/has/clear of a field.
Damien Neil5ec58b92019-04-30 11:36:39 -0700102func testField(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700103 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700104 num := fd.Number()
Damien Neil5ec58b92019-04-30 11:36:39 -0700105
Damien Neild91246e2019-06-21 08:36:26 -0700106 switch {
107 case fd.IsList():
108 testFieldList(t, m, fd)
109 case fd.IsMap():
110 testFieldMap(t, m, fd)
Damien Neilf5274512019-08-05 10:48:38 -0700111 case fd.Message() != nil:
112 default:
113 if got, want := m.NewField(fd), fd.Default(); !valueEqual(got, want) {
114 t.Errorf("Message.NewField(%v) = %v, want default value %v", name, formatValue(got), formatValue(want))
115 }
116 if fd.Kind() == pref.FloatKind || fd.Kind() == pref.DoubleKind {
117 testFieldFloat(t, m, fd)
118 }
Damien Neild91246e2019-06-21 08:36:26 -0700119 }
120
Damien Neil5ec58b92019-04-30 11:36:39 -0700121 // Set to a non-zero value, the zero value, different non-zero values.
122 for _, n := range []seed{1, 0, minVal, maxVal} {
123 v := newValue(m, fd, n, nil)
Joe Tsai378c1322019-04-25 23:48:08 -0700124 m.Set(fd, v)
Damien Neil5ec58b92019-04-30 11:36:39 -0700125 wantHas := true
126 if n == 0 {
127 if fd.Syntax() == pref.Proto3 && fd.Message() == nil {
128 wantHas = false
129 }
Damien Neild91246e2019-06-21 08:36:26 -0700130 if fd.IsExtension() {
131 wantHas = true
132 }
Damien Neila0a54b82019-11-01 15:18:36 -0700133 if fd.Cardinality() == pref.Repeated {
134 wantHas = false
135 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700136 if fd.ContainingOneof() != nil {
Damien Neil5ec58b92019-04-30 11:36:39 -0700137 wantHas = true
138 }
139 }
Damien Neilf5274512019-08-05 10:48:38 -0700140 if fd.Syntax() == pref.Proto3 && fd.Cardinality() != pref.Repeated && fd.ContainingOneof() == nil && fd.Kind() == pref.EnumKind && v.Enum() == 0 {
141 wantHas = false
142 }
Joe Tsai378c1322019-04-25 23:48:08 -0700143 if got, want := m.Has(fd), wantHas; got != want {
144 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 -0700145 }
Joe Tsai378c1322019-04-25 23:48:08 -0700146 if got, want := m.Get(fd), v; !valueEqual(got, want) {
147 t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700148 }
Damien Neild91246e2019-06-21 08:36:26 -0700149 found := false
150 m.Range(func(d pref.FieldDescriptor, got pref.Value) bool {
151 if fd != d {
152 return true
153 }
154 found = true
155 if want := v; !valueEqual(got, want) {
156 t.Errorf("after setting %q:\nMessage.Range got value %v, want %v", name, formatValue(got), formatValue(want))
157 }
158 return true
159 })
160 if got, want := wantHas, found; got != want {
161 t.Errorf("after setting %q:\nMessageRange saw field: %v, want %v", name, got, want)
162 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700163 }
164
Joe Tsai378c1322019-04-25 23:48:08 -0700165 m.Clear(fd)
166 if got, want := m.Has(fd), false; got != want {
167 t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700168 }
169 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700170 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -0700171 if got := m.Get(fd); got.List().Len() != 0 {
172 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700173 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700174 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -0700175 if got := m.Get(fd); got.Map().Len() != 0 {
Damien Neil290ceea2019-07-15 13:39:43 -0700176 t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty map", name, num, formatValue(got))
Damien Neil5ec58b92019-04-30 11:36:39 -0700177 }
Joe Tsai378c1322019-04-25 23:48:08 -0700178 case fd.Message() == nil:
179 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
180 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 -0700181 }
182 }
Damien Neild91246e2019-06-21 08:36:26 -0700183
Damien Neil290ceea2019-07-15 13:39:43 -0700184 // Set to the default value.
185 switch {
186 case fd.IsList() || fd.IsMap():
Damien Neil9f1165c2019-11-26 13:31:38 -0800187 m.Set(fd, m.Mutable(fd))
Damien Neila0a54b82019-11-01 15:18:36 -0700188 if got, want := m.Has(fd), (fd.IsExtension() && fd.Cardinality() != pref.Repeated) || fd.ContainingOneof() != nil; got != want {
Damien Neil290ceea2019-07-15 13:39:43 -0700189 t.Errorf("after setting %q to default:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
190 }
191 case fd.Message() == nil:
192 m.Set(fd, m.Get(fd))
193 if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) {
194 t.Errorf("after setting %q to default:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want))
195 }
196 }
197 m.Clear(fd)
198
Damien Neild91246e2019-06-21 08:36:26 -0700199 // Set to the wrong type.
Joe Tsai84177c92019-09-17 13:38:48 -0700200 v := pref.ValueOfString("")
Damien Neild91246e2019-06-21 08:36:26 -0700201 if fd.Kind() == pref.StringKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700202 v = pref.ValueOfInt32(0)
Damien Neild91246e2019-06-21 08:36:26 -0700203 }
204 if !panics(func() {
205 m.Set(fd, v)
206 }) {
207 t.Errorf("setting %v to %T succeeds, want panic", name, v.Interface())
208 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700209}
210
211// testFieldMap tests set/get/has/clear of entries in a map field.
212func testFieldMap(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700213 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700214 num := fd.Number()
215
Damien Neilf5274512019-08-05 10:48:38 -0700216 // New values.
Joe Tsai378c1322019-04-25 23:48:08 -0700217 m.Clear(fd) // start with an empty map
Damien Neilf5274512019-08-05 10:48:38 -0700218 mapv := m.Get(fd).Map()
Damien Neil9f1165c2019-11-26 13:31:38 -0800219 if mapv.IsValid() {
220 t.Errorf("after clearing field: message.Get(%v).IsValid() = true, want false", name)
221 }
Damien Neilf5274512019-08-05 10:48:38 -0700222 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
223 t.Errorf("message.Get(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
224 }
Damien Neil9f1165c2019-11-26 13:31:38 -0800225 if !panics(func() {
226 m.Set(fd, pref.ValueOfMap(mapv))
227 }) {
228 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
229 }
230 if !panics(func() {
231 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, nil))
232 }) {
233 t.Errorf("message.Get(%v).Set(...) of invalid map does not panic", name)
234 }
Damien Neilf5274512019-08-05 10:48:38 -0700235 mapv = m.Mutable(fd).Map() // mutable map
Damien Neil9f1165c2019-11-26 13:31:38 -0800236 if !mapv.IsValid() {
237 t.Errorf("message.Mutable(%v).IsValid() = false, want true", name)
238 }
Damien Neilf5274512019-08-05 10:48:38 -0700239 if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) {
240 t.Errorf("message.Mutable(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want))
241 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700242
243 // Add values.
244 want := make(testMap)
245 for i, n := range []seed{1, 0, minVal, maxVal} {
Joe Tsai378c1322019-04-25 23:48:08 -0700246 if got, want := m.Has(fd), i > 0; got != want {
247 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 -0700248 }
249
250 k := newMapKey(fd, n)
251 v := newMapValue(fd, mapv, n, nil)
252 mapv.Set(k, v)
253 want.Set(k, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700254 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700255 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 -0700256 }
257 }
258
259 // Set values.
260 want.Range(func(k pref.MapKey, v pref.Value) bool {
261 nv := newMapValue(fd, mapv, 10, nil)
262 mapv.Set(k, nv)
263 want.Set(k, nv)
Joe Tsai84177c92019-09-17 13:38:48 -0700264 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700265 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 -0700266 }
267 return true
268 })
269
270 // Clear values.
271 want.Range(func(k pref.MapKey, v pref.Value) bool {
272 mapv.Clear(k)
273 want.Clear(k)
Joe Tsai378c1322019-04-25 23:48:08 -0700274 if got, want := m.Has(fd), want.Len() > 0; got != want {
275 t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want)
Damien Neil5ec58b92019-04-30 11:36:39 -0700276 }
Joe Tsai84177c92019-09-17 13:38:48 -0700277 if got, want := m.Get(fd), pref.ValueOfMap(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700278 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 -0700279 }
280 return true
281 })
Damien Neil9f1165c2019-11-26 13:31:38 -0800282 if mapv := m.Get(fd).Map(); mapv.IsValid() {
283 t.Errorf("after clearing all elements: message.Get(%v).IsValid() = true, want false %v", name, formatValue(pref.ValueOfMap(mapv)))
284 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700285
286 // Non-existent map keys.
287 missingKey := newMapKey(fd, 1)
288 if got, want := mapv.Has(missingKey), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700289 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 -0700290 }
291 if got, want := mapv.Get(missingKey).IsValid(), false; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700292 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 -0700293 }
294 mapv.Clear(missingKey) // noop
Damien Neil3dbd95a2020-02-19 10:48:36 -0800295
296 // Mutable.
297 if fd.MapValue().Message() == nil {
298 if !panics(func() {
299 mapv.Mutable(newMapKey(fd, 1))
300 }) {
301 t.Errorf("Mutable on %q succeeds, want panic", name)
302 }
303 } else {
304 k := newMapKey(fd, 1)
305 v := mapv.Mutable(k)
306 if got, want := mapv.Len(), 1; got != want {
307 t.Errorf("after Mutable on %q, Map.Len() = %v, want %v", name, got, want)
308 }
309 populateMessage(v.Message(), 1, nil)
310 if !valueEqual(mapv.Get(k), v) {
311 t.Errorf("after Mutable on %q, changing new mutable value does not change map entry", name)
312 }
313 mapv.Clear(k)
314 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700315}
316
317type testMap map[interface{}]pref.Value
318
Damien Neil3dbd95a2020-02-19 10:48:36 -0800319func (m testMap) Get(k pref.MapKey) pref.Value { return m[k.Interface()] }
320func (m testMap) Set(k pref.MapKey, v pref.Value) { m[k.Interface()] = v }
321func (m testMap) Has(k pref.MapKey) bool { return m.Get(k).IsValid() }
322func (m testMap) Clear(k pref.MapKey) { delete(m, k.Interface()) }
323func (m testMap) Mutable(k pref.MapKey) pref.Value { panic("unimplemented") }
324func (m testMap) Len() int { return len(m) }
325func (m testMap) NewValue() pref.Value { panic("unimplemented") }
Damien Neil5ec58b92019-04-30 11:36:39 -0700326func (m testMap) Range(f func(pref.MapKey, pref.Value) bool) {
327 for k, v := range m {
328 if !f(pref.ValueOf(k).MapKey(), v) {
329 return
330 }
331 }
332}
Damien Neil82886da2019-11-26 13:27:24 -0800333func (m testMap) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700334
335// testFieldList exercises set/get/append/truncate of values in a list.
336func testFieldList(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700337 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700338 num := fd.Number()
339
340 m.Clear(fd) // start with an empty list
Damien Neilf5274512019-08-05 10:48:38 -0700341 list := m.Get(fd).List()
Damien Neil9f1165c2019-11-26 13:31:38 -0800342 if list.IsValid() {
343 t.Errorf("message.Get(%v).IsValid() = true, want false", name)
344 }
345 if !panics(func() {
346 m.Set(fd, pref.ValueOfList(list))
347 }) {
348 t.Errorf("message.Set(%v, <invalid>) does not panic", name)
349 }
350 if !panics(func() {
351 list.Append(newListElement(fd, list, 0, nil))
352 }) {
353 t.Errorf("message.Get(%v).Append(...) of invalid list does not panic", name)
354 }
Damien Neilf5274512019-08-05 10:48:38 -0700355 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
356 t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
357 }
358 list = m.Mutable(fd).List() // mutable list
Damien Neil9f1165c2019-11-26 13:31:38 -0800359 if !list.IsValid() {
360 t.Errorf("message.Get(%v).IsValid() = false, want true", name)
361 }
Damien Neilf5274512019-08-05 10:48:38 -0700362 if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) {
363 t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want))
364 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700365
366 // Append values.
367 var want pref.List = &testList{}
368 for i, n := range []seed{1, 0, minVal, maxVal} {
Damien Neila0a54b82019-11-01 15:18:36 -0700369 if got, want := m.Has(fd), i > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700370 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 -0700371 }
372 v := newListElement(fd, list, n, nil)
373 want.Append(v)
374 list.Append(v)
375
Joe Tsai84177c92019-09-17 13:38:48 -0700376 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700377 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 -0700378 }
379 }
380
381 // Set values.
382 for i := 0; i < want.Len(); i++ {
383 v := newListElement(fd, list, seed(i+10), nil)
384 want.Set(i, v)
385 list.Set(i, v)
Joe Tsai84177c92019-09-17 13:38:48 -0700386 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700387 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 -0700388 }
389 }
390
391 // Truncate.
392 for want.Len() > 0 {
393 n := want.Len() - 1
394 want.Truncate(n)
395 list.Truncate(n)
Damien Neila0a54b82019-11-01 15:18:36 -0700396 if got, want := m.Has(fd), want.Len() > 0; got != want {
Joe Tsai378c1322019-04-25 23:48:08 -0700397 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 -0700398 }
Joe Tsai84177c92019-09-17 13:38:48 -0700399 if got, want := m.Get(fd), pref.ValueOfList(want); !valueEqual(got, want) {
Joe Tsai378c1322019-04-25 23:48:08 -0700400 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 -0700401 }
402 }
Damien Neil3dbd95a2020-02-19 10:48:36 -0800403
404 // AppendMutable.
405 if fd.Message() == nil {
406 if !panics(func() {
407 list.AppendMutable()
408 }) {
409 t.Errorf("AppendMutable on %q succeeds, want panic", name)
410 }
411 } else {
412 v := list.AppendMutable()
413 if got, want := list.Len(), 1; got != want {
414 t.Errorf("after AppendMutable on %q, list.Len() = %v, want %v", name, got, want)
415 }
416 populateMessage(v.Message(), 1, nil)
417 if !valueEqual(list.Get(0), v) {
418 t.Errorf("after AppendMutable on %q, changing new mutable value does not change list item 0", name)
419 }
420 want.Truncate(0)
421 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700422}
423
424type testList struct {
425 a []pref.Value
426}
427
Damien Neil3dbd95a2020-02-19 10:48:36 -0800428func (l *testList) Append(v pref.Value) { l.a = append(l.a, v) }
429func (l *testList) AppendMutable() pref.Value { panic("unimplemented") }
430func (l *testList) Get(n int) pref.Value { return l.a[n] }
431func (l *testList) Len() int { return len(l.a) }
432func (l *testList) Set(n int, v pref.Value) { l.a[n] = v }
433func (l *testList) Truncate(n int) { l.a = l.a[:n] }
434func (l *testList) NewElement() pref.Value { panic("unimplemented") }
435func (l *testList) IsValid() bool { return true }
Damien Neil5ec58b92019-04-30 11:36:39 -0700436
437// testFieldFloat exercises some interesting floating-point scalar field values.
438func testFieldFloat(t testing.TB, m pref.Message, fd pref.FieldDescriptor) {
Damien Neil5ec58b92019-04-30 11:36:39 -0700439 name := fd.FullName()
Joe Tsai378c1322019-04-25 23:48:08 -0700440 num := fd.Number()
441
Damien Neil5ec58b92019-04-30 11:36:39 -0700442 for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} {
443 var val pref.Value
444 if fd.Kind() == pref.FloatKind {
Joe Tsai84177c92019-09-17 13:38:48 -0700445 val = pref.ValueOfFloat32(float32(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700446 } else {
Joe Tsai84177c92019-09-17 13:38:48 -0700447 val = pref.ValueOfFloat64(float64(v))
Damien Neil5ec58b92019-04-30 11:36:39 -0700448 }
Joe Tsai378c1322019-04-25 23:48:08 -0700449 m.Set(fd, val)
Damien Neil5ec58b92019-04-30 11:36:39 -0700450 // Note that Has is true for -0.
Joe Tsai378c1322019-04-25 23:48:08 -0700451 if got, want := m.Has(fd), true; got != want {
452 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 -0700453 }
Joe Tsai378c1322019-04-25 23:48:08 -0700454 if got, want := m.Get(fd), val; !valueEqual(got, want) {
455 t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want))
Damien Neil5ec58b92019-04-30 11:36:39 -0700456 }
457 }
458}
459
460// testOneof tests the behavior of fields in a oneof.
461func testOneof(t testing.TB, m pref.Message, od pref.OneofDescriptor) {
Damien Neila3456c92019-04-30 11:36:49 -0700462 for _, mutable := range []bool{false, true} {
463 for i := 0; i < od.Fields().Len(); i++ {
464 fda := od.Fields().Get(i)
465 if mutable {
466 // Set fields by requesting a mutable reference.
467 if !fda.IsMap() && !fda.IsList() && fda.Message() == nil {
468 continue
469 }
470 _ = m.Mutable(fda)
471 } else {
472 // Set fields explicitly.
473 m.Set(fda, newValue(m, fda, 1, nil))
474 }
475 if got, want := m.WhichOneof(od), fda; got != want {
476 t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want)
477 }
478 for j := 0; j < od.Fields().Len(); j++ {
479 fdb := od.Fields().Get(j)
480 if got, want := m.Has(fdb), i == j; got != want {
481 t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want)
482 }
Damien Neil5ec58b92019-04-30 11:36:39 -0700483 }
484 }
485 }
486}
487
Damien Neild91246e2019-06-21 08:36:26 -0700488// testUnknown tests the behavior of unknown fields.
489func testUnknown(t testing.TB, m pref.Message) {
490 var b []byte
491 b = wire.AppendTag(b, 1000, wire.VarintType)
492 b = wire.AppendVarint(b, 1001)
493 m.SetUnknown(pref.RawFields(b))
494 if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) {
495 t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want)
496 }
497}
498
Damien Neil5ec58b92019-04-30 11:36:39 -0700499func formatValue(v pref.Value) string {
500 switch v := v.Interface().(type) {
501 case pref.List:
502 var buf bytes.Buffer
503 buf.WriteString("list[")
504 for i := 0; i < v.Len(); i++ {
505 if i > 0 {
506 buf.WriteString(" ")
507 }
508 buf.WriteString(formatValue(v.Get(i)))
509 }
510 buf.WriteString("]")
511 return buf.String()
512 case pref.Map:
513 var buf bytes.Buffer
514 buf.WriteString("map[")
515 var keys []pref.MapKey
516 v.Range(func(k pref.MapKey, v pref.Value) bool {
517 keys = append(keys, k)
518 return true
519 })
520 sort.Slice(keys, func(i, j int) bool {
521 return keys[i].String() < keys[j].String()
522 })
523 for i, k := range keys {
524 if i > 0 {
525 buf.WriteString(" ")
526 }
527 buf.WriteString(formatValue(k.Value()))
528 buf.WriteString(":")
529 buf.WriteString(formatValue(v.Get(k)))
530 }
531 buf.WriteString("]")
532 return buf.String()
533 case pref.Message:
Damien Neil5c5b5312019-05-14 12:44:37 -0700534 b, err := prototext.Marshal(v.Interface())
Damien Neil5ec58b92019-04-30 11:36:39 -0700535 if err != nil {
536 return fmt.Sprintf("<%v>", err)
537 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700538 return fmt.Sprintf("%v{%v}", v.Descriptor().FullName(), string(b))
Damien Neil5ec58b92019-04-30 11:36:39 -0700539 case string:
540 return fmt.Sprintf("%q", v)
541 default:
542 return fmt.Sprint(v)
543 }
544}
545
546func valueEqual(a, b pref.Value) bool {
547 ai, bi := a.Interface(), b.Interface()
548 switch ai.(type) {
549 case pref.Message:
550 return proto.Equal(
551 a.Message().Interface(),
552 b.Message().Interface(),
553 )
554 case pref.List:
555 lista, listb := a.List(), b.List()
556 if lista.Len() != listb.Len() {
557 return false
558 }
559 for i := 0; i < lista.Len(); i++ {
560 if !valueEqual(lista.Get(i), listb.Get(i)) {
561 return false
562 }
563 }
564 return true
565 case pref.Map:
566 mapa, mapb := a.Map(), b.Map()
567 if mapa.Len() != mapb.Len() {
568 return false
569 }
570 equal := true
571 mapa.Range(func(k pref.MapKey, v pref.Value) bool {
572 if !valueEqual(v, mapb.Get(k)) {
573 equal = false
574 return false
575 }
576 return true
577 })
578 return equal
579 case []byte:
580 return bytes.Equal(a.Bytes(), b.Bytes())
Joe Tsaifb30a402019-05-20 15:19:14 -0700581 case float32:
Damien Neil5ec58b92019-04-30 11:36:39 -0700582 // NaNs are equal, but must be the same NaN.
Joe Tsaifb30a402019-05-20 15:19:14 -0700583 return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32))
584 case float64:
585 // NaNs are equal, but must be the same NaN.
586 return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64))
Damien Neil5ec58b92019-04-30 11:36:39 -0700587 default:
588 return ai == bi
589 }
590}
591
592// A seed is used to vary the content of a value.
593//
594// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages
595// is unpopulated.
596//
597// A seed of minVal or maxVal is the least or greatest value of the value type.
598type seed int
599
600const (
601 minVal seed = -1
602 maxVal seed = -2
603)
604
Damien Neilf5274512019-08-05 10:48:38 -0700605// newSeed creates new seed values from a base, for example to create seeds for the
606// elements in a list. If the input seed is minVal or maxVal, so is the output.
607func newSeed(n seed, adjust ...int) seed {
608 switch n {
609 case minVal, maxVal:
610 return n
611 }
612 for _, a := range adjust {
613 n = 10*n + seed(a)
614 }
615 return n
616}
617
Damien Neil5ec58b92019-04-30 11:36:39 -0700618// newValue returns a new value assignable to a field.
619//
620// The stack parameter is used to avoid infinite recursion when populating circular
621// data structures.
Joe Tsai0fc49f82019-05-01 12:29:25 -0700622func newValue(m pref.Message, fd pref.FieldDescriptor, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700623 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -0700624 case fd.IsList():
Joe Tsaiac31a352019-05-13 14:32:56 -0700625 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800626 return m.New().Mutable(fd)
Joe Tsaiac31a352019-05-13 14:32:56 -0700627 }
Damien Neil290ceea2019-07-15 13:39:43 -0700628 list := m.NewField(fd).List()
Joe Tsaiac31a352019-05-13 14:32:56 -0700629 list.Append(newListElement(fd, list, 0, stack))
630 list.Append(newListElement(fd, list, minVal, stack))
631 list.Append(newListElement(fd, list, maxVal, stack))
632 list.Append(newListElement(fd, list, n, stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700633 return pref.ValueOfList(list)
Damien Neil5ec58b92019-04-30 11:36:39 -0700634 case fd.IsMap():
Damien Neil5ec58b92019-04-30 11:36:39 -0700635 if n == 0 {
Damien Neil9f1165c2019-11-26 13:31:38 -0800636 return m.New().Mutable(fd)
Damien Neil5ec58b92019-04-30 11:36:39 -0700637 }
Damien Neil290ceea2019-07-15 13:39:43 -0700638 mapv := m.NewField(fd).Map()
Damien Neil5ec58b92019-04-30 11:36:39 -0700639 mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack))
640 mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack))
641 mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack))
Damien Neilf5274512019-08-05 10:48:38 -0700642 mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack))
Joe Tsai84177c92019-09-17 13:38:48 -0700643 return pref.ValueOfMap(mapv)
Damien Neil5ec58b92019-04-30 11:36:39 -0700644 case fd.Message() != nil:
Damien Neilf5274512019-08-05 10:48:38 -0700645 return populateMessage(m.NewField(fd).Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700646 default:
647 return newScalarValue(fd, n)
648 }
649}
650
Joe Tsai0fc49f82019-05-01 12:29:25 -0700651func newListElement(fd pref.FieldDescriptor, list pref.List, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700652 if fd.Message() == nil {
653 return newScalarValue(fd, n)
654 }
Damien Neilf5274512019-08-05 10:48:38 -0700655 return populateMessage(list.NewElement().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700656}
657
658func newMapKey(fd pref.FieldDescriptor, n seed) pref.MapKey {
Joe Tsaiac31a352019-05-13 14:32:56 -0700659 kd := fd.MapKey()
Damien Neil5ec58b92019-04-30 11:36:39 -0700660 return newScalarValue(kd, n).MapKey()
661}
662
Joe Tsai0fc49f82019-05-01 12:29:25 -0700663func newMapValue(fd pref.FieldDescriptor, mapv pref.Map, n seed, stack []pref.MessageDescriptor) pref.Value {
Joe Tsaiac31a352019-05-13 14:32:56 -0700664 vd := fd.MapValue()
Damien Neil5ec58b92019-04-30 11:36:39 -0700665 if vd.Message() == nil {
666 return newScalarValue(vd, n)
667 }
Damien Neilf5274512019-08-05 10:48:38 -0700668 return populateMessage(mapv.NewValue().Message(), n, stack)
Damien Neil5ec58b92019-04-30 11:36:39 -0700669}
670
671func newScalarValue(fd pref.FieldDescriptor, n seed) pref.Value {
672 switch fd.Kind() {
673 case pref.BoolKind:
Joe Tsai84177c92019-09-17 13:38:48 -0700674 return pref.ValueOfBool(n != 0)
Damien Neil5ec58b92019-04-30 11:36:39 -0700675 case pref.EnumKind:
Damien Neilf5274512019-08-05 10:48:38 -0700676 vals := fd.Enum().Values()
677 var i int
678 switch n {
679 case minVal:
680 i = 0
681 case maxVal:
682 i = vals.Len() - 1
683 default:
684 i = int(n) % vals.Len()
685 }
Joe Tsai84177c92019-09-17 13:38:48 -0700686 return pref.ValueOfEnum(vals.Get(i).Number())
Damien Neil5ec58b92019-04-30 11:36:39 -0700687 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
688 switch n {
689 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700690 return pref.ValueOfInt32(math.MinInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700691 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700692 return pref.ValueOfInt32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700693 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700694 return pref.ValueOfInt32(int32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700695 }
696 case pref.Uint32Kind, pref.Fixed32Kind:
697 switch n {
698 case minVal:
699 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700700 return pref.ValueOfUint32(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700701 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700702 return pref.ValueOfUint32(math.MaxInt32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700703 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700704 return pref.ValueOfUint32(uint32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700705 }
706 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
707 switch n {
708 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700709 return pref.ValueOfInt64(math.MinInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700710 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700711 return pref.ValueOfInt64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700712 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700713 return pref.ValueOfInt64(int64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700714 }
715 case pref.Uint64Kind, pref.Fixed64Kind:
716 switch n {
717 case minVal:
718 // Only use 0 for the zero value.
Joe Tsai84177c92019-09-17 13:38:48 -0700719 return pref.ValueOfUint64(1)
Damien Neil5ec58b92019-04-30 11:36:39 -0700720 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700721 return pref.ValueOfUint64(math.MaxInt64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700722 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700723 return pref.ValueOfUint64(uint64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700724 }
725 case pref.FloatKind:
726 switch n {
727 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700728 return pref.ValueOfFloat32(math.SmallestNonzeroFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700729 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700730 return pref.ValueOfFloat32(math.MaxFloat32)
Damien Neil5ec58b92019-04-30 11:36:39 -0700731 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700732 return pref.ValueOfFloat32(1.5 * float32(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700733 }
734 case pref.DoubleKind:
735 switch n {
736 case minVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700737 return pref.ValueOfFloat64(math.SmallestNonzeroFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700738 case maxVal:
Joe Tsai84177c92019-09-17 13:38:48 -0700739 return pref.ValueOfFloat64(math.MaxFloat64)
Damien Neil5ec58b92019-04-30 11:36:39 -0700740 default:
Joe Tsai84177c92019-09-17 13:38:48 -0700741 return pref.ValueOfFloat64(1.5 * float64(n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700742 }
743 case pref.StringKind:
744 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700745 return pref.ValueOfString("")
Damien Neil5ec58b92019-04-30 11:36:39 -0700746 }
Joe Tsai84177c92019-09-17 13:38:48 -0700747 return pref.ValueOfString(fmt.Sprintf("%d", n))
Damien Neil5ec58b92019-04-30 11:36:39 -0700748 case pref.BytesKind:
749 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700750 return pref.ValueOfBytes(nil)
Damien Neil5ec58b92019-04-30 11:36:39 -0700751 }
Joe Tsai84177c92019-09-17 13:38:48 -0700752 return pref.ValueOfBytes([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
Damien Neil5ec58b92019-04-30 11:36:39 -0700753 }
754 panic("unhandled kind")
755}
756
Joe Tsai0fc49f82019-05-01 12:29:25 -0700757func populateMessage(m pref.Message, n seed, stack []pref.MessageDescriptor) pref.Value {
Damien Neil5ec58b92019-04-30 11:36:39 -0700758 if n == 0 {
Joe Tsai84177c92019-09-17 13:38:48 -0700759 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700760 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700761 md := m.Descriptor()
Damien Neil5ec58b92019-04-30 11:36:39 -0700762 for _, x := range stack {
763 if md == x {
Joe Tsai84177c92019-09-17 13:38:48 -0700764 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700765 }
766 }
767 stack = append(stack, md)
Damien Neil5ec58b92019-04-30 11:36:39 -0700768 for i := 0; i < md.Fields().Len(); i++ {
769 fd := md.Fields().Get(i)
770 if fd.IsWeak() {
771 continue
772 }
Damien Neilf5274512019-08-05 10:48:38 -0700773 m.Set(fd, newValue(m, fd, newSeed(n, i), stack))
Damien Neil5ec58b92019-04-30 11:36:39 -0700774 }
Joe Tsai84177c92019-09-17 13:38:48 -0700775 return pref.ValueOfMessage(m)
Damien Neil5ec58b92019-04-30 11:36:39 -0700776}
Damien Neild91246e2019-06-21 08:36:26 -0700777
778func panics(f func()) (didPanic bool) {
779 defer func() {
780 if err := recover(); err != nil {
781 didPanic = true
782 }
783 }()
784 f()
785 return false
786}