1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsen// Package prototest exercises protobuf reflection. 6*1c12ee1eSDan Willemsenpackage prototest 7*1c12ee1eSDan Willemsen 8*1c12ee1eSDan Willemsenimport ( 9*1c12ee1eSDan Willemsen "bytes" 10*1c12ee1eSDan Willemsen "fmt" 11*1c12ee1eSDan Willemsen "math" 12*1c12ee1eSDan Willemsen "reflect" 13*1c12ee1eSDan Willemsen "sort" 14*1c12ee1eSDan Willemsen "strings" 15*1c12ee1eSDan Willemsen "testing" 16*1c12ee1eSDan Willemsen 17*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/prototext" 18*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 19*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 20*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 21*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoregistry" 22*1c12ee1eSDan Willemsen) 23*1c12ee1eSDan Willemsen 24*1c12ee1eSDan Willemsen// TODO: Test invalid field descriptors or oneof descriptors. 25*1c12ee1eSDan Willemsen// TODO: This should test the functionality that can be provided by fast-paths. 26*1c12ee1eSDan Willemsen 27*1c12ee1eSDan Willemsen// Message tests a message implementation. 28*1c12ee1eSDan Willemsentype Message struct { 29*1c12ee1eSDan Willemsen // Resolver is used to determine the list of extension fields to test with. 30*1c12ee1eSDan Willemsen // If nil, this defaults to using protoregistry.GlobalTypes. 31*1c12ee1eSDan Willemsen Resolver interface { 32*1c12ee1eSDan Willemsen FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) 33*1c12ee1eSDan Willemsen FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) 34*1c12ee1eSDan Willemsen RangeExtensionsByMessage(message protoreflect.FullName, f func(protoreflect.ExtensionType) bool) 35*1c12ee1eSDan Willemsen } 36*1c12ee1eSDan Willemsen} 37*1c12ee1eSDan Willemsen 38*1c12ee1eSDan Willemsen// Test performs tests on a MessageType implementation. 39*1c12ee1eSDan Willemsenfunc (test Message) Test(t testing.TB, mt protoreflect.MessageType) { 40*1c12ee1eSDan Willemsen testType(t, mt) 41*1c12ee1eSDan Willemsen 42*1c12ee1eSDan Willemsen md := mt.Descriptor() 43*1c12ee1eSDan Willemsen m1 := mt.New() 44*1c12ee1eSDan Willemsen for i := 0; i < md.Fields().Len(); i++ { 45*1c12ee1eSDan Willemsen fd := md.Fields().Get(i) 46*1c12ee1eSDan Willemsen testField(t, m1, fd) 47*1c12ee1eSDan Willemsen } 48*1c12ee1eSDan Willemsen if test.Resolver == nil { 49*1c12ee1eSDan Willemsen test.Resolver = protoregistry.GlobalTypes 50*1c12ee1eSDan Willemsen } 51*1c12ee1eSDan Willemsen var extTypes []protoreflect.ExtensionType 52*1c12ee1eSDan Willemsen test.Resolver.RangeExtensionsByMessage(md.FullName(), func(e protoreflect.ExtensionType) bool { 53*1c12ee1eSDan Willemsen extTypes = append(extTypes, e) 54*1c12ee1eSDan Willemsen return true 55*1c12ee1eSDan Willemsen }) 56*1c12ee1eSDan Willemsen for _, xt := range extTypes { 57*1c12ee1eSDan Willemsen testField(t, m1, xt.TypeDescriptor()) 58*1c12ee1eSDan Willemsen } 59*1c12ee1eSDan Willemsen for i := 0; i < md.Oneofs().Len(); i++ { 60*1c12ee1eSDan Willemsen testOneof(t, m1, md.Oneofs().Get(i)) 61*1c12ee1eSDan Willemsen } 62*1c12ee1eSDan Willemsen testUnknown(t, m1) 63*1c12ee1eSDan Willemsen 64*1c12ee1eSDan Willemsen // Test round-trip marshal/unmarshal. 65*1c12ee1eSDan Willemsen m2 := mt.New().Interface() 66*1c12ee1eSDan Willemsen populateMessage(m2.ProtoReflect(), 1, nil) 67*1c12ee1eSDan Willemsen for _, xt := range extTypes { 68*1c12ee1eSDan Willemsen m2.ProtoReflect().Set(xt.TypeDescriptor(), newValue(m2.ProtoReflect(), xt.TypeDescriptor(), 1, nil)) 69*1c12ee1eSDan Willemsen } 70*1c12ee1eSDan Willemsen b, err := proto.MarshalOptions{ 71*1c12ee1eSDan Willemsen AllowPartial: true, 72*1c12ee1eSDan Willemsen }.Marshal(m2) 73*1c12ee1eSDan Willemsen if err != nil { 74*1c12ee1eSDan Willemsen t.Errorf("Marshal() = %v, want nil\n%v", err, prototext.Format(m2)) 75*1c12ee1eSDan Willemsen } 76*1c12ee1eSDan Willemsen m3 := mt.New().Interface() 77*1c12ee1eSDan Willemsen if err := (proto.UnmarshalOptions{ 78*1c12ee1eSDan Willemsen AllowPartial: true, 79*1c12ee1eSDan Willemsen Resolver: test.Resolver, 80*1c12ee1eSDan Willemsen }.Unmarshal(b, m3)); err != nil { 81*1c12ee1eSDan Willemsen t.Errorf("Unmarshal() = %v, want nil\n%v", err, prototext.Format(m2)) 82*1c12ee1eSDan Willemsen } 83*1c12ee1eSDan Willemsen if !proto.Equal(m2, m3) { 84*1c12ee1eSDan Willemsen t.Errorf("round-trip marshal/unmarshal did not preserve message\nOriginal:\n%v\nNew:\n%v", prototext.Format(m2), prototext.Format(m3)) 85*1c12ee1eSDan Willemsen } 86*1c12ee1eSDan Willemsen} 87*1c12ee1eSDan Willemsen 88*1c12ee1eSDan Willemsenfunc testType(t testing.TB, mt protoreflect.MessageType) { 89*1c12ee1eSDan Willemsen m := mt.New().Interface() 90*1c12ee1eSDan Willemsen want := reflect.TypeOf(m) 91*1c12ee1eSDan Willemsen if got := reflect.TypeOf(m.ProtoReflect().Interface()); got != want { 92*1c12ee1eSDan Willemsen t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Interface()): %v != %v", got, want) 93*1c12ee1eSDan Willemsen } 94*1c12ee1eSDan Willemsen if got := reflect.TypeOf(m.ProtoReflect().New().Interface()); got != want { 95*1c12ee1eSDan Willemsen t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().New().Interface()): %v != %v", got, want) 96*1c12ee1eSDan Willemsen } 97*1c12ee1eSDan Willemsen if got := reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()); got != want { 98*1c12ee1eSDan Willemsen t.Errorf("type mismatch: reflect.TypeOf(m) != reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()): %v != %v", got, want) 99*1c12ee1eSDan Willemsen } 100*1c12ee1eSDan Willemsen if mt, ok := mt.(protoreflect.MessageFieldTypes); ok { 101*1c12ee1eSDan Willemsen testFieldTypes(t, mt) 102*1c12ee1eSDan Willemsen } 103*1c12ee1eSDan Willemsen} 104*1c12ee1eSDan Willemsen 105*1c12ee1eSDan Willemsenfunc testFieldTypes(t testing.TB, mt protoreflect.MessageFieldTypes) { 106*1c12ee1eSDan Willemsen descName := func(d protoreflect.Descriptor) protoreflect.FullName { 107*1c12ee1eSDan Willemsen if d == nil { 108*1c12ee1eSDan Willemsen return "<nil>" 109*1c12ee1eSDan Willemsen } 110*1c12ee1eSDan Willemsen return d.FullName() 111*1c12ee1eSDan Willemsen } 112*1c12ee1eSDan Willemsen typeName := func(mt protoreflect.MessageType) protoreflect.FullName { 113*1c12ee1eSDan Willemsen if mt == nil { 114*1c12ee1eSDan Willemsen return "<nil>" 115*1c12ee1eSDan Willemsen } 116*1c12ee1eSDan Willemsen return mt.Descriptor().FullName() 117*1c12ee1eSDan Willemsen } 118*1c12ee1eSDan Willemsen adjustExpr := func(idx int, expr string) string { 119*1c12ee1eSDan Willemsen expr = strings.Replace(expr, "fd.", "md.Fields().Get(i).", -1) 120*1c12ee1eSDan Willemsen expr = strings.Replace(expr, "(fd)", "(md.Fields().Get(i))", -1) 121*1c12ee1eSDan Willemsen expr = strings.Replace(expr, "mti.", "mt.Message(i).", -1) 122*1c12ee1eSDan Willemsen expr = strings.Replace(expr, "(i)", fmt.Sprintf("(%d)", idx), -1) 123*1c12ee1eSDan Willemsen return expr 124*1c12ee1eSDan Willemsen } 125*1c12ee1eSDan Willemsen checkEnumDesc := func(idx int, gotExpr, wantExpr string, got, want protoreflect.EnumDescriptor) { 126*1c12ee1eSDan Willemsen if got != want { 127*1c12ee1eSDan Willemsen t.Errorf("descriptor mismatch: %v != %v: %v != %v", adjustExpr(idx, gotExpr), adjustExpr(idx, wantExpr), descName(got), descName(want)) 128*1c12ee1eSDan Willemsen } 129*1c12ee1eSDan Willemsen } 130*1c12ee1eSDan Willemsen checkMessageDesc := func(idx int, gotExpr, wantExpr string, got, want protoreflect.MessageDescriptor) { 131*1c12ee1eSDan Willemsen if got != want { 132*1c12ee1eSDan Willemsen t.Errorf("descriptor mismatch: %v != %v: %v != %v", adjustExpr(idx, gotExpr), adjustExpr(idx, wantExpr), descName(got), descName(want)) 133*1c12ee1eSDan Willemsen } 134*1c12ee1eSDan Willemsen } 135*1c12ee1eSDan Willemsen checkMessageType := func(idx int, gotExpr, wantExpr string, got, want protoreflect.MessageType) { 136*1c12ee1eSDan Willemsen if got != want { 137*1c12ee1eSDan Willemsen t.Errorf("type mismatch: %v != %v: %v != %v", adjustExpr(idx, gotExpr), adjustExpr(idx, wantExpr), typeName(got), typeName(want)) 138*1c12ee1eSDan Willemsen } 139*1c12ee1eSDan Willemsen } 140*1c12ee1eSDan Willemsen 141*1c12ee1eSDan Willemsen fds := mt.Descriptor().Fields() 142*1c12ee1eSDan Willemsen m := mt.New() 143*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); i++ { 144*1c12ee1eSDan Willemsen fd := fds.Get(i) 145*1c12ee1eSDan Willemsen switch { 146*1c12ee1eSDan Willemsen case fd.IsList(): 147*1c12ee1eSDan Willemsen if fd.Enum() != nil { 148*1c12ee1eSDan Willemsen checkEnumDesc(i, 149*1c12ee1eSDan Willemsen "mt.Enum(i).Descriptor()", "fd.Enum()", 150*1c12ee1eSDan Willemsen mt.Enum(i).Descriptor(), fd.Enum()) 151*1c12ee1eSDan Willemsen } 152*1c12ee1eSDan Willemsen if fd.Message() != nil { 153*1c12ee1eSDan Willemsen checkMessageDesc(i, 154*1c12ee1eSDan Willemsen "mt.Message(i).Descriptor()", "fd.Message()", 155*1c12ee1eSDan Willemsen mt.Message(i).Descriptor(), fd.Message()) 156*1c12ee1eSDan Willemsen checkMessageType(i, 157*1c12ee1eSDan Willemsen "mt.Message(i)", "m.NewField(fd).List().NewElement().Message().Type()", 158*1c12ee1eSDan Willemsen mt.Message(i), m.NewField(fd).List().NewElement().Message().Type()) 159*1c12ee1eSDan Willemsen } 160*1c12ee1eSDan Willemsen case fd.IsMap(): 161*1c12ee1eSDan Willemsen mti := mt.Message(i) 162*1c12ee1eSDan Willemsen if m := mti.New(); m != nil { 163*1c12ee1eSDan Willemsen checkMessageDesc(i, 164*1c12ee1eSDan Willemsen "m.Descriptor()", "fd.Message()", 165*1c12ee1eSDan Willemsen m.Descriptor(), fd.Message()) 166*1c12ee1eSDan Willemsen } 167*1c12ee1eSDan Willemsen if m := mti.Zero(); m != nil { 168*1c12ee1eSDan Willemsen checkMessageDesc(i, 169*1c12ee1eSDan Willemsen "m.Descriptor()", "fd.Message()", 170*1c12ee1eSDan Willemsen m.Descriptor(), fd.Message()) 171*1c12ee1eSDan Willemsen } 172*1c12ee1eSDan Willemsen checkMessageDesc(i, 173*1c12ee1eSDan Willemsen "mti.Descriptor()", "fd.Message()", 174*1c12ee1eSDan Willemsen mti.Descriptor(), fd.Message()) 175*1c12ee1eSDan Willemsen if mti := mti.(protoreflect.MessageFieldTypes); mti != nil { 176*1c12ee1eSDan Willemsen if fd.MapValue().Enum() != nil { 177*1c12ee1eSDan Willemsen checkEnumDesc(i, 178*1c12ee1eSDan Willemsen "mti.Enum(fd.MapValue().Index()).Descriptor()", "fd.MapValue().Enum()", 179*1c12ee1eSDan Willemsen mti.Enum(fd.MapValue().Index()).Descriptor(), fd.MapValue().Enum()) 180*1c12ee1eSDan Willemsen } 181*1c12ee1eSDan Willemsen if fd.MapValue().Message() != nil { 182*1c12ee1eSDan Willemsen checkMessageDesc(i, 183*1c12ee1eSDan Willemsen "mti.Message(fd.MapValue().Index()).Descriptor()", "fd.MapValue().Message()", 184*1c12ee1eSDan Willemsen mti.Message(fd.MapValue().Index()).Descriptor(), fd.MapValue().Message()) 185*1c12ee1eSDan Willemsen checkMessageType(i, 186*1c12ee1eSDan Willemsen "mti.Message(fd.MapValue().Index())", "m.NewField(fd).Map().NewValue().Message().Type()", 187*1c12ee1eSDan Willemsen mti.Message(fd.MapValue().Index()), m.NewField(fd).Map().NewValue().Message().Type()) 188*1c12ee1eSDan Willemsen } 189*1c12ee1eSDan Willemsen } 190*1c12ee1eSDan Willemsen default: 191*1c12ee1eSDan Willemsen if fd.Enum() != nil { 192*1c12ee1eSDan Willemsen checkEnumDesc(i, 193*1c12ee1eSDan Willemsen "mt.Enum(i).Descriptor()", "fd.Enum()", 194*1c12ee1eSDan Willemsen mt.Enum(i).Descriptor(), fd.Enum()) 195*1c12ee1eSDan Willemsen } 196*1c12ee1eSDan Willemsen if fd.Message() != nil { 197*1c12ee1eSDan Willemsen checkMessageDesc(i, 198*1c12ee1eSDan Willemsen "mt.Message(i).Descriptor()", "fd.Message()", 199*1c12ee1eSDan Willemsen mt.Message(i).Descriptor(), fd.Message()) 200*1c12ee1eSDan Willemsen checkMessageType(i, 201*1c12ee1eSDan Willemsen "mt.Message(i)", "m.NewField(fd).Message().Type()", 202*1c12ee1eSDan Willemsen mt.Message(i), m.NewField(fd).Message().Type()) 203*1c12ee1eSDan Willemsen } 204*1c12ee1eSDan Willemsen } 205*1c12ee1eSDan Willemsen } 206*1c12ee1eSDan Willemsen} 207*1c12ee1eSDan Willemsen 208*1c12ee1eSDan Willemsen// testField exercises set/get/has/clear of a field. 209*1c12ee1eSDan Willemsenfunc testField(t testing.TB, m protoreflect.Message, fd protoreflect.FieldDescriptor) { 210*1c12ee1eSDan Willemsen name := fd.FullName() 211*1c12ee1eSDan Willemsen num := fd.Number() 212*1c12ee1eSDan Willemsen 213*1c12ee1eSDan Willemsen switch { 214*1c12ee1eSDan Willemsen case fd.IsList(): 215*1c12ee1eSDan Willemsen testFieldList(t, m, fd) 216*1c12ee1eSDan Willemsen case fd.IsMap(): 217*1c12ee1eSDan Willemsen testFieldMap(t, m, fd) 218*1c12ee1eSDan Willemsen case fd.Message() != nil: 219*1c12ee1eSDan Willemsen default: 220*1c12ee1eSDan Willemsen if got, want := m.NewField(fd), fd.Default(); !valueEqual(got, want) { 221*1c12ee1eSDan Willemsen t.Errorf("Message.NewField(%v) = %v, want default value %v", name, formatValue(got), formatValue(want)) 222*1c12ee1eSDan Willemsen } 223*1c12ee1eSDan Willemsen if fd.Kind() == protoreflect.FloatKind || fd.Kind() == protoreflect.DoubleKind { 224*1c12ee1eSDan Willemsen testFieldFloat(t, m, fd) 225*1c12ee1eSDan Willemsen } 226*1c12ee1eSDan Willemsen } 227*1c12ee1eSDan Willemsen 228*1c12ee1eSDan Willemsen // Set to a non-zero value, the zero value, different non-zero values. 229*1c12ee1eSDan Willemsen for _, n := range []seed{1, 0, minVal, maxVal} { 230*1c12ee1eSDan Willemsen v := newValue(m, fd, n, nil) 231*1c12ee1eSDan Willemsen m.Set(fd, v) 232*1c12ee1eSDan Willemsen wantHas := true 233*1c12ee1eSDan Willemsen if n == 0 { 234*1c12ee1eSDan Willemsen if fd.Syntax() == protoreflect.Proto3 && fd.Message() == nil { 235*1c12ee1eSDan Willemsen wantHas = false 236*1c12ee1eSDan Willemsen } 237*1c12ee1eSDan Willemsen if fd.IsExtension() { 238*1c12ee1eSDan Willemsen wantHas = true 239*1c12ee1eSDan Willemsen } 240*1c12ee1eSDan Willemsen if fd.Cardinality() == protoreflect.Repeated { 241*1c12ee1eSDan Willemsen wantHas = false 242*1c12ee1eSDan Willemsen } 243*1c12ee1eSDan Willemsen if fd.ContainingOneof() != nil { 244*1c12ee1eSDan Willemsen wantHas = true 245*1c12ee1eSDan Willemsen } 246*1c12ee1eSDan Willemsen } 247*1c12ee1eSDan Willemsen if fd.Syntax() == protoreflect.Proto3 && fd.Cardinality() != protoreflect.Repeated && fd.ContainingOneof() == nil && fd.Kind() == protoreflect.EnumKind && v.Enum() == 0 { 248*1c12ee1eSDan Willemsen wantHas = false 249*1c12ee1eSDan Willemsen } 250*1c12ee1eSDan Willemsen if got, want := m.Has(fd), wantHas; got != want { 251*1c12ee1eSDan Willemsen t.Errorf("after setting %q to %v:\nMessage.Has(%v) = %v, want %v", name, formatValue(v), num, got, want) 252*1c12ee1eSDan Willemsen } 253*1c12ee1eSDan Willemsen if got, want := m.Get(fd), v; !valueEqual(got, want) { 254*1c12ee1eSDan Willemsen t.Errorf("after setting %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want)) 255*1c12ee1eSDan Willemsen } 256*1c12ee1eSDan Willemsen found := false 257*1c12ee1eSDan Willemsen m.Range(func(d protoreflect.FieldDescriptor, got protoreflect.Value) bool { 258*1c12ee1eSDan Willemsen if fd != d { 259*1c12ee1eSDan Willemsen return true 260*1c12ee1eSDan Willemsen } 261*1c12ee1eSDan Willemsen found = true 262*1c12ee1eSDan Willemsen if want := v; !valueEqual(got, want) { 263*1c12ee1eSDan Willemsen t.Errorf("after setting %q:\nMessage.Range got value %v, want %v", name, formatValue(got), formatValue(want)) 264*1c12ee1eSDan Willemsen } 265*1c12ee1eSDan Willemsen return true 266*1c12ee1eSDan Willemsen }) 267*1c12ee1eSDan Willemsen if got, want := wantHas, found; got != want { 268*1c12ee1eSDan Willemsen t.Errorf("after setting %q:\nMessageRange saw field: %v, want %v", name, got, want) 269*1c12ee1eSDan Willemsen } 270*1c12ee1eSDan Willemsen } 271*1c12ee1eSDan Willemsen 272*1c12ee1eSDan Willemsen m.Clear(fd) 273*1c12ee1eSDan Willemsen if got, want := m.Has(fd), false; got != want { 274*1c12ee1eSDan Willemsen t.Errorf("after clearing %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want) 275*1c12ee1eSDan Willemsen } 276*1c12ee1eSDan Willemsen switch { 277*1c12ee1eSDan Willemsen case fd.IsList(): 278*1c12ee1eSDan Willemsen if got := m.Get(fd); got.List().Len() != 0 { 279*1c12ee1eSDan Willemsen t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty list", name, num, formatValue(got)) 280*1c12ee1eSDan Willemsen } 281*1c12ee1eSDan Willemsen case fd.IsMap(): 282*1c12ee1eSDan Willemsen if got := m.Get(fd); got.Map().Len() != 0 { 283*1c12ee1eSDan Willemsen t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want empty map", name, num, formatValue(got)) 284*1c12ee1eSDan Willemsen } 285*1c12ee1eSDan Willemsen case fd.Message() == nil: 286*1c12ee1eSDan Willemsen if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) { 287*1c12ee1eSDan Willemsen t.Errorf("after clearing %q:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want)) 288*1c12ee1eSDan Willemsen } 289*1c12ee1eSDan Willemsen } 290*1c12ee1eSDan Willemsen 291*1c12ee1eSDan Willemsen // Set to the default value. 292*1c12ee1eSDan Willemsen switch { 293*1c12ee1eSDan Willemsen case fd.IsList() || fd.IsMap(): 294*1c12ee1eSDan Willemsen m.Set(fd, m.Mutable(fd)) 295*1c12ee1eSDan Willemsen if got, want := m.Has(fd), (fd.IsExtension() && fd.Cardinality() != protoreflect.Repeated) || fd.ContainingOneof() != nil; got != want { 296*1c12ee1eSDan Willemsen t.Errorf("after setting %q to default:\nMessage.Has(%v) = %v, want %v", name, num, got, want) 297*1c12ee1eSDan Willemsen } 298*1c12ee1eSDan Willemsen case fd.Message() == nil: 299*1c12ee1eSDan Willemsen m.Set(fd, m.Get(fd)) 300*1c12ee1eSDan Willemsen if got, want := m.Get(fd), fd.Default(); !valueEqual(got, want) { 301*1c12ee1eSDan Willemsen t.Errorf("after setting %q to default:\nMessage.Get(%v) = %v, want default %v", name, num, formatValue(got), formatValue(want)) 302*1c12ee1eSDan Willemsen } 303*1c12ee1eSDan Willemsen } 304*1c12ee1eSDan Willemsen m.Clear(fd) 305*1c12ee1eSDan Willemsen 306*1c12ee1eSDan Willemsen // Set to the wrong type. 307*1c12ee1eSDan Willemsen v := protoreflect.ValueOfString("") 308*1c12ee1eSDan Willemsen if fd.Kind() == protoreflect.StringKind { 309*1c12ee1eSDan Willemsen v = protoreflect.ValueOfInt32(0) 310*1c12ee1eSDan Willemsen } 311*1c12ee1eSDan Willemsen if !panics(func() { 312*1c12ee1eSDan Willemsen m.Set(fd, v) 313*1c12ee1eSDan Willemsen }) { 314*1c12ee1eSDan Willemsen t.Errorf("setting %v to %T succeeds, want panic", name, v.Interface()) 315*1c12ee1eSDan Willemsen } 316*1c12ee1eSDan Willemsen} 317*1c12ee1eSDan Willemsen 318*1c12ee1eSDan Willemsen// testFieldMap tests set/get/has/clear of entries in a map field. 319*1c12ee1eSDan Willemsenfunc testFieldMap(t testing.TB, m protoreflect.Message, fd protoreflect.FieldDescriptor) { 320*1c12ee1eSDan Willemsen name := fd.FullName() 321*1c12ee1eSDan Willemsen num := fd.Number() 322*1c12ee1eSDan Willemsen 323*1c12ee1eSDan Willemsen // New values. 324*1c12ee1eSDan Willemsen m.Clear(fd) // start with an empty map 325*1c12ee1eSDan Willemsen mapv := m.Get(fd).Map() 326*1c12ee1eSDan Willemsen if mapv.IsValid() { 327*1c12ee1eSDan Willemsen t.Errorf("after clearing field: message.Get(%v).IsValid() = true, want false", name) 328*1c12ee1eSDan Willemsen } 329*1c12ee1eSDan Willemsen if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) { 330*1c12ee1eSDan Willemsen t.Errorf("message.Get(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want)) 331*1c12ee1eSDan Willemsen } 332*1c12ee1eSDan Willemsen if !panics(func() { 333*1c12ee1eSDan Willemsen m.Set(fd, protoreflect.ValueOfMap(mapv)) 334*1c12ee1eSDan Willemsen }) { 335*1c12ee1eSDan Willemsen t.Errorf("message.Set(%v, <invalid>) does not panic", name) 336*1c12ee1eSDan Willemsen } 337*1c12ee1eSDan Willemsen if !panics(func() { 338*1c12ee1eSDan Willemsen mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, nil)) 339*1c12ee1eSDan Willemsen }) { 340*1c12ee1eSDan Willemsen t.Errorf("message.Get(%v).Set(...) of invalid map does not panic", name) 341*1c12ee1eSDan Willemsen } 342*1c12ee1eSDan Willemsen mapv = m.Mutable(fd).Map() // mutable map 343*1c12ee1eSDan Willemsen if !mapv.IsValid() { 344*1c12ee1eSDan Willemsen t.Errorf("message.Mutable(%v).IsValid() = false, want true", name) 345*1c12ee1eSDan Willemsen } 346*1c12ee1eSDan Willemsen if got, want := mapv.NewValue(), newMapValue(fd, mapv, 0, nil); !valueEqual(got, want) { 347*1c12ee1eSDan Willemsen t.Errorf("message.Mutable(%v).NewValue() = %v, want %v", name, formatValue(got), formatValue(want)) 348*1c12ee1eSDan Willemsen } 349*1c12ee1eSDan Willemsen 350*1c12ee1eSDan Willemsen // Add values. 351*1c12ee1eSDan Willemsen want := make(testMap) 352*1c12ee1eSDan Willemsen for i, n := range []seed{1, 0, minVal, maxVal} { 353*1c12ee1eSDan Willemsen if got, want := m.Has(fd), i > 0; got != want { 354*1c12ee1eSDan Willemsen t.Errorf("after inserting %d elements to %q:\nMessage.Has(%v) = %v, want %v", i, name, num, got, want) 355*1c12ee1eSDan Willemsen } 356*1c12ee1eSDan Willemsen 357*1c12ee1eSDan Willemsen k := newMapKey(fd, n) 358*1c12ee1eSDan Willemsen v := newMapValue(fd, mapv, n, nil) 359*1c12ee1eSDan Willemsen mapv.Set(k, v) 360*1c12ee1eSDan Willemsen want.Set(k, v) 361*1c12ee1eSDan Willemsen if got, want := m.Get(fd), protoreflect.ValueOfMap(want); !valueEqual(got, want) { 362*1c12ee1eSDan Willemsen t.Errorf("after inserting %d elements to %q:\nMessage.Get(%v) = %v, want %v", i, name, num, formatValue(got), formatValue(want)) 363*1c12ee1eSDan Willemsen } 364*1c12ee1eSDan Willemsen } 365*1c12ee1eSDan Willemsen 366*1c12ee1eSDan Willemsen // Set values. 367*1c12ee1eSDan Willemsen want.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 368*1c12ee1eSDan Willemsen nv := newMapValue(fd, mapv, 10, nil) 369*1c12ee1eSDan Willemsen mapv.Set(k, nv) 370*1c12ee1eSDan Willemsen want.Set(k, nv) 371*1c12ee1eSDan Willemsen if got, want := m.Get(fd), protoreflect.ValueOfMap(want); !valueEqual(got, want) { 372*1c12ee1eSDan Willemsen t.Errorf("after setting element %v of %q:\nMessage.Get(%v) = %v, want %v", formatValue(k.Value()), name, num, formatValue(got), formatValue(want)) 373*1c12ee1eSDan Willemsen } 374*1c12ee1eSDan Willemsen return true 375*1c12ee1eSDan Willemsen }) 376*1c12ee1eSDan Willemsen 377*1c12ee1eSDan Willemsen // Clear values. 378*1c12ee1eSDan Willemsen want.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 379*1c12ee1eSDan Willemsen mapv.Clear(k) 380*1c12ee1eSDan Willemsen want.Clear(k) 381*1c12ee1eSDan Willemsen if got, want := m.Has(fd), want.Len() > 0; got != want { 382*1c12ee1eSDan Willemsen t.Errorf("after clearing elements of %q:\nMessage.Has(%v) = %v, want %v", name, num, got, want) 383*1c12ee1eSDan Willemsen } 384*1c12ee1eSDan Willemsen if got, want := m.Get(fd), protoreflect.ValueOfMap(want); !valueEqual(got, want) { 385*1c12ee1eSDan Willemsen t.Errorf("after clearing elements of %q:\nMessage.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want)) 386*1c12ee1eSDan Willemsen } 387*1c12ee1eSDan Willemsen return true 388*1c12ee1eSDan Willemsen }) 389*1c12ee1eSDan Willemsen if mapv := m.Get(fd).Map(); mapv.IsValid() { 390*1c12ee1eSDan Willemsen t.Errorf("after clearing all elements: message.Get(%v).IsValid() = true, want false %v", name, formatValue(protoreflect.ValueOfMap(mapv))) 391*1c12ee1eSDan Willemsen } 392*1c12ee1eSDan Willemsen 393*1c12ee1eSDan Willemsen // Non-existent map keys. 394*1c12ee1eSDan Willemsen missingKey := newMapKey(fd, 1) 395*1c12ee1eSDan Willemsen if got, want := mapv.Has(missingKey), false; got != want { 396*1c12ee1eSDan Willemsen t.Errorf("non-existent map key in %q: Map.Has(%v) = %v, want %v", name, formatValue(missingKey.Value()), got, want) 397*1c12ee1eSDan Willemsen } 398*1c12ee1eSDan Willemsen if got, want := mapv.Get(missingKey).IsValid(), false; got != want { 399*1c12ee1eSDan Willemsen t.Errorf("non-existent map key in %q: Map.Get(%v).IsValid() = %v, want %v", name, formatValue(missingKey.Value()), got, want) 400*1c12ee1eSDan Willemsen } 401*1c12ee1eSDan Willemsen mapv.Clear(missingKey) // noop 402*1c12ee1eSDan Willemsen 403*1c12ee1eSDan Willemsen // Mutable. 404*1c12ee1eSDan Willemsen if fd.MapValue().Message() == nil { 405*1c12ee1eSDan Willemsen if !panics(func() { 406*1c12ee1eSDan Willemsen mapv.Mutable(newMapKey(fd, 1)) 407*1c12ee1eSDan Willemsen }) { 408*1c12ee1eSDan Willemsen t.Errorf("Mutable on %q succeeds, want panic", name) 409*1c12ee1eSDan Willemsen } 410*1c12ee1eSDan Willemsen } else { 411*1c12ee1eSDan Willemsen k := newMapKey(fd, 1) 412*1c12ee1eSDan Willemsen v := mapv.Mutable(k) 413*1c12ee1eSDan Willemsen if got, want := mapv.Len(), 1; got != want { 414*1c12ee1eSDan Willemsen t.Errorf("after Mutable on %q, Map.Len() = %v, want %v", name, got, want) 415*1c12ee1eSDan Willemsen } 416*1c12ee1eSDan Willemsen populateMessage(v.Message(), 1, nil) 417*1c12ee1eSDan Willemsen if !valueEqual(mapv.Get(k), v) { 418*1c12ee1eSDan Willemsen t.Errorf("after Mutable on %q, changing new mutable value does not change map entry", name) 419*1c12ee1eSDan Willemsen } 420*1c12ee1eSDan Willemsen mapv.Clear(k) 421*1c12ee1eSDan Willemsen } 422*1c12ee1eSDan Willemsen} 423*1c12ee1eSDan Willemsen 424*1c12ee1eSDan Willemsentype testMap map[interface{}]protoreflect.Value 425*1c12ee1eSDan Willemsen 426*1c12ee1eSDan Willemsenfunc (m testMap) Get(k protoreflect.MapKey) protoreflect.Value { return m[k.Interface()] } 427*1c12ee1eSDan Willemsenfunc (m testMap) Set(k protoreflect.MapKey, v protoreflect.Value) { m[k.Interface()] = v } 428*1c12ee1eSDan Willemsenfunc (m testMap) Has(k protoreflect.MapKey) bool { return m.Get(k).IsValid() } 429*1c12ee1eSDan Willemsenfunc (m testMap) Clear(k protoreflect.MapKey) { delete(m, k.Interface()) } 430*1c12ee1eSDan Willemsenfunc (m testMap) Mutable(k protoreflect.MapKey) protoreflect.Value { panic("unimplemented") } 431*1c12ee1eSDan Willemsenfunc (m testMap) Len() int { return len(m) } 432*1c12ee1eSDan Willemsenfunc (m testMap) NewValue() protoreflect.Value { panic("unimplemented") } 433*1c12ee1eSDan Willemsenfunc (m testMap) Range(f func(protoreflect.MapKey, protoreflect.Value) bool) { 434*1c12ee1eSDan Willemsen for k, v := range m { 435*1c12ee1eSDan Willemsen if !f(protoreflect.ValueOf(k).MapKey(), v) { 436*1c12ee1eSDan Willemsen return 437*1c12ee1eSDan Willemsen } 438*1c12ee1eSDan Willemsen } 439*1c12ee1eSDan Willemsen} 440*1c12ee1eSDan Willemsenfunc (m testMap) IsValid() bool { return true } 441*1c12ee1eSDan Willemsen 442*1c12ee1eSDan Willemsen// testFieldList exercises set/get/append/truncate of values in a list. 443*1c12ee1eSDan Willemsenfunc testFieldList(t testing.TB, m protoreflect.Message, fd protoreflect.FieldDescriptor) { 444*1c12ee1eSDan Willemsen name := fd.FullName() 445*1c12ee1eSDan Willemsen num := fd.Number() 446*1c12ee1eSDan Willemsen 447*1c12ee1eSDan Willemsen m.Clear(fd) // start with an empty list 448*1c12ee1eSDan Willemsen list := m.Get(fd).List() 449*1c12ee1eSDan Willemsen if list.IsValid() { 450*1c12ee1eSDan Willemsen t.Errorf("message.Get(%v).IsValid() = true, want false", name) 451*1c12ee1eSDan Willemsen } 452*1c12ee1eSDan Willemsen if !panics(func() { 453*1c12ee1eSDan Willemsen m.Set(fd, protoreflect.ValueOfList(list)) 454*1c12ee1eSDan Willemsen }) { 455*1c12ee1eSDan Willemsen t.Errorf("message.Set(%v, <invalid>) does not panic", name) 456*1c12ee1eSDan Willemsen } 457*1c12ee1eSDan Willemsen if !panics(func() { 458*1c12ee1eSDan Willemsen list.Append(newListElement(fd, list, 0, nil)) 459*1c12ee1eSDan Willemsen }) { 460*1c12ee1eSDan Willemsen t.Errorf("message.Get(%v).Append(...) of invalid list does not panic", name) 461*1c12ee1eSDan Willemsen } 462*1c12ee1eSDan Willemsen if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) { 463*1c12ee1eSDan Willemsen t.Errorf("message.Get(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want)) 464*1c12ee1eSDan Willemsen } 465*1c12ee1eSDan Willemsen list = m.Mutable(fd).List() // mutable list 466*1c12ee1eSDan Willemsen if !list.IsValid() { 467*1c12ee1eSDan Willemsen t.Errorf("message.Get(%v).IsValid() = false, want true", name) 468*1c12ee1eSDan Willemsen } 469*1c12ee1eSDan Willemsen if got, want := list.NewElement(), newListElement(fd, list, 0, nil); !valueEqual(got, want) { 470*1c12ee1eSDan Willemsen t.Errorf("message.Mutable(%v).NewElement() = %v, want %v", name, formatValue(got), formatValue(want)) 471*1c12ee1eSDan Willemsen } 472*1c12ee1eSDan Willemsen 473*1c12ee1eSDan Willemsen // Append values. 474*1c12ee1eSDan Willemsen var want protoreflect.List = &testList{} 475*1c12ee1eSDan Willemsen for i, n := range []seed{1, 0, minVal, maxVal} { 476*1c12ee1eSDan Willemsen if got, want := m.Has(fd), i > 0; got != want { 477*1c12ee1eSDan Willemsen t.Errorf("after appending %d elements to %q:\nMessage.Has(%v) = %v, want %v", i, name, num, got, want) 478*1c12ee1eSDan Willemsen } 479*1c12ee1eSDan Willemsen v := newListElement(fd, list, n, nil) 480*1c12ee1eSDan Willemsen want.Append(v) 481*1c12ee1eSDan Willemsen list.Append(v) 482*1c12ee1eSDan Willemsen 483*1c12ee1eSDan Willemsen if got, want := m.Get(fd), protoreflect.ValueOfList(want); !valueEqual(got, want) { 484*1c12ee1eSDan Willemsen t.Errorf("after appending %d elements to %q:\nMessage.Get(%v) = %v, want %v", i+1, name, num, formatValue(got), formatValue(want)) 485*1c12ee1eSDan Willemsen } 486*1c12ee1eSDan Willemsen } 487*1c12ee1eSDan Willemsen 488*1c12ee1eSDan Willemsen // Set values. 489*1c12ee1eSDan Willemsen for i := 0; i < want.Len(); i++ { 490*1c12ee1eSDan Willemsen v := newListElement(fd, list, seed(i+10), nil) 491*1c12ee1eSDan Willemsen want.Set(i, v) 492*1c12ee1eSDan Willemsen list.Set(i, v) 493*1c12ee1eSDan Willemsen if got, want := m.Get(fd), protoreflect.ValueOfList(want); !valueEqual(got, want) { 494*1c12ee1eSDan Willemsen t.Errorf("after setting element %d of %q:\nMessage.Get(%v) = %v, want %v", i, name, num, formatValue(got), formatValue(want)) 495*1c12ee1eSDan Willemsen } 496*1c12ee1eSDan Willemsen } 497*1c12ee1eSDan Willemsen 498*1c12ee1eSDan Willemsen // Truncate. 499*1c12ee1eSDan Willemsen for want.Len() > 0 { 500*1c12ee1eSDan Willemsen n := want.Len() - 1 501*1c12ee1eSDan Willemsen want.Truncate(n) 502*1c12ee1eSDan Willemsen list.Truncate(n) 503*1c12ee1eSDan Willemsen if got, want := m.Has(fd), want.Len() > 0; got != want { 504*1c12ee1eSDan Willemsen t.Errorf("after truncating %q to %d:\nMessage.Has(%v) = %v, want %v", name, n, num, got, want) 505*1c12ee1eSDan Willemsen } 506*1c12ee1eSDan Willemsen if got, want := m.Get(fd), protoreflect.ValueOfList(want); !valueEqual(got, want) { 507*1c12ee1eSDan Willemsen t.Errorf("after truncating %q to %d:\nMessage.Get(%v) = %v, want %v", name, n, num, formatValue(got), formatValue(want)) 508*1c12ee1eSDan Willemsen } 509*1c12ee1eSDan Willemsen } 510*1c12ee1eSDan Willemsen 511*1c12ee1eSDan Willemsen // AppendMutable. 512*1c12ee1eSDan Willemsen if fd.Message() == nil { 513*1c12ee1eSDan Willemsen if !panics(func() { 514*1c12ee1eSDan Willemsen list.AppendMutable() 515*1c12ee1eSDan Willemsen }) { 516*1c12ee1eSDan Willemsen t.Errorf("AppendMutable on %q succeeds, want panic", name) 517*1c12ee1eSDan Willemsen } 518*1c12ee1eSDan Willemsen } else { 519*1c12ee1eSDan Willemsen v := list.AppendMutable() 520*1c12ee1eSDan Willemsen if got, want := list.Len(), 1; got != want { 521*1c12ee1eSDan Willemsen t.Errorf("after AppendMutable on %q, list.Len() = %v, want %v", name, got, want) 522*1c12ee1eSDan Willemsen } 523*1c12ee1eSDan Willemsen populateMessage(v.Message(), 1, nil) 524*1c12ee1eSDan Willemsen if !valueEqual(list.Get(0), v) { 525*1c12ee1eSDan Willemsen t.Errorf("after AppendMutable on %q, changing new mutable value does not change list item 0", name) 526*1c12ee1eSDan Willemsen } 527*1c12ee1eSDan Willemsen want.Truncate(0) 528*1c12ee1eSDan Willemsen } 529*1c12ee1eSDan Willemsen} 530*1c12ee1eSDan Willemsen 531*1c12ee1eSDan Willemsentype testList struct { 532*1c12ee1eSDan Willemsen a []protoreflect.Value 533*1c12ee1eSDan Willemsen} 534*1c12ee1eSDan Willemsen 535*1c12ee1eSDan Willemsenfunc (l *testList) Append(v protoreflect.Value) { l.a = append(l.a, v) } 536*1c12ee1eSDan Willemsenfunc (l *testList) AppendMutable() protoreflect.Value { panic("unimplemented") } 537*1c12ee1eSDan Willemsenfunc (l *testList) Get(n int) protoreflect.Value { return l.a[n] } 538*1c12ee1eSDan Willemsenfunc (l *testList) Len() int { return len(l.a) } 539*1c12ee1eSDan Willemsenfunc (l *testList) Set(n int, v protoreflect.Value) { l.a[n] = v } 540*1c12ee1eSDan Willemsenfunc (l *testList) Truncate(n int) { l.a = l.a[:n] } 541*1c12ee1eSDan Willemsenfunc (l *testList) NewElement() protoreflect.Value { panic("unimplemented") } 542*1c12ee1eSDan Willemsenfunc (l *testList) IsValid() bool { return true } 543*1c12ee1eSDan Willemsen 544*1c12ee1eSDan Willemsen// testFieldFloat exercises some interesting floating-point scalar field values. 545*1c12ee1eSDan Willemsenfunc testFieldFloat(t testing.TB, m protoreflect.Message, fd protoreflect.FieldDescriptor) { 546*1c12ee1eSDan Willemsen name := fd.FullName() 547*1c12ee1eSDan Willemsen num := fd.Number() 548*1c12ee1eSDan Willemsen 549*1c12ee1eSDan Willemsen for _, v := range []float64{math.Inf(-1), math.Inf(1), math.NaN(), math.Copysign(0, -1)} { 550*1c12ee1eSDan Willemsen var val protoreflect.Value 551*1c12ee1eSDan Willemsen if fd.Kind() == protoreflect.FloatKind { 552*1c12ee1eSDan Willemsen val = protoreflect.ValueOfFloat32(float32(v)) 553*1c12ee1eSDan Willemsen } else { 554*1c12ee1eSDan Willemsen val = protoreflect.ValueOfFloat64(float64(v)) 555*1c12ee1eSDan Willemsen } 556*1c12ee1eSDan Willemsen m.Set(fd, val) 557*1c12ee1eSDan Willemsen // Note that Has is true for -0. 558*1c12ee1eSDan Willemsen if got, want := m.Has(fd), true; got != want { 559*1c12ee1eSDan Willemsen t.Errorf("after setting %v to %v: Message.Has(%v) = %v, want %v", name, v, num, got, want) 560*1c12ee1eSDan Willemsen } 561*1c12ee1eSDan Willemsen if got, want := m.Get(fd), val; !valueEqual(got, want) { 562*1c12ee1eSDan Willemsen t.Errorf("after setting %v: Message.Get(%v) = %v, want %v", name, num, formatValue(got), formatValue(want)) 563*1c12ee1eSDan Willemsen } 564*1c12ee1eSDan Willemsen } 565*1c12ee1eSDan Willemsen} 566*1c12ee1eSDan Willemsen 567*1c12ee1eSDan Willemsen// testOneof tests the behavior of fields in a oneof. 568*1c12ee1eSDan Willemsenfunc testOneof(t testing.TB, m protoreflect.Message, od protoreflect.OneofDescriptor) { 569*1c12ee1eSDan Willemsen for _, mutable := range []bool{false, true} { 570*1c12ee1eSDan Willemsen for i := 0; i < od.Fields().Len(); i++ { 571*1c12ee1eSDan Willemsen fda := od.Fields().Get(i) 572*1c12ee1eSDan Willemsen if mutable { 573*1c12ee1eSDan Willemsen // Set fields by requesting a mutable reference. 574*1c12ee1eSDan Willemsen if !fda.IsMap() && !fda.IsList() && fda.Message() == nil { 575*1c12ee1eSDan Willemsen continue 576*1c12ee1eSDan Willemsen } 577*1c12ee1eSDan Willemsen _ = m.Mutable(fda) 578*1c12ee1eSDan Willemsen } else { 579*1c12ee1eSDan Willemsen // Set fields explicitly. 580*1c12ee1eSDan Willemsen m.Set(fda, newValue(m, fda, 1, nil)) 581*1c12ee1eSDan Willemsen } 582*1c12ee1eSDan Willemsen if got, want := m.WhichOneof(od), fda; got != want { 583*1c12ee1eSDan Willemsen t.Errorf("after setting oneof field %q:\nWhichOneof(%q) = %v, want %v", fda.FullName(), fda.Name(), got, want) 584*1c12ee1eSDan Willemsen } 585*1c12ee1eSDan Willemsen for j := 0; j < od.Fields().Len(); j++ { 586*1c12ee1eSDan Willemsen fdb := od.Fields().Get(j) 587*1c12ee1eSDan Willemsen if got, want := m.Has(fdb), i == j; got != want { 588*1c12ee1eSDan Willemsen t.Errorf("after setting oneof field %q:\nGet(%q) = %v, want %v", fda.FullName(), fdb.FullName(), got, want) 589*1c12ee1eSDan Willemsen } 590*1c12ee1eSDan Willemsen } 591*1c12ee1eSDan Willemsen } 592*1c12ee1eSDan Willemsen } 593*1c12ee1eSDan Willemsen} 594*1c12ee1eSDan Willemsen 595*1c12ee1eSDan Willemsen// testUnknown tests the behavior of unknown fields. 596*1c12ee1eSDan Willemsenfunc testUnknown(t testing.TB, m protoreflect.Message) { 597*1c12ee1eSDan Willemsen var b []byte 598*1c12ee1eSDan Willemsen b = protowire.AppendTag(b, 1000, protowire.VarintType) 599*1c12ee1eSDan Willemsen b = protowire.AppendVarint(b, 1001) 600*1c12ee1eSDan Willemsen m.SetUnknown(protoreflect.RawFields(b)) 601*1c12ee1eSDan Willemsen if got, want := []byte(m.GetUnknown()), b; !bytes.Equal(got, want) { 602*1c12ee1eSDan Willemsen t.Errorf("after setting unknown fields:\nGetUnknown() = %v, want %v", got, want) 603*1c12ee1eSDan Willemsen } 604*1c12ee1eSDan Willemsen} 605*1c12ee1eSDan Willemsen 606*1c12ee1eSDan Willemsenfunc formatValue(v protoreflect.Value) string { 607*1c12ee1eSDan Willemsen switch v := v.Interface().(type) { 608*1c12ee1eSDan Willemsen case protoreflect.List: 609*1c12ee1eSDan Willemsen var buf bytes.Buffer 610*1c12ee1eSDan Willemsen buf.WriteString("list[") 611*1c12ee1eSDan Willemsen for i := 0; i < v.Len(); i++ { 612*1c12ee1eSDan Willemsen if i > 0 { 613*1c12ee1eSDan Willemsen buf.WriteString(" ") 614*1c12ee1eSDan Willemsen } 615*1c12ee1eSDan Willemsen buf.WriteString(formatValue(v.Get(i))) 616*1c12ee1eSDan Willemsen } 617*1c12ee1eSDan Willemsen buf.WriteString("]") 618*1c12ee1eSDan Willemsen return buf.String() 619*1c12ee1eSDan Willemsen case protoreflect.Map: 620*1c12ee1eSDan Willemsen var buf bytes.Buffer 621*1c12ee1eSDan Willemsen buf.WriteString("map[") 622*1c12ee1eSDan Willemsen var keys []protoreflect.MapKey 623*1c12ee1eSDan Willemsen v.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 624*1c12ee1eSDan Willemsen keys = append(keys, k) 625*1c12ee1eSDan Willemsen return true 626*1c12ee1eSDan Willemsen }) 627*1c12ee1eSDan Willemsen sort.Slice(keys, func(i, j int) bool { 628*1c12ee1eSDan Willemsen return keys[i].String() < keys[j].String() 629*1c12ee1eSDan Willemsen }) 630*1c12ee1eSDan Willemsen for i, k := range keys { 631*1c12ee1eSDan Willemsen if i > 0 { 632*1c12ee1eSDan Willemsen buf.WriteString(" ") 633*1c12ee1eSDan Willemsen } 634*1c12ee1eSDan Willemsen buf.WriteString(formatValue(k.Value())) 635*1c12ee1eSDan Willemsen buf.WriteString(":") 636*1c12ee1eSDan Willemsen buf.WriteString(formatValue(v.Get(k))) 637*1c12ee1eSDan Willemsen } 638*1c12ee1eSDan Willemsen buf.WriteString("]") 639*1c12ee1eSDan Willemsen return buf.String() 640*1c12ee1eSDan Willemsen case protoreflect.Message: 641*1c12ee1eSDan Willemsen b, err := prototext.Marshal(v.Interface()) 642*1c12ee1eSDan Willemsen if err != nil { 643*1c12ee1eSDan Willemsen return fmt.Sprintf("<%v>", err) 644*1c12ee1eSDan Willemsen } 645*1c12ee1eSDan Willemsen return fmt.Sprintf("%v{%s}", v.Descriptor().FullName(), b) 646*1c12ee1eSDan Willemsen case string: 647*1c12ee1eSDan Willemsen return fmt.Sprintf("%q", v) 648*1c12ee1eSDan Willemsen default: 649*1c12ee1eSDan Willemsen return fmt.Sprint(v) 650*1c12ee1eSDan Willemsen } 651*1c12ee1eSDan Willemsen} 652*1c12ee1eSDan Willemsen 653*1c12ee1eSDan Willemsenfunc valueEqual(a, b protoreflect.Value) bool { 654*1c12ee1eSDan Willemsen ai, bi := a.Interface(), b.Interface() 655*1c12ee1eSDan Willemsen switch ai.(type) { 656*1c12ee1eSDan Willemsen case protoreflect.Message: 657*1c12ee1eSDan Willemsen return proto.Equal( 658*1c12ee1eSDan Willemsen a.Message().Interface(), 659*1c12ee1eSDan Willemsen b.Message().Interface(), 660*1c12ee1eSDan Willemsen ) 661*1c12ee1eSDan Willemsen case protoreflect.List: 662*1c12ee1eSDan Willemsen lista, listb := a.List(), b.List() 663*1c12ee1eSDan Willemsen if lista.Len() != listb.Len() { 664*1c12ee1eSDan Willemsen return false 665*1c12ee1eSDan Willemsen } 666*1c12ee1eSDan Willemsen for i := 0; i < lista.Len(); i++ { 667*1c12ee1eSDan Willemsen if !valueEqual(lista.Get(i), listb.Get(i)) { 668*1c12ee1eSDan Willemsen return false 669*1c12ee1eSDan Willemsen } 670*1c12ee1eSDan Willemsen } 671*1c12ee1eSDan Willemsen return true 672*1c12ee1eSDan Willemsen case protoreflect.Map: 673*1c12ee1eSDan Willemsen mapa, mapb := a.Map(), b.Map() 674*1c12ee1eSDan Willemsen if mapa.Len() != mapb.Len() { 675*1c12ee1eSDan Willemsen return false 676*1c12ee1eSDan Willemsen } 677*1c12ee1eSDan Willemsen equal := true 678*1c12ee1eSDan Willemsen mapa.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 679*1c12ee1eSDan Willemsen if !valueEqual(v, mapb.Get(k)) { 680*1c12ee1eSDan Willemsen equal = false 681*1c12ee1eSDan Willemsen return false 682*1c12ee1eSDan Willemsen } 683*1c12ee1eSDan Willemsen return true 684*1c12ee1eSDan Willemsen }) 685*1c12ee1eSDan Willemsen return equal 686*1c12ee1eSDan Willemsen case []byte: 687*1c12ee1eSDan Willemsen return bytes.Equal(a.Bytes(), b.Bytes()) 688*1c12ee1eSDan Willemsen case float32: 689*1c12ee1eSDan Willemsen // NaNs are equal, but must be the same NaN. 690*1c12ee1eSDan Willemsen return math.Float32bits(ai.(float32)) == math.Float32bits(bi.(float32)) 691*1c12ee1eSDan Willemsen case float64: 692*1c12ee1eSDan Willemsen // NaNs are equal, but must be the same NaN. 693*1c12ee1eSDan Willemsen return math.Float64bits(ai.(float64)) == math.Float64bits(bi.(float64)) 694*1c12ee1eSDan Willemsen default: 695*1c12ee1eSDan Willemsen return ai == bi 696*1c12ee1eSDan Willemsen } 697*1c12ee1eSDan Willemsen} 698*1c12ee1eSDan Willemsen 699*1c12ee1eSDan Willemsen// A seed is used to vary the content of a value. 700*1c12ee1eSDan Willemsen// 701*1c12ee1eSDan Willemsen// A seed of 0 is the zero value. Messages do not have a zero-value; a 0-seeded messages 702*1c12ee1eSDan Willemsen// is unpopulated. 703*1c12ee1eSDan Willemsen// 704*1c12ee1eSDan Willemsen// A seed of minVal or maxVal is the least or greatest value of the value type. 705*1c12ee1eSDan Willemsentype seed int 706*1c12ee1eSDan Willemsen 707*1c12ee1eSDan Willemsenconst ( 708*1c12ee1eSDan Willemsen minVal seed = -1 709*1c12ee1eSDan Willemsen maxVal seed = -2 710*1c12ee1eSDan Willemsen) 711*1c12ee1eSDan Willemsen 712*1c12ee1eSDan Willemsen// newSeed creates new seed values from a base, for example to create seeds for the 713*1c12ee1eSDan Willemsen// elements in a list. If the input seed is minVal or maxVal, so is the output. 714*1c12ee1eSDan Willemsenfunc newSeed(n seed, adjust ...int) seed { 715*1c12ee1eSDan Willemsen switch n { 716*1c12ee1eSDan Willemsen case minVal, maxVal: 717*1c12ee1eSDan Willemsen return n 718*1c12ee1eSDan Willemsen } 719*1c12ee1eSDan Willemsen for _, a := range adjust { 720*1c12ee1eSDan Willemsen n = 10*n + seed(a) 721*1c12ee1eSDan Willemsen } 722*1c12ee1eSDan Willemsen return n 723*1c12ee1eSDan Willemsen} 724*1c12ee1eSDan Willemsen 725*1c12ee1eSDan Willemsen// newValue returns a new value assignable to a field. 726*1c12ee1eSDan Willemsen// 727*1c12ee1eSDan Willemsen// The stack parameter is used to avoid infinite recursion when populating circular 728*1c12ee1eSDan Willemsen// data structures. 729*1c12ee1eSDan Willemsenfunc newValue(m protoreflect.Message, fd protoreflect.FieldDescriptor, n seed, stack []protoreflect.MessageDescriptor) protoreflect.Value { 730*1c12ee1eSDan Willemsen switch { 731*1c12ee1eSDan Willemsen case fd.IsList(): 732*1c12ee1eSDan Willemsen if n == 0 { 733*1c12ee1eSDan Willemsen return m.New().Mutable(fd) 734*1c12ee1eSDan Willemsen } 735*1c12ee1eSDan Willemsen list := m.NewField(fd).List() 736*1c12ee1eSDan Willemsen list.Append(newListElement(fd, list, 0, stack)) 737*1c12ee1eSDan Willemsen list.Append(newListElement(fd, list, minVal, stack)) 738*1c12ee1eSDan Willemsen list.Append(newListElement(fd, list, maxVal, stack)) 739*1c12ee1eSDan Willemsen list.Append(newListElement(fd, list, n, stack)) 740*1c12ee1eSDan Willemsen return protoreflect.ValueOfList(list) 741*1c12ee1eSDan Willemsen case fd.IsMap(): 742*1c12ee1eSDan Willemsen if n == 0 { 743*1c12ee1eSDan Willemsen return m.New().Mutable(fd) 744*1c12ee1eSDan Willemsen } 745*1c12ee1eSDan Willemsen mapv := m.NewField(fd).Map() 746*1c12ee1eSDan Willemsen mapv.Set(newMapKey(fd, 0), newMapValue(fd, mapv, 0, stack)) 747*1c12ee1eSDan Willemsen mapv.Set(newMapKey(fd, minVal), newMapValue(fd, mapv, minVal, stack)) 748*1c12ee1eSDan Willemsen mapv.Set(newMapKey(fd, maxVal), newMapValue(fd, mapv, maxVal, stack)) 749*1c12ee1eSDan Willemsen mapv.Set(newMapKey(fd, n), newMapValue(fd, mapv, newSeed(n, 0), stack)) 750*1c12ee1eSDan Willemsen return protoreflect.ValueOfMap(mapv) 751*1c12ee1eSDan Willemsen case fd.Message() != nil: 752*1c12ee1eSDan Willemsen return populateMessage(m.NewField(fd).Message(), n, stack) 753*1c12ee1eSDan Willemsen default: 754*1c12ee1eSDan Willemsen return newScalarValue(fd, n) 755*1c12ee1eSDan Willemsen } 756*1c12ee1eSDan Willemsen} 757*1c12ee1eSDan Willemsen 758*1c12ee1eSDan Willemsenfunc newListElement(fd protoreflect.FieldDescriptor, list protoreflect.List, n seed, stack []protoreflect.MessageDescriptor) protoreflect.Value { 759*1c12ee1eSDan Willemsen if fd.Message() == nil { 760*1c12ee1eSDan Willemsen return newScalarValue(fd, n) 761*1c12ee1eSDan Willemsen } 762*1c12ee1eSDan Willemsen return populateMessage(list.NewElement().Message(), n, stack) 763*1c12ee1eSDan Willemsen} 764*1c12ee1eSDan Willemsen 765*1c12ee1eSDan Willemsenfunc newMapKey(fd protoreflect.FieldDescriptor, n seed) protoreflect.MapKey { 766*1c12ee1eSDan Willemsen kd := fd.MapKey() 767*1c12ee1eSDan Willemsen return newScalarValue(kd, n).MapKey() 768*1c12ee1eSDan Willemsen} 769*1c12ee1eSDan Willemsen 770*1c12ee1eSDan Willemsenfunc newMapValue(fd protoreflect.FieldDescriptor, mapv protoreflect.Map, n seed, stack []protoreflect.MessageDescriptor) protoreflect.Value { 771*1c12ee1eSDan Willemsen vd := fd.MapValue() 772*1c12ee1eSDan Willemsen if vd.Message() == nil { 773*1c12ee1eSDan Willemsen return newScalarValue(vd, n) 774*1c12ee1eSDan Willemsen } 775*1c12ee1eSDan Willemsen return populateMessage(mapv.NewValue().Message(), n, stack) 776*1c12ee1eSDan Willemsen} 777*1c12ee1eSDan Willemsen 778*1c12ee1eSDan Willemsenfunc newScalarValue(fd protoreflect.FieldDescriptor, n seed) protoreflect.Value { 779*1c12ee1eSDan Willemsen switch fd.Kind() { 780*1c12ee1eSDan Willemsen case protoreflect.BoolKind: 781*1c12ee1eSDan Willemsen return protoreflect.ValueOfBool(n != 0) 782*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 783*1c12ee1eSDan Willemsen vals := fd.Enum().Values() 784*1c12ee1eSDan Willemsen var i int 785*1c12ee1eSDan Willemsen switch n { 786*1c12ee1eSDan Willemsen case minVal: 787*1c12ee1eSDan Willemsen i = 0 788*1c12ee1eSDan Willemsen case maxVal: 789*1c12ee1eSDan Willemsen i = vals.Len() - 1 790*1c12ee1eSDan Willemsen default: 791*1c12ee1eSDan Willemsen i = int(n) % vals.Len() 792*1c12ee1eSDan Willemsen } 793*1c12ee1eSDan Willemsen return protoreflect.ValueOfEnum(vals.Get(i).Number()) 794*1c12ee1eSDan Willemsen case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 795*1c12ee1eSDan Willemsen switch n { 796*1c12ee1eSDan Willemsen case minVal: 797*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt32(math.MinInt32) 798*1c12ee1eSDan Willemsen case maxVal: 799*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt32(math.MaxInt32) 800*1c12ee1eSDan Willemsen default: 801*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt32(int32(n)) 802*1c12ee1eSDan Willemsen } 803*1c12ee1eSDan Willemsen case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 804*1c12ee1eSDan Willemsen switch n { 805*1c12ee1eSDan Willemsen case minVal: 806*1c12ee1eSDan Willemsen // Only use 0 for the zero value. 807*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint32(1) 808*1c12ee1eSDan Willemsen case maxVal: 809*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint32(math.MaxInt32) 810*1c12ee1eSDan Willemsen default: 811*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint32(uint32(n)) 812*1c12ee1eSDan Willemsen } 813*1c12ee1eSDan Willemsen case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 814*1c12ee1eSDan Willemsen switch n { 815*1c12ee1eSDan Willemsen case minVal: 816*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt64(math.MinInt64) 817*1c12ee1eSDan Willemsen case maxVal: 818*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt64(math.MaxInt64) 819*1c12ee1eSDan Willemsen default: 820*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt64(int64(n)) 821*1c12ee1eSDan Willemsen } 822*1c12ee1eSDan Willemsen case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 823*1c12ee1eSDan Willemsen switch n { 824*1c12ee1eSDan Willemsen case minVal: 825*1c12ee1eSDan Willemsen // Only use 0 for the zero value. 826*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint64(1) 827*1c12ee1eSDan Willemsen case maxVal: 828*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint64(math.MaxInt64) 829*1c12ee1eSDan Willemsen default: 830*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint64(uint64(n)) 831*1c12ee1eSDan Willemsen } 832*1c12ee1eSDan Willemsen case protoreflect.FloatKind: 833*1c12ee1eSDan Willemsen switch n { 834*1c12ee1eSDan Willemsen case minVal: 835*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat32(math.SmallestNonzeroFloat32) 836*1c12ee1eSDan Willemsen case maxVal: 837*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat32(math.MaxFloat32) 838*1c12ee1eSDan Willemsen default: 839*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat32(1.5 * float32(n)) 840*1c12ee1eSDan Willemsen } 841*1c12ee1eSDan Willemsen case protoreflect.DoubleKind: 842*1c12ee1eSDan Willemsen switch n { 843*1c12ee1eSDan Willemsen case minVal: 844*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat64(math.SmallestNonzeroFloat64) 845*1c12ee1eSDan Willemsen case maxVal: 846*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat64(math.MaxFloat64) 847*1c12ee1eSDan Willemsen default: 848*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat64(1.5 * float64(n)) 849*1c12ee1eSDan Willemsen } 850*1c12ee1eSDan Willemsen case protoreflect.StringKind: 851*1c12ee1eSDan Willemsen if n == 0 { 852*1c12ee1eSDan Willemsen return protoreflect.ValueOfString("") 853*1c12ee1eSDan Willemsen } 854*1c12ee1eSDan Willemsen return protoreflect.ValueOfString(fmt.Sprintf("%d", n)) 855*1c12ee1eSDan Willemsen case protoreflect.BytesKind: 856*1c12ee1eSDan Willemsen if n == 0 { 857*1c12ee1eSDan Willemsen return protoreflect.ValueOfBytes(nil) 858*1c12ee1eSDan Willemsen } 859*1c12ee1eSDan Willemsen return protoreflect.ValueOfBytes([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)}) 860*1c12ee1eSDan Willemsen } 861*1c12ee1eSDan Willemsen panic("unhandled kind") 862*1c12ee1eSDan Willemsen} 863*1c12ee1eSDan Willemsen 864*1c12ee1eSDan Willemsenfunc populateMessage(m protoreflect.Message, n seed, stack []protoreflect.MessageDescriptor) protoreflect.Value { 865*1c12ee1eSDan Willemsen if n == 0 { 866*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(m) 867*1c12ee1eSDan Willemsen } 868*1c12ee1eSDan Willemsen md := m.Descriptor() 869*1c12ee1eSDan Willemsen for _, x := range stack { 870*1c12ee1eSDan Willemsen if md == x { 871*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(m) 872*1c12ee1eSDan Willemsen } 873*1c12ee1eSDan Willemsen } 874*1c12ee1eSDan Willemsen stack = append(stack, md) 875*1c12ee1eSDan Willemsen for i := 0; i < md.Fields().Len(); i++ { 876*1c12ee1eSDan Willemsen fd := md.Fields().Get(i) 877*1c12ee1eSDan Willemsen if fd.IsWeak() { 878*1c12ee1eSDan Willemsen continue 879*1c12ee1eSDan Willemsen } 880*1c12ee1eSDan Willemsen m.Set(fd, newValue(m, fd, newSeed(n, i), stack)) 881*1c12ee1eSDan Willemsen } 882*1c12ee1eSDan Willemsen return protoreflect.ValueOfMessage(m) 883*1c12ee1eSDan Willemsen} 884*1c12ee1eSDan Willemsen 885*1c12ee1eSDan Willemsenfunc panics(f func()) (didPanic bool) { 886*1c12ee1eSDan Willemsen defer func() { 887*1c12ee1eSDan Willemsen if err := recover(); err != nil { 888*1c12ee1eSDan Willemsen didPanic = true 889*1c12ee1eSDan Willemsen } 890*1c12ee1eSDan Willemsen }() 891*1c12ee1eSDan Willemsen f() 892*1c12ee1eSDan Willemsen return false 893*1c12ee1eSDan Willemsen} 894