1*1c12ee1eSDan Willemsen// Copyright 2018 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 filedesc_test 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "bytes" 9*1c12ee1eSDan Willemsen "compress/gzip" 10*1c12ee1eSDan Willemsen "io/ioutil" 11*1c12ee1eSDan Willemsen "testing" 12*1c12ee1eSDan Willemsen 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protodesc" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 16*1c12ee1eSDan Willemsen 17*1c12ee1eSDan Willemsen testpb "google.golang.org/protobuf/internal/testprotos/test" 18*1c12ee1eSDan Willemsen _ "google.golang.org/protobuf/internal/testprotos/test/weak1" 19*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/descriptorpb" 20*1c12ee1eSDan Willemsen) 21*1c12ee1eSDan Willemsen 22*1c12ee1eSDan Willemsenvar testFile = new(testpb.TestAllTypes).ProtoReflect().Descriptor().ParentFile() 23*1c12ee1eSDan Willemsen 24*1c12ee1eSDan Willemsenfunc TestInit(t *testing.T) { 25*1c12ee1eSDan Willemsen // Compare the FileDescriptorProto for the same test file from two different sources: 26*1c12ee1eSDan Willemsen // 27*1c12ee1eSDan Willemsen // 1. The result of passing the filedesc-produced FileDescriptor through protodesc. 28*1c12ee1eSDan Willemsen // 2. The protoc-generated wire-encoded message. 29*1c12ee1eSDan Willemsen // 30*1c12ee1eSDan Willemsen // This serves as a test of both filedesc and protodesc. 31*1c12ee1eSDan Willemsen got := protodesc.ToFileDescriptorProto(testFile) 32*1c12ee1eSDan Willemsen 33*1c12ee1eSDan Willemsen want := &descriptorpb.FileDescriptorProto{} 34*1c12ee1eSDan Willemsen zb, _ := (&testpb.TestAllTypes{}).Descriptor() 35*1c12ee1eSDan Willemsen r, _ := gzip.NewReader(bytes.NewBuffer(zb)) 36*1c12ee1eSDan Willemsen b, _ := ioutil.ReadAll(r) 37*1c12ee1eSDan Willemsen if err := proto.Unmarshal(b, want); err != nil { 38*1c12ee1eSDan Willemsen t.Fatal(err) 39*1c12ee1eSDan Willemsen } 40*1c12ee1eSDan Willemsen 41*1c12ee1eSDan Willemsen if !proto.Equal(got, want) { 42*1c12ee1eSDan Willemsen t.Errorf("protodesc.ToFileDescriptorProto(testpb.Test_protoFile) is not equal to the protoc-generated FileDescriptorProto for internal/testprotos/test/test.proto") 43*1c12ee1eSDan Willemsen } 44*1c12ee1eSDan Willemsen 45*1c12ee1eSDan Willemsen // Verify that the test proto file provides exhaustive coverage of all descriptor fields. 46*1c12ee1eSDan Willemsen seen := make(map[protoreflect.FullName]bool) 47*1c12ee1eSDan Willemsen visitFields(want.ProtoReflect(), func(field protoreflect.FieldDescriptor) { 48*1c12ee1eSDan Willemsen seen[field.FullName()] = true 49*1c12ee1eSDan Willemsen }) 50*1c12ee1eSDan Willemsen descFile := new(descriptorpb.DescriptorProto).ProtoReflect().Descriptor().ParentFile() 51*1c12ee1eSDan Willemsen descPkg := descFile.Package() 52*1c12ee1eSDan Willemsen ignore := map[protoreflect.FullName]bool{ 53*1c12ee1eSDan Willemsen // The protoreflect descriptors don't include source info. 54*1c12ee1eSDan Willemsen descPkg.Append("FileDescriptorProto.source_code_info"): true, 55*1c12ee1eSDan Willemsen descPkg.Append("FileDescriptorProto.syntax"): true, 56*1c12ee1eSDan Willemsen // Nothing is using edition yet. 57*1c12ee1eSDan Willemsen descPkg.Append("FileDescriptorProto.edition"): true, 58*1c12ee1eSDan Willemsen 59*1c12ee1eSDan Willemsen // Impossible to test proto3 optional in a proto2 file. 60*1c12ee1eSDan Willemsen descPkg.Append("FieldDescriptorProto.proto3_optional"): true, 61*1c12ee1eSDan Willemsen 62*1c12ee1eSDan Willemsen // TODO: Test oneof and extension options. Testing these requires extending the 63*1c12ee1eSDan Willemsen // options messages (because they contain no user-settable fields), but importing 64*1c12ee1eSDan Willemsen // descriptor.proto from test.proto currently causes an import cycle. Add test 65*1c12ee1eSDan Willemsen // cases when that import cycle has been fixed. 66*1c12ee1eSDan Willemsen descPkg.Append("OneofDescriptorProto.options"): true, 67*1c12ee1eSDan Willemsen } 68*1c12ee1eSDan Willemsen for _, messageName := range []protoreflect.Name{ 69*1c12ee1eSDan Willemsen "FileDescriptorProto", 70*1c12ee1eSDan Willemsen "DescriptorProto", 71*1c12ee1eSDan Willemsen "FieldDescriptorProto", 72*1c12ee1eSDan Willemsen "OneofDescriptorProto", 73*1c12ee1eSDan Willemsen "EnumDescriptorProto", 74*1c12ee1eSDan Willemsen "EnumValueDescriptorProto", 75*1c12ee1eSDan Willemsen } { 76*1c12ee1eSDan Willemsen message := descFile.Messages().ByName(messageName) 77*1c12ee1eSDan Willemsen for i, fields := 0, message.Fields(); i < fields.Len(); i++ { 78*1c12ee1eSDan Willemsen if name := fields.Get(i).FullName(); !seen[name] && !ignore[name] { 79*1c12ee1eSDan Willemsen t.Errorf("No test for descriptor field: %v", name) 80*1c12ee1eSDan Willemsen } 81*1c12ee1eSDan Willemsen } 82*1c12ee1eSDan Willemsen } 83*1c12ee1eSDan Willemsen 84*1c12ee1eSDan Willemsen // Verify that message descriptors for map entries have no Go type info. 85*1c12ee1eSDan Willemsen mapEntryName := protoreflect.FullName("goproto.proto.test.TestAllTypes.MapInt32Int32Entry") 86*1c12ee1eSDan Willemsen d := testFile.Messages().ByName("TestAllTypes").Fields().ByName("map_int32_int32").Message() 87*1c12ee1eSDan Willemsen if gotName, wantName := d.FullName(), mapEntryName; gotName != wantName { 88*1c12ee1eSDan Willemsen t.Fatalf("looked up wrong descriptor: got %v, want %v", gotName, wantName) 89*1c12ee1eSDan Willemsen } 90*1c12ee1eSDan Willemsen if _, ok := d.(protoreflect.MessageType); ok { 91*1c12ee1eSDan Willemsen t.Errorf("message descriptor for %v must not implement protoreflect.MessageType", mapEntryName) 92*1c12ee1eSDan Willemsen } 93*1c12ee1eSDan Willemsen} 94*1c12ee1eSDan Willemsen 95*1c12ee1eSDan Willemsen// visitFields calls f for every field set in m and its children. 96*1c12ee1eSDan Willemsenfunc visitFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor)) { 97*1c12ee1eSDan Willemsen m.Range(func(fd protoreflect.FieldDescriptor, value protoreflect.Value) bool { 98*1c12ee1eSDan Willemsen f(fd) 99*1c12ee1eSDan Willemsen switch fd.Kind() { 100*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind: 101*1c12ee1eSDan Willemsen if fd.IsList() { 102*1c12ee1eSDan Willemsen for i, list := 0, value.List(); i < list.Len(); i++ { 103*1c12ee1eSDan Willemsen visitFields(list.Get(i).Message(), f) 104*1c12ee1eSDan Willemsen } 105*1c12ee1eSDan Willemsen } else { 106*1c12ee1eSDan Willemsen visitFields(value.Message(), f) 107*1c12ee1eSDan Willemsen } 108*1c12ee1eSDan Willemsen } 109*1c12ee1eSDan Willemsen return true 110*1c12ee1eSDan Willemsen }) 111*1c12ee1eSDan Willemsen} 112*1c12ee1eSDan Willemsen 113*1c12ee1eSDan Willemsenfunc TestWeakInit(t *testing.T) { 114*1c12ee1eSDan Willemsen // We do not expect to get a placeholder since weak1 is imported. 115*1c12ee1eSDan Willemsen fd1 := testFile.Messages().ByName("TestWeak").Fields().ByName("weak_message1") 116*1c12ee1eSDan Willemsen if got, want := fd1.IsWeak(), true; got != want { 117*1c12ee1eSDan Willemsen t.Errorf("field %v: IsWeak() = %v, want %v", fd1.FullName(), got, want) 118*1c12ee1eSDan Willemsen } 119*1c12ee1eSDan Willemsen if got, want := fd1.Message().IsPlaceholder(), false; got != want { 120*1c12ee1eSDan Willemsen t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd1.FullName(), got, want) 121*1c12ee1eSDan Willemsen } 122*1c12ee1eSDan Willemsen if got, want := fd1.Message().Fields().Len(), 1; got != want { 123*1c12ee1eSDan Willemsen t.Errorf("field %v: Message().Fields().Len() == %d, want %d", fd1.FullName(), got, want) 124*1c12ee1eSDan Willemsen } 125*1c12ee1eSDan Willemsen 126*1c12ee1eSDan Willemsen // We do expect to get a placeholder since weak2 is not imported. 127*1c12ee1eSDan Willemsen fd2 := testFile.Messages().ByName("TestWeak").Fields().ByName("weak_message2") 128*1c12ee1eSDan Willemsen if got, want := fd2.IsWeak(), true; got != want { 129*1c12ee1eSDan Willemsen t.Errorf("field %v: IsWeak() = %v, want %v", fd2.FullName(), got, want) 130*1c12ee1eSDan Willemsen } 131*1c12ee1eSDan Willemsen if got, want := fd2.Message().IsPlaceholder(), true; got != want { 132*1c12ee1eSDan Willemsen t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd2.FullName(), got, want) 133*1c12ee1eSDan Willemsen } 134*1c12ee1eSDan Willemsen if got, want := fd2.Message().Fields().Len(), 0; got != want { 135*1c12ee1eSDan Willemsen t.Errorf("field %v: Message().Fields().Len() == %d, want %d", fd2.FullName(), got, want) 136*1c12ee1eSDan Willemsen } 137*1c12ee1eSDan Willemsen} 138