1*1c12ee1eSDan Willemsen// Copyright 2021 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 Willemsenpackage nullable 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "reflect" 9*1c12ee1eSDan Willemsen "testing" 10*1c12ee1eSDan Willemsen 11*1c12ee1eSDan Willemsen "github.com/google/go-cmp/cmp" 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoimpl" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/testing/protocmp" 16*1c12ee1eSDan Willemsen) 17*1c12ee1eSDan Willemsen 18*1c12ee1eSDan Willemsenfunc Test(t *testing.T) { 19*1c12ee1eSDan Willemsen for _, mt := range []protoreflect.MessageType{ 20*1c12ee1eSDan Willemsen protoimpl.X.ProtoMessageV2Of((*Proto2)(nil)).ProtoReflect().Type(), 21*1c12ee1eSDan Willemsen protoimpl.X.ProtoMessageV2Of((*Proto3)(nil)).ProtoReflect().Type(), 22*1c12ee1eSDan Willemsen } { 23*1c12ee1eSDan Willemsen t.Run(string(mt.Descriptor().FullName()), func(t *testing.T) { 24*1c12ee1eSDan Willemsen testEmptyMessage(t, mt.Zero(), false) 25*1c12ee1eSDan Willemsen testEmptyMessage(t, mt.New(), true) 26*1c12ee1eSDan Willemsen //testMethods(t, mt) 27*1c12ee1eSDan Willemsen }) 28*1c12ee1eSDan Willemsen } 29*1c12ee1eSDan Willemsen} 30*1c12ee1eSDan Willemsen 31*1c12ee1eSDan Willemsenvar methodTestProtos = []protoreflect.MessageType{ 32*1c12ee1eSDan Willemsen protoimpl.X.ProtoMessageV2Of((*Methods)(nil)).ProtoReflect().Type(), 33*1c12ee1eSDan Willemsen} 34*1c12ee1eSDan Willemsen 35*1c12ee1eSDan Willemsenfunc TestMethods(t *testing.T) { 36*1c12ee1eSDan Willemsen for _, mt := range methodTestProtos { 37*1c12ee1eSDan Willemsen t.Run(string(mt.Descriptor().FullName()), func(t *testing.T) { 38*1c12ee1eSDan Willemsen testMethods(t, mt) 39*1c12ee1eSDan Willemsen }) 40*1c12ee1eSDan Willemsen } 41*1c12ee1eSDan Willemsen} 42*1c12ee1eSDan Willemsen 43*1c12ee1eSDan Willemsenfunc testMethods(t *testing.T, mt protoreflect.MessageType) { 44*1c12ee1eSDan Willemsen m1 := mt.New() 45*1c12ee1eSDan Willemsen populated := testPopulateMessage(t, m1, 2) 46*1c12ee1eSDan Willemsen b, err := proto.Marshal(m1.Interface()) 47*1c12ee1eSDan Willemsen if err != nil { 48*1c12ee1eSDan Willemsen t.Errorf("proto.Marshal error: %v", err) 49*1c12ee1eSDan Willemsen } 50*1c12ee1eSDan Willemsen if populated && len(b) == 0 { 51*1c12ee1eSDan Willemsen t.Errorf("len(proto.Marshal) = 0, want >0") 52*1c12ee1eSDan Willemsen } 53*1c12ee1eSDan Willemsen m2 := mt.New() 54*1c12ee1eSDan Willemsen if err := proto.Unmarshal(b, m2.Interface()); err != nil { 55*1c12ee1eSDan Willemsen t.Errorf("proto.Unmarshal error: %v", err) 56*1c12ee1eSDan Willemsen } 57*1c12ee1eSDan Willemsen if diff := cmp.Diff(m1.Interface(), m2.Interface(), protocmp.Transform()); diff != "" { 58*1c12ee1eSDan Willemsen t.Errorf("message mismatch:\n%v", diff) 59*1c12ee1eSDan Willemsen } 60*1c12ee1eSDan Willemsen proto.Reset(m2.Interface()) 61*1c12ee1eSDan Willemsen testEmptyMessage(t, m2, true) 62*1c12ee1eSDan Willemsen proto.Merge(m2.Interface(), m1.Interface()) 63*1c12ee1eSDan Willemsen if diff := cmp.Diff(m1.Interface(), m2.Interface(), protocmp.Transform()); diff != "" { 64*1c12ee1eSDan Willemsen t.Errorf("message mismatch:\n%v", diff) 65*1c12ee1eSDan Willemsen } 66*1c12ee1eSDan Willemsen proto.Merge(mt.New().Interface(), mt.Zero().Interface()) 67*1c12ee1eSDan Willemsen} 68*1c12ee1eSDan Willemsen 69*1c12ee1eSDan Willemsenfunc testEmptyMessage(t *testing.T, m protoreflect.Message, wantValid bool) { 70*1c12ee1eSDan Willemsen numFields := func(m protoreflect.Message) (n int) { 71*1c12ee1eSDan Willemsen m.Range(func(protoreflect.FieldDescriptor, protoreflect.Value) bool { 72*1c12ee1eSDan Willemsen n++ 73*1c12ee1eSDan Willemsen return true 74*1c12ee1eSDan Willemsen }) 75*1c12ee1eSDan Willemsen return n 76*1c12ee1eSDan Willemsen } 77*1c12ee1eSDan Willemsen 78*1c12ee1eSDan Willemsen md := m.Descriptor() 79*1c12ee1eSDan Willemsen if gotValid := m.IsValid(); gotValid != wantValid { 80*1c12ee1eSDan Willemsen t.Errorf("%v.IsValid = %v, want %v", md.FullName(), gotValid, wantValid) 81*1c12ee1eSDan Willemsen } 82*1c12ee1eSDan Willemsen m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { 83*1c12ee1eSDan Willemsen t.Errorf("%v.Range iterated over field %v, want no iteration", md.FullName(), fd.Name()) 84*1c12ee1eSDan Willemsen return true 85*1c12ee1eSDan Willemsen }) 86*1c12ee1eSDan Willemsen fds := md.Fields() 87*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); i++ { 88*1c12ee1eSDan Willemsen fd := fds.Get(i) 89*1c12ee1eSDan Willemsen if m.Has(fd) { 90*1c12ee1eSDan Willemsen t.Errorf("%v.Has(%v) = true, want false", md.FullName(), fd.Name()) 91*1c12ee1eSDan Willemsen } 92*1c12ee1eSDan Willemsen v := m.Get(fd) 93*1c12ee1eSDan Willemsen switch { 94*1c12ee1eSDan Willemsen case fd.IsList(): 95*1c12ee1eSDan Willemsen if n := v.List().Len(); n > 0 { 96*1c12ee1eSDan Willemsen t.Errorf("%v.Get(%v).List().Len() = %v, want 0", md.FullName(), fd.Name(), n) 97*1c12ee1eSDan Willemsen } 98*1c12ee1eSDan Willemsen ls := m.NewField(fd).List() 99*1c12ee1eSDan Willemsen if fd.Message() != nil { 100*1c12ee1eSDan Willemsen if n := numFields(ls.NewElement().Message()); n > 0 { 101*1c12ee1eSDan Willemsen t.Errorf("%v.NewField(%v).List().NewElement().Message().Len() = %v, want 0", md.FullName(), fd.Name(), n) 102*1c12ee1eSDan Willemsen } 103*1c12ee1eSDan Willemsen } 104*1c12ee1eSDan Willemsen case fd.IsMap(): 105*1c12ee1eSDan Willemsen if n := v.Map().Len(); n > 0 { 106*1c12ee1eSDan Willemsen t.Errorf("%v.Get(%v).Map().Len() = %v, want 0", md.FullName(), fd.Name(), n) 107*1c12ee1eSDan Willemsen } 108*1c12ee1eSDan Willemsen ms := m.NewField(fd).Map() 109*1c12ee1eSDan Willemsen if fd.MapValue().Message() != nil { 110*1c12ee1eSDan Willemsen if n := numFields(ms.NewValue().Message()); n > 0 { 111*1c12ee1eSDan Willemsen t.Errorf("%v.NewField(%v).Map().NewValue().Message().Len() = %v, want 0", md.FullName(), fd.Name(), n) 112*1c12ee1eSDan Willemsen } 113*1c12ee1eSDan Willemsen } 114*1c12ee1eSDan Willemsen case fd.Message() != nil: 115*1c12ee1eSDan Willemsen if n := numFields(v.Message()); n > 0 { 116*1c12ee1eSDan Willemsen t.Errorf("%v.Get(%v).Message().Len() = %v, want 0", md.FullName(), fd.Name(), n) 117*1c12ee1eSDan Willemsen } 118*1c12ee1eSDan Willemsen if n := numFields(m.NewField(fd).Message()); n > 0 { 119*1c12ee1eSDan Willemsen t.Errorf("%v.NewField(%v).Message().Len() = %v, want 0", md.FullName(), fd.Name(), n) 120*1c12ee1eSDan Willemsen } 121*1c12ee1eSDan Willemsen default: 122*1c12ee1eSDan Willemsen if !reflect.DeepEqual(v.Interface(), fd.Default().Interface()) { 123*1c12ee1eSDan Willemsen t.Errorf("%v.Get(%v) = %v, want %v", md.FullName(), fd.Name(), v, fd.Default()) 124*1c12ee1eSDan Willemsen } 125*1c12ee1eSDan Willemsen m.NewField(fd) // should not panic 126*1c12ee1eSDan Willemsen } 127*1c12ee1eSDan Willemsen } 128*1c12ee1eSDan Willemsen ods := md.Oneofs() 129*1c12ee1eSDan Willemsen for i := 0; i < ods.Len(); i++ { 130*1c12ee1eSDan Willemsen od := ods.Get(i) 131*1c12ee1eSDan Willemsen if fd := m.WhichOneof(od); fd != nil { 132*1c12ee1eSDan Willemsen t.Errorf("%v.WhichOneof(%v) = %v, want nil", md.FullName(), od.Name(), fd.Name()) 133*1c12ee1eSDan Willemsen } 134*1c12ee1eSDan Willemsen } 135*1c12ee1eSDan Willemsen if b := m.GetUnknown(); b != nil { 136*1c12ee1eSDan Willemsen t.Errorf("%v.GetUnknown() = %v, want nil", md.FullName(), b) 137*1c12ee1eSDan Willemsen } 138*1c12ee1eSDan Willemsen} 139*1c12ee1eSDan Willemsen 140*1c12ee1eSDan Willemsenfunc testPopulateMessage(t *testing.T, m protoreflect.Message, depth int) bool { 141*1c12ee1eSDan Willemsen if depth == 0 { 142*1c12ee1eSDan Willemsen return false 143*1c12ee1eSDan Willemsen } 144*1c12ee1eSDan Willemsen md := m.Descriptor() 145*1c12ee1eSDan Willemsen fds := md.Fields() 146*1c12ee1eSDan Willemsen var populatedMessage bool 147*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); i++ { 148*1c12ee1eSDan Willemsen populatedField := true 149*1c12ee1eSDan Willemsen fd := fds.Get(i) 150*1c12ee1eSDan Willemsen m.Clear(fd) // should not panic 151*1c12ee1eSDan Willemsen switch { 152*1c12ee1eSDan Willemsen case fd.IsList(): 153*1c12ee1eSDan Willemsen ls := m.Mutable(fd).List() 154*1c12ee1eSDan Willemsen if fd.Message() == nil { 155*1c12ee1eSDan Willemsen ls.Append(scalarValue(fd.Kind())) 156*1c12ee1eSDan Willemsen } else { 157*1c12ee1eSDan Willemsen populatedField = testPopulateMessage(t, ls.AppendMutable().Message(), depth-1) 158*1c12ee1eSDan Willemsen } 159*1c12ee1eSDan Willemsen case fd.IsMap(): 160*1c12ee1eSDan Willemsen ms := m.Mutable(fd).Map() 161*1c12ee1eSDan Willemsen if fd.MapValue().Message() == nil { 162*1c12ee1eSDan Willemsen ms.Set( 163*1c12ee1eSDan Willemsen scalarValue(fd.MapKey().Kind()).MapKey(), 164*1c12ee1eSDan Willemsen scalarValue(fd.MapValue().Kind()), 165*1c12ee1eSDan Willemsen ) 166*1c12ee1eSDan Willemsen } else { 167*1c12ee1eSDan Willemsen // NOTE: Map.Mutable does not work with non-nullable fields. 168*1c12ee1eSDan Willemsen m2 := ms.NewValue().Message() 169*1c12ee1eSDan Willemsen populatedField = testPopulateMessage(t, m2, depth-1) 170*1c12ee1eSDan Willemsen ms.Set( 171*1c12ee1eSDan Willemsen scalarValue(fd.MapKey().Kind()).MapKey(), 172*1c12ee1eSDan Willemsen protoreflect.ValueOfMessage(m2), 173*1c12ee1eSDan Willemsen ) 174*1c12ee1eSDan Willemsen } 175*1c12ee1eSDan Willemsen case fd.Message() != nil: 176*1c12ee1eSDan Willemsen populatedField = testPopulateMessage(t, m.Mutable(fd).Message(), depth-1) 177*1c12ee1eSDan Willemsen default: 178*1c12ee1eSDan Willemsen m.Set(fd, scalarValue(fd.Kind())) 179*1c12ee1eSDan Willemsen } 180*1c12ee1eSDan Willemsen if populatedField && !m.Has(fd) { 181*1c12ee1eSDan Willemsen t.Errorf("%v.Has(%v) = false, want true", md.FullName(), fd.Name()) 182*1c12ee1eSDan Willemsen } 183*1c12ee1eSDan Willemsen populatedMessage = populatedMessage || populatedField 184*1c12ee1eSDan Willemsen } 185*1c12ee1eSDan Willemsen m.SetUnknown(m.GetUnknown()) // should not panic 186*1c12ee1eSDan Willemsen return populatedMessage 187*1c12ee1eSDan Willemsen} 188*1c12ee1eSDan Willemsen 189*1c12ee1eSDan Willemsenfunc scalarValue(k protoreflect.Kind) protoreflect.Value { 190*1c12ee1eSDan Willemsen switch k { 191*1c12ee1eSDan Willemsen case protoreflect.BoolKind: 192*1c12ee1eSDan Willemsen return protoreflect.ValueOfBool(true) 193*1c12ee1eSDan Willemsen case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: 194*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt32(-32) 195*1c12ee1eSDan Willemsen case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: 196*1c12ee1eSDan Willemsen return protoreflect.ValueOfInt64(-64) 197*1c12ee1eSDan Willemsen case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: 198*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint32(32) 199*1c12ee1eSDan Willemsen case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: 200*1c12ee1eSDan Willemsen return protoreflect.ValueOfUint64(64) 201*1c12ee1eSDan Willemsen case protoreflect.FloatKind: 202*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat32(32.32) 203*1c12ee1eSDan Willemsen case protoreflect.DoubleKind: 204*1c12ee1eSDan Willemsen return protoreflect.ValueOfFloat64(64.64) 205*1c12ee1eSDan Willemsen case protoreflect.StringKind: 206*1c12ee1eSDan Willemsen return protoreflect.ValueOfString(string("string")) 207*1c12ee1eSDan Willemsen case protoreflect.BytesKind: 208*1c12ee1eSDan Willemsen return protoreflect.ValueOfBytes([]byte("bytes")) 209*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 210*1c12ee1eSDan Willemsen return protoreflect.ValueOfEnum(1) 211*1c12ee1eSDan Willemsen default: 212*1c12ee1eSDan Willemsen panic("unknown kind: " + k.String()) 213*1c12ee1eSDan Willemsen } 214*1c12ee1eSDan Willemsen} 215