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 Willemsenpackage protodesc 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "fmt" 9*1c12ee1eSDan Willemsen "strings" 10*1c12ee1eSDan Willemsen "testing" 11*1c12ee1eSDan Willemsen 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/prototext" 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/flags" 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 15*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 16*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoregistry" 17*1c12ee1eSDan Willemsen 18*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/descriptorpb" 19*1c12ee1eSDan Willemsen) 20*1c12ee1eSDan Willemsen 21*1c12ee1eSDan Willemsenfunc mustParseFile(s string) *descriptorpb.FileDescriptorProto { 22*1c12ee1eSDan Willemsen pb := new(descriptorpb.FileDescriptorProto) 23*1c12ee1eSDan Willemsen if err := prototext.Unmarshal([]byte(s), pb); err != nil { 24*1c12ee1eSDan Willemsen panic(err) 25*1c12ee1eSDan Willemsen } 26*1c12ee1eSDan Willemsen return pb 27*1c12ee1eSDan Willemsen} 28*1c12ee1eSDan Willemsen 29*1c12ee1eSDan Willemsenfunc cloneFile(in *descriptorpb.FileDescriptorProto) *descriptorpb.FileDescriptorProto { 30*1c12ee1eSDan Willemsen return proto.Clone(in).(*descriptorpb.FileDescriptorProto) 31*1c12ee1eSDan Willemsen} 32*1c12ee1eSDan Willemsen 33*1c12ee1eSDan Willemsenvar ( 34*1c12ee1eSDan Willemsen proto2Enum = mustParseFile(` 35*1c12ee1eSDan Willemsen syntax: "proto2" 36*1c12ee1eSDan Willemsen name: "proto2_enum.proto" 37*1c12ee1eSDan Willemsen package: "test.proto2" 38*1c12ee1eSDan Willemsen enum_type: [{name:"Enum" value:[{name:"ONE" number:1}]}] 39*1c12ee1eSDan Willemsen `) 40*1c12ee1eSDan Willemsen proto3Message = mustParseFile(` 41*1c12ee1eSDan Willemsen syntax: "proto3" 42*1c12ee1eSDan Willemsen name: "proto3_message.proto" 43*1c12ee1eSDan Willemsen package: "test.proto3" 44*1c12ee1eSDan Willemsen message_type: [{ 45*1c12ee1eSDan Willemsen name: "Message" 46*1c12ee1eSDan Willemsen field: [ 47*1c12ee1eSDan Willemsen {name:"foo" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, 48*1c12ee1eSDan Willemsen {name:"bar" number:2 label:LABEL_OPTIONAL type:TYPE_STRING} 49*1c12ee1eSDan Willemsen ] 50*1c12ee1eSDan Willemsen }] 51*1c12ee1eSDan Willemsen `) 52*1c12ee1eSDan Willemsen extendableMessage = mustParseFile(` 53*1c12ee1eSDan Willemsen syntax: "proto2" 54*1c12ee1eSDan Willemsen name: "extendable_message.proto" 55*1c12ee1eSDan Willemsen package: "test.proto2" 56*1c12ee1eSDan Willemsen message_type: [{name:"Message" extension_range:[{start:1 end:1000}]}] 57*1c12ee1eSDan Willemsen `) 58*1c12ee1eSDan Willemsen importPublicFile1 = mustParseFile(` 59*1c12ee1eSDan Willemsen syntax: "proto3" 60*1c12ee1eSDan Willemsen name: "import_public1.proto" 61*1c12ee1eSDan Willemsen dependency: ["proto2_enum.proto", "proto3_message.proto", "extendable_message.proto"] 62*1c12ee1eSDan Willemsen message_type: [{name:"Public1"}] 63*1c12ee1eSDan Willemsen `) 64*1c12ee1eSDan Willemsen importPublicFile2 = mustParseFile(` 65*1c12ee1eSDan Willemsen syntax: "proto3" 66*1c12ee1eSDan Willemsen name: "import_public2.proto" 67*1c12ee1eSDan Willemsen dependency: ["import_public1.proto"] 68*1c12ee1eSDan Willemsen public_dependency: [0] 69*1c12ee1eSDan Willemsen message_type: [{name:"Public2"}] 70*1c12ee1eSDan Willemsen `) 71*1c12ee1eSDan Willemsen importPublicFile3 = mustParseFile(` 72*1c12ee1eSDan Willemsen syntax: "proto3" 73*1c12ee1eSDan Willemsen name: "import_public3.proto" 74*1c12ee1eSDan Willemsen dependency: ["import_public2.proto", "extendable_message.proto"] 75*1c12ee1eSDan Willemsen public_dependency: [0] 76*1c12ee1eSDan Willemsen message_type: [{name:"Public3"}] 77*1c12ee1eSDan Willemsen `) 78*1c12ee1eSDan Willemsen importPublicFile4 = mustParseFile(` 79*1c12ee1eSDan Willemsen syntax: "proto3" 80*1c12ee1eSDan Willemsen name: "import_public4.proto" 81*1c12ee1eSDan Willemsen dependency: ["import_public2.proto", "import_public3.proto", "proto2_enum.proto"] 82*1c12ee1eSDan Willemsen public_dependency: [0, 1] 83*1c12ee1eSDan Willemsen message_type: [{name:"Public4"}] 84*1c12ee1eSDan Willemsen `) 85*1c12ee1eSDan Willemsen) 86*1c12ee1eSDan Willemsen 87*1c12ee1eSDan Willemsenfunc TestNewFile(t *testing.T) { 88*1c12ee1eSDan Willemsen tests := []struct { 89*1c12ee1eSDan Willemsen label string 90*1c12ee1eSDan Willemsen inDeps []*descriptorpb.FileDescriptorProto 91*1c12ee1eSDan Willemsen inDesc *descriptorpb.FileDescriptorProto 92*1c12ee1eSDan Willemsen inOpts FileOptions 93*1c12ee1eSDan Willemsen wantDesc *descriptorpb.FileDescriptorProto 94*1c12ee1eSDan Willemsen wantErr string 95*1c12ee1eSDan Willemsen }{{ 96*1c12ee1eSDan Willemsen label: "empty path", 97*1c12ee1eSDan Willemsen inDesc: mustParseFile(``), 98*1c12ee1eSDan Willemsen wantErr: `path must be populated`, 99*1c12ee1eSDan Willemsen }, { 100*1c12ee1eSDan Willemsen label: "empty package and syntax", 101*1c12ee1eSDan Willemsen inDesc: mustParseFile(`name:"weird"`), 102*1c12ee1eSDan Willemsen }, { 103*1c12ee1eSDan Willemsen label: "invalid syntax", 104*1c12ee1eSDan Willemsen inDesc: mustParseFile(`name:"weird" syntax:"proto9"`), 105*1c12ee1eSDan Willemsen wantErr: `invalid syntax: "proto9"`, 106*1c12ee1eSDan Willemsen }, { 107*1c12ee1eSDan Willemsen label: "bad package", 108*1c12ee1eSDan Willemsen inDesc: mustParseFile(`name:"weird" package:"$"`), 109*1c12ee1eSDan Willemsen wantErr: `invalid package: "$"`, 110*1c12ee1eSDan Willemsen }, { 111*1c12ee1eSDan Willemsen label: "unresolvable import", 112*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 113*1c12ee1eSDan Willemsen name: "test.proto" 114*1c12ee1eSDan Willemsen dependency: "dep.proto" 115*1c12ee1eSDan Willemsen `), 116*1c12ee1eSDan Willemsen wantErr: `could not resolve import "dep.proto": not found`, 117*1c12ee1eSDan Willemsen }, { 118*1c12ee1eSDan Willemsen label: "unresolvable import but allowed", 119*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 120*1c12ee1eSDan Willemsen name: "test.proto" 121*1c12ee1eSDan Willemsen dependency: "dep.proto" 122*1c12ee1eSDan Willemsen `), 123*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 124*1c12ee1eSDan Willemsen }, { 125*1c12ee1eSDan Willemsen label: "duplicate import", 126*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 127*1c12ee1eSDan Willemsen name: "test.proto" 128*1c12ee1eSDan Willemsen dependency: ["dep.proto", "dep.proto"] 129*1c12ee1eSDan Willemsen `), 130*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 131*1c12ee1eSDan Willemsen wantErr: `already imported "dep.proto"`, 132*1c12ee1eSDan Willemsen }, { 133*1c12ee1eSDan Willemsen label: "invalid weak import", 134*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 135*1c12ee1eSDan Willemsen name: "test.proto" 136*1c12ee1eSDan Willemsen dependency: "dep.proto" 137*1c12ee1eSDan Willemsen weak_dependency: [-23] 138*1c12ee1eSDan Willemsen `), 139*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 140*1c12ee1eSDan Willemsen wantErr: `invalid or duplicate weak import index: -23`, 141*1c12ee1eSDan Willemsen }, { 142*1c12ee1eSDan Willemsen label: "normal weak and public import", 143*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 144*1c12ee1eSDan Willemsen name: "test.proto" 145*1c12ee1eSDan Willemsen dependency: "dep.proto" 146*1c12ee1eSDan Willemsen weak_dependency: [0] 147*1c12ee1eSDan Willemsen public_dependency: [0] 148*1c12ee1eSDan Willemsen `), 149*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 150*1c12ee1eSDan Willemsen }, { 151*1c12ee1eSDan Willemsen label: "import public indirect dependency duplicate", 152*1c12ee1eSDan Willemsen inDeps: []*descriptorpb.FileDescriptorProto{ 153*1c12ee1eSDan Willemsen mustParseFile(`name:"leaf.proto"`), 154*1c12ee1eSDan Willemsen mustParseFile(`name:"public.proto" dependency:"leaf.proto" public_dependency:0`), 155*1c12ee1eSDan Willemsen }, 156*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 157*1c12ee1eSDan Willemsen name: "test.proto" 158*1c12ee1eSDan Willemsen dependency: ["public.proto", "leaf.proto"] 159*1c12ee1eSDan Willemsen `), 160*1c12ee1eSDan Willemsen }, { 161*1c12ee1eSDan Willemsen label: "import public graph", 162*1c12ee1eSDan Willemsen inDeps: []*descriptorpb.FileDescriptorProto{ 163*1c12ee1eSDan Willemsen cloneFile(proto2Enum), 164*1c12ee1eSDan Willemsen cloneFile(proto3Message), 165*1c12ee1eSDan Willemsen cloneFile(extendableMessage), 166*1c12ee1eSDan Willemsen cloneFile(importPublicFile1), 167*1c12ee1eSDan Willemsen cloneFile(importPublicFile2), 168*1c12ee1eSDan Willemsen cloneFile(importPublicFile3), 169*1c12ee1eSDan Willemsen cloneFile(importPublicFile4), 170*1c12ee1eSDan Willemsen }, 171*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 172*1c12ee1eSDan Willemsen name: "test.proto" 173*1c12ee1eSDan Willemsen package: "test.graph" 174*1c12ee1eSDan Willemsen dependency: ["import_public4.proto"], 175*1c12ee1eSDan Willemsen `), 176*1c12ee1eSDan Willemsen // TODO: Test import public 177*1c12ee1eSDan Willemsen }, { 178*1c12ee1eSDan Willemsen label: "preserve source code locations", 179*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 180*1c12ee1eSDan Willemsen name: "test.proto" 181*1c12ee1eSDan Willemsen package: "fizz.buzz" 182*1c12ee1eSDan Willemsen source_code_info: {location: [{ 183*1c12ee1eSDan Willemsen span: [39,0,882,1] 184*1c12ee1eSDan Willemsen }, { 185*1c12ee1eSDan Willemsen path: [12] 186*1c12ee1eSDan Willemsen span: [39,0,18] 187*1c12ee1eSDan Willemsen leading_detached_comments: [" foo\n"," bar\n"] 188*1c12ee1eSDan Willemsen }, { 189*1c12ee1eSDan Willemsen path: [8,9] 190*1c12ee1eSDan Willemsen span: [51,0,28] 191*1c12ee1eSDan Willemsen leading_comments: " Comment\n" 192*1c12ee1eSDan Willemsen }]} 193*1c12ee1eSDan Willemsen `), 194*1c12ee1eSDan Willemsen }, { 195*1c12ee1eSDan Willemsen label: "invalid source code span", 196*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 197*1c12ee1eSDan Willemsen name: "test.proto" 198*1c12ee1eSDan Willemsen package: "fizz.buzz" 199*1c12ee1eSDan Willemsen source_code_info: {location: [{ 200*1c12ee1eSDan Willemsen span: [39] 201*1c12ee1eSDan Willemsen }]} 202*1c12ee1eSDan Willemsen `), 203*1c12ee1eSDan Willemsen wantErr: `invalid span: [39]`, 204*1c12ee1eSDan Willemsen }, { 205*1c12ee1eSDan Willemsen label: "resolve relative reference", 206*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 207*1c12ee1eSDan Willemsen name: "test.proto" 208*1c12ee1eSDan Willemsen package: "fizz.buzz" 209*1c12ee1eSDan Willemsen message_type: [{ 210*1c12ee1eSDan Willemsen name: "A" 211*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:"B.C"}] 212*1c12ee1eSDan Willemsen nested_type: [{name: "B"}] 213*1c12ee1eSDan Willemsen }, { 214*1c12ee1eSDan Willemsen name: "B" 215*1c12ee1eSDan Willemsen nested_type: [{name: "C"}] 216*1c12ee1eSDan Willemsen }] 217*1c12ee1eSDan Willemsen `), 218*1c12ee1eSDan Willemsen wantDesc: mustParseFile(` 219*1c12ee1eSDan Willemsen name: "test.proto" 220*1c12ee1eSDan Willemsen package: "fizz.buzz" 221*1c12ee1eSDan Willemsen message_type: [{ 222*1c12ee1eSDan Willemsen name: "A" 223*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".fizz.buzz.B.C"}] 224*1c12ee1eSDan Willemsen nested_type: [{name: "B"}] 225*1c12ee1eSDan Willemsen }, { 226*1c12ee1eSDan Willemsen name: "B" 227*1c12ee1eSDan Willemsen nested_type: [{name: "C"}] 228*1c12ee1eSDan Willemsen }] 229*1c12ee1eSDan Willemsen `), 230*1c12ee1eSDan Willemsen }, { 231*1c12ee1eSDan Willemsen label: "resolve the wrong type", 232*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 233*1c12ee1eSDan Willemsen name: "test.proto" 234*1c12ee1eSDan Willemsen message_type: [{ 235*1c12ee1eSDan Willemsen name: "M" 236*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:"E"}] 237*1c12ee1eSDan Willemsen enum_type: [{name: "E" value: [{name:"V0" number:0}, {name:"V1" number:1}]}] 238*1c12ee1eSDan Willemsen }] 239*1c12ee1eSDan Willemsen `), 240*1c12ee1eSDan Willemsen wantErr: `message field "M.F" cannot resolve type: resolved "M.E", but it is not an message`, 241*1c12ee1eSDan Willemsen }, { 242*1c12ee1eSDan Willemsen label: "auto-resolve unknown kind", 243*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 244*1c12ee1eSDan Willemsen name: "test.proto" 245*1c12ee1eSDan Willemsen message_type: [{ 246*1c12ee1eSDan Willemsen name: "M" 247*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type_name:"E"}] 248*1c12ee1eSDan Willemsen enum_type: [{name: "E" value: [{name:"V0" number:0}, {name:"V1" number:1}]}] 249*1c12ee1eSDan Willemsen }] 250*1c12ee1eSDan Willemsen `), 251*1c12ee1eSDan Willemsen wantDesc: mustParseFile(` 252*1c12ee1eSDan Willemsen name: "test.proto" 253*1c12ee1eSDan Willemsen message_type: [{ 254*1c12ee1eSDan Willemsen name: "M" 255*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".M.E"}] 256*1c12ee1eSDan Willemsen enum_type: [{name: "E" value: [{name:"V0" number:0}, {name:"V1" number:1}]}] 257*1c12ee1eSDan Willemsen }] 258*1c12ee1eSDan Willemsen `), 259*1c12ee1eSDan Willemsen }, { 260*1c12ee1eSDan Willemsen label: "unresolved import", 261*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 262*1c12ee1eSDan Willemsen name: "test.proto" 263*1c12ee1eSDan Willemsen package: "fizz.buzz" 264*1c12ee1eSDan Willemsen dependency: "remote.proto" 265*1c12ee1eSDan Willemsen `), 266*1c12ee1eSDan Willemsen wantErr: `could not resolve import "remote.proto": not found`, 267*1c12ee1eSDan Willemsen }, { 268*1c12ee1eSDan Willemsen label: "unresolved message field", 269*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 270*1c12ee1eSDan Willemsen name: "test.proto" 271*1c12ee1eSDan Willemsen package: "fizz.buzz" 272*1c12ee1eSDan Willemsen message_type: [{ 273*1c12ee1eSDan Willemsen name: "M" 274*1c12ee1eSDan Willemsen field: [{name:"F1" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:"some.other.enum" default_value:"UNKNOWN"}] 275*1c12ee1eSDan Willemsen }] 276*1c12ee1eSDan Willemsen `), 277*1c12ee1eSDan Willemsen wantErr: `message field "fizz.buzz.M.F1" cannot resolve type: "*.some.other.enum" not found`, 278*1c12ee1eSDan Willemsen }, { 279*1c12ee1eSDan Willemsen label: "unresolved default enum value", 280*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 281*1c12ee1eSDan Willemsen name: "test.proto" 282*1c12ee1eSDan Willemsen package: "fizz.buzz" 283*1c12ee1eSDan Willemsen message_type: [{ 284*1c12ee1eSDan Willemsen name: "M" 285*1c12ee1eSDan Willemsen field: [{name:"F1" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:"E" default_value:"UNKNOWN"}] 286*1c12ee1eSDan Willemsen enum_type: [{name:"E" value:[{name:"V0" number:0}]}] 287*1c12ee1eSDan Willemsen }] 288*1c12ee1eSDan Willemsen `), 289*1c12ee1eSDan Willemsen wantErr: `message field "fizz.buzz.M.F1" has invalid default: could not parse value for enum: "UNKNOWN"`, 290*1c12ee1eSDan Willemsen }, { 291*1c12ee1eSDan Willemsen label: "allowed unresolved default enum value", 292*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 293*1c12ee1eSDan Willemsen name: "test.proto" 294*1c12ee1eSDan Willemsen package: "fizz.buzz" 295*1c12ee1eSDan Willemsen message_type: [{ 296*1c12ee1eSDan Willemsen name: "M" 297*1c12ee1eSDan Willemsen field: [{name:"F1" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".fizz.buzz.M.E" default_value:"UNKNOWN"}] 298*1c12ee1eSDan Willemsen enum_type: [{name:"E" value:[{name:"V0" number:0}]}] 299*1c12ee1eSDan Willemsen }] 300*1c12ee1eSDan Willemsen `), 301*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 302*1c12ee1eSDan Willemsen }, { 303*1c12ee1eSDan Willemsen label: "unresolved extendee", 304*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 305*1c12ee1eSDan Willemsen name: "test.proto" 306*1c12ee1eSDan Willemsen package: "fizz.buzz" 307*1c12ee1eSDan Willemsen extension: [{name:"X" number:1 label:LABEL_OPTIONAL extendee:"some.extended.message" type:TYPE_MESSAGE type_name:"some.other.message"}] 308*1c12ee1eSDan Willemsen `), 309*1c12ee1eSDan Willemsen wantErr: `extension field "fizz.buzz.X" cannot resolve extendee: "*.some.extended.message" not found`, 310*1c12ee1eSDan Willemsen }, { 311*1c12ee1eSDan Willemsen label: "unresolved method input", 312*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 313*1c12ee1eSDan Willemsen name: "test.proto" 314*1c12ee1eSDan Willemsen package: "fizz.buzz" 315*1c12ee1eSDan Willemsen service: [{ 316*1c12ee1eSDan Willemsen name: "S" 317*1c12ee1eSDan Willemsen method: [{name:"M" input_type:"foo.bar.input" output_type:".absolute.foo.bar.output"}] 318*1c12ee1eSDan Willemsen }] 319*1c12ee1eSDan Willemsen `), 320*1c12ee1eSDan Willemsen wantErr: `service method "fizz.buzz.S.M" cannot resolve input: "*.foo.bar.input" not found`, 321*1c12ee1eSDan Willemsen }, { 322*1c12ee1eSDan Willemsen label: "allowed unresolved references", 323*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 324*1c12ee1eSDan Willemsen name: "test.proto" 325*1c12ee1eSDan Willemsen package: "fizz.buzz" 326*1c12ee1eSDan Willemsen dependency: "remote.proto" 327*1c12ee1eSDan Willemsen message_type: [{ 328*1c12ee1eSDan Willemsen name: "M" 329*1c12ee1eSDan Willemsen field: [{name:"F1" number:1 label:LABEL_OPTIONAL type_name:"some.other.enum" default_value:"UNKNOWN"}] 330*1c12ee1eSDan Willemsen }] 331*1c12ee1eSDan Willemsen extension: [{name:"X" number:1 label:LABEL_OPTIONAL extendee:"some.extended.message" type:TYPE_MESSAGE type_name:"some.other.message"}] 332*1c12ee1eSDan Willemsen service: [{ 333*1c12ee1eSDan Willemsen name: "S" 334*1c12ee1eSDan Willemsen method: [{name:"M" input_type:"foo.bar.input" output_type:".absolute.foo.bar.output"}] 335*1c12ee1eSDan Willemsen }] 336*1c12ee1eSDan Willemsen `), 337*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 338*1c12ee1eSDan Willemsen }, { 339*1c12ee1eSDan Willemsen label: "resolved but not imported", 340*1c12ee1eSDan Willemsen inDeps: []*descriptorpb.FileDescriptorProto{mustParseFile(` 341*1c12ee1eSDan Willemsen name: "dep.proto" 342*1c12ee1eSDan Willemsen package: "fizz" 343*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{name:"M"}]}] 344*1c12ee1eSDan Willemsen `)}, 345*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 346*1c12ee1eSDan Willemsen name: "test.proto" 347*1c12ee1eSDan Willemsen package: "fizz.buzz" 348*1c12ee1eSDan Willemsen message_type: [{ 349*1c12ee1eSDan Willemsen name: "M" 350*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:"M.M"}] 351*1c12ee1eSDan Willemsen }] 352*1c12ee1eSDan Willemsen `), 353*1c12ee1eSDan Willemsen wantErr: `message field "fizz.buzz.M.F" cannot resolve type: resolved "fizz.M.M", but "dep.proto" is not imported`, 354*1c12ee1eSDan Willemsen }, { 355*1c12ee1eSDan Willemsen label: "resolved from remote import", 356*1c12ee1eSDan Willemsen inDeps: []*descriptorpb.FileDescriptorProto{mustParseFile(` 357*1c12ee1eSDan Willemsen name: "dep.proto" 358*1c12ee1eSDan Willemsen package: "fizz" 359*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{name:"M"}]}] 360*1c12ee1eSDan Willemsen `)}, 361*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 362*1c12ee1eSDan Willemsen name: "test.proto" 363*1c12ee1eSDan Willemsen package: "fizz.buzz" 364*1c12ee1eSDan Willemsen dependency: "dep.proto" 365*1c12ee1eSDan Willemsen message_type: [{ 366*1c12ee1eSDan Willemsen name: "M" 367*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:"M.M"}] 368*1c12ee1eSDan Willemsen }] 369*1c12ee1eSDan Willemsen `), 370*1c12ee1eSDan Willemsen wantDesc: mustParseFile(` 371*1c12ee1eSDan Willemsen name: "test.proto" 372*1c12ee1eSDan Willemsen package: "fizz.buzz" 373*1c12ee1eSDan Willemsen dependency: "dep.proto" 374*1c12ee1eSDan Willemsen message_type: [{ 375*1c12ee1eSDan Willemsen name: "M" 376*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".fizz.M.M"}] 377*1c12ee1eSDan Willemsen }] 378*1c12ee1eSDan Willemsen `), 379*1c12ee1eSDan Willemsen }, { 380*1c12ee1eSDan Willemsen label: "namespace conflict on enum value", 381*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 382*1c12ee1eSDan Willemsen name: "test.proto" 383*1c12ee1eSDan Willemsen enum_type: [{ 384*1c12ee1eSDan Willemsen name: "foo" 385*1c12ee1eSDan Willemsen value: [{name:"foo" number:0}] 386*1c12ee1eSDan Willemsen }] 387*1c12ee1eSDan Willemsen `), 388*1c12ee1eSDan Willemsen wantErr: `descriptor "foo" already declared`, 389*1c12ee1eSDan Willemsen }, { 390*1c12ee1eSDan Willemsen label: "no namespace conflict on message field", 391*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 392*1c12ee1eSDan Willemsen name: "test.proto" 393*1c12ee1eSDan Willemsen message_type: [{ 394*1c12ee1eSDan Willemsen name: "foo" 395*1c12ee1eSDan Willemsen field: [{name:"foo" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}] 396*1c12ee1eSDan Willemsen }] 397*1c12ee1eSDan Willemsen `), 398*1c12ee1eSDan Willemsen }, { 399*1c12ee1eSDan Willemsen label: "invalid name", 400*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 401*1c12ee1eSDan Willemsen name: "test.proto" 402*1c12ee1eSDan Willemsen message_type: [{name: "$"}] 403*1c12ee1eSDan Willemsen `), 404*1c12ee1eSDan Willemsen wantErr: `descriptor "" has an invalid nested name: "$"`, 405*1c12ee1eSDan Willemsen }, { 406*1c12ee1eSDan Willemsen label: "invalid empty enum", 407*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 408*1c12ee1eSDan Willemsen name: "test.proto" 409*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{name:"E"}]}] 410*1c12ee1eSDan Willemsen `), 411*1c12ee1eSDan Willemsen wantErr: `enum "M.E" must contain at least one value declaration`, 412*1c12ee1eSDan Willemsen }, { 413*1c12ee1eSDan Willemsen label: "invalid enum value without number", 414*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 415*1c12ee1eSDan Willemsen name: "test.proto" 416*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{name:"E" value:[{name:"one"}]}]}] 417*1c12ee1eSDan Willemsen `), 418*1c12ee1eSDan Willemsen wantErr: `enum value "M.one" must have a specified number`, 419*1c12ee1eSDan Willemsen }, { 420*1c12ee1eSDan Willemsen label: "valid enum", 421*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 422*1c12ee1eSDan Willemsen name: "test.proto" 423*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{name:"E" value:[{name:"one" number:1}]}]}] 424*1c12ee1eSDan Willemsen `), 425*1c12ee1eSDan Willemsen }, { 426*1c12ee1eSDan Willemsen label: "invalid enum reserved names", 427*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 428*1c12ee1eSDan Willemsen name: "test.proto" 429*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 430*1c12ee1eSDan Willemsen name: "E" 431*1c12ee1eSDan Willemsen reserved_name: [""] 432*1c12ee1eSDan Willemsen value: [{name:"V" number:0}] 433*1c12ee1eSDan Willemsen }]}] 434*1c12ee1eSDan Willemsen `), 435*1c12ee1eSDan Willemsen // NOTE: In theory this should be an error. 436*1c12ee1eSDan Willemsen // See https://github.com/protocolbuffers/protobuf/issues/6335. 437*1c12ee1eSDan Willemsen /*wantErr: `enum "M.E" reserved names has invalid name: ""`,*/ 438*1c12ee1eSDan Willemsen }, { 439*1c12ee1eSDan Willemsen label: "duplicate enum reserved names", 440*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 441*1c12ee1eSDan Willemsen name: "test.proto" 442*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 443*1c12ee1eSDan Willemsen name: "E" 444*1c12ee1eSDan Willemsen reserved_name: ["foo", "foo"] 445*1c12ee1eSDan Willemsen }]}] 446*1c12ee1eSDan Willemsen `), 447*1c12ee1eSDan Willemsen wantErr: `enum "M.E" reserved names has duplicate name: "foo"`, 448*1c12ee1eSDan Willemsen }, { 449*1c12ee1eSDan Willemsen label: "valid enum reserved names", 450*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 451*1c12ee1eSDan Willemsen name: "test.proto" 452*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 453*1c12ee1eSDan Willemsen name: "E" 454*1c12ee1eSDan Willemsen reserved_name: ["foo", "bar"] 455*1c12ee1eSDan Willemsen value: [{name:"baz" number:1}] 456*1c12ee1eSDan Willemsen }]}] 457*1c12ee1eSDan Willemsen `), 458*1c12ee1eSDan Willemsen }, { 459*1c12ee1eSDan Willemsen label: "use of enum reserved names", 460*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 461*1c12ee1eSDan Willemsen name: "test.proto" 462*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 463*1c12ee1eSDan Willemsen name: "E" 464*1c12ee1eSDan Willemsen reserved_name: ["foo", "bar"] 465*1c12ee1eSDan Willemsen value: [{name:"foo" number:1}] 466*1c12ee1eSDan Willemsen }]}] 467*1c12ee1eSDan Willemsen `), 468*1c12ee1eSDan Willemsen wantErr: `enum value "M.foo" must not use reserved name`, 469*1c12ee1eSDan Willemsen }, { 470*1c12ee1eSDan Willemsen label: "invalid enum reserved ranges", 471*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 472*1c12ee1eSDan Willemsen name: "test.proto" 473*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 474*1c12ee1eSDan Willemsen name: "E" 475*1c12ee1eSDan Willemsen reserved_range: [{start:5 end:4}] 476*1c12ee1eSDan Willemsen }]}] 477*1c12ee1eSDan Willemsen `), 478*1c12ee1eSDan Willemsen wantErr: `enum "M.E" reserved ranges has invalid range: 5 to 4`, 479*1c12ee1eSDan Willemsen }, { 480*1c12ee1eSDan Willemsen label: "overlapping enum reserved ranges", 481*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 482*1c12ee1eSDan Willemsen name: "test.proto" 483*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 484*1c12ee1eSDan Willemsen name: "E" 485*1c12ee1eSDan Willemsen reserved_range: [{start:1 end:1000}, {start:10 end:100}] 486*1c12ee1eSDan Willemsen }]}] 487*1c12ee1eSDan Willemsen `), 488*1c12ee1eSDan Willemsen wantErr: `enum "M.E" reserved ranges has overlapping ranges: 1 to 1000 with 10 to 100`, 489*1c12ee1eSDan Willemsen }, { 490*1c12ee1eSDan Willemsen label: "valid enum reserved names", 491*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 492*1c12ee1eSDan Willemsen name: "test.proto" 493*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 494*1c12ee1eSDan Willemsen name: "E" 495*1c12ee1eSDan Willemsen reserved_range: [{start:1 end:10}, {start:100 end:1000}] 496*1c12ee1eSDan Willemsen value: [{name:"baz" number:50}] 497*1c12ee1eSDan Willemsen }]}] 498*1c12ee1eSDan Willemsen `), 499*1c12ee1eSDan Willemsen }, { 500*1c12ee1eSDan Willemsen label: "use of enum reserved range", 501*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 502*1c12ee1eSDan Willemsen name: "test.proto" 503*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 504*1c12ee1eSDan Willemsen name: "E" 505*1c12ee1eSDan Willemsen reserved_range: [{start:1 end:10}, {start:100 end:1000}] 506*1c12ee1eSDan Willemsen value: [{name:"baz" number:500}] 507*1c12ee1eSDan Willemsen }]}] 508*1c12ee1eSDan Willemsen `), 509*1c12ee1eSDan Willemsen wantErr: `enum value "M.baz" must not use reserved number 500`, 510*1c12ee1eSDan Willemsen }, { 511*1c12ee1eSDan Willemsen label: "unused enum alias feature", 512*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 513*1c12ee1eSDan Willemsen name: "test.proto" 514*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 515*1c12ee1eSDan Willemsen name: "E" 516*1c12ee1eSDan Willemsen value: [{name:"baz" number:500}] 517*1c12ee1eSDan Willemsen options: {allow_alias:true} 518*1c12ee1eSDan Willemsen }]}] 519*1c12ee1eSDan Willemsen `), 520*1c12ee1eSDan Willemsen wantErr: `enum "M.E" allows aliases, but none were found`, 521*1c12ee1eSDan Willemsen }, { 522*1c12ee1eSDan Willemsen label: "enum number conflicts", 523*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 524*1c12ee1eSDan Willemsen name: "test.proto" 525*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 526*1c12ee1eSDan Willemsen name: "E" 527*1c12ee1eSDan Willemsen value: [{name:"foo" number:0}, {name:"bar" number:1}, {name:"baz" number:1}] 528*1c12ee1eSDan Willemsen }]}] 529*1c12ee1eSDan Willemsen `), 530*1c12ee1eSDan Willemsen wantErr: `enum "M.E" has conflicting non-aliased values on number 1: "baz" with "bar"`, 531*1c12ee1eSDan Willemsen }, { 532*1c12ee1eSDan Willemsen label: "aliased enum numbers", 533*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 534*1c12ee1eSDan Willemsen name: "test.proto" 535*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 536*1c12ee1eSDan Willemsen name: "E" 537*1c12ee1eSDan Willemsen value: [{name:"foo" number:0}, {name:"bar" number:1}, {name:"baz" number:1}] 538*1c12ee1eSDan Willemsen options: {allow_alias:true} 539*1c12ee1eSDan Willemsen }]}] 540*1c12ee1eSDan Willemsen `), 541*1c12ee1eSDan Willemsen }, { 542*1c12ee1eSDan Willemsen label: "invalid proto3 enum", 543*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 544*1c12ee1eSDan Willemsen syntax: "proto3" 545*1c12ee1eSDan Willemsen name: "test.proto" 546*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 547*1c12ee1eSDan Willemsen name: "E" 548*1c12ee1eSDan Willemsen value: [{name:"baz" number:500}] 549*1c12ee1eSDan Willemsen }]}] 550*1c12ee1eSDan Willemsen `), 551*1c12ee1eSDan Willemsen wantErr: `enum "M.baz" using proto3 semantics must have zero number for the first value`, 552*1c12ee1eSDan Willemsen }, { 553*1c12ee1eSDan Willemsen label: "valid proto3 enum", 554*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 555*1c12ee1eSDan Willemsen syntax: "proto3" 556*1c12ee1eSDan Willemsen name: "test.proto" 557*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 558*1c12ee1eSDan Willemsen name: "E" 559*1c12ee1eSDan Willemsen value: [{name:"baz" number:0}] 560*1c12ee1eSDan Willemsen }]}] 561*1c12ee1eSDan Willemsen `), 562*1c12ee1eSDan Willemsen }, { 563*1c12ee1eSDan Willemsen label: "proto3 enum name prefix conflict", 564*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 565*1c12ee1eSDan Willemsen syntax: "proto3" 566*1c12ee1eSDan Willemsen name: "test.proto" 567*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 568*1c12ee1eSDan Willemsen name: "E" 569*1c12ee1eSDan Willemsen value: [{name:"e_Foo" number:0}, {name:"fOo" number:1}] 570*1c12ee1eSDan Willemsen }]}] 571*1c12ee1eSDan Willemsen `), 572*1c12ee1eSDan Willemsen wantErr: `enum "M.E" using proto3 semantics has conflict: "fOo" with "e_Foo"`, 573*1c12ee1eSDan Willemsen }, { 574*1c12ee1eSDan Willemsen label: "proto2 enum has name prefix check", 575*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 576*1c12ee1eSDan Willemsen name: "test.proto" 577*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 578*1c12ee1eSDan Willemsen name: "E" 579*1c12ee1eSDan Willemsen value: [{name:"e_Foo" number:0}, {name:"fOo" number:1}] 580*1c12ee1eSDan Willemsen }]}] 581*1c12ee1eSDan Willemsen `), 582*1c12ee1eSDan Willemsen }, { 583*1c12ee1eSDan Willemsen label: "proto3 enum same name prefix with number conflict", 584*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 585*1c12ee1eSDan Willemsen syntax: "proto3" 586*1c12ee1eSDan Willemsen name: "test.proto" 587*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 588*1c12ee1eSDan Willemsen name: "E" 589*1c12ee1eSDan Willemsen value: [{name:"e_Foo" number:0}, {name:"fOo" number:0}] 590*1c12ee1eSDan Willemsen }]}] 591*1c12ee1eSDan Willemsen `), 592*1c12ee1eSDan Willemsen wantErr: `enum "M.E" has conflicting non-aliased values on number 0: "fOo" with "e_Foo"`, 593*1c12ee1eSDan Willemsen }, { 594*1c12ee1eSDan Willemsen label: "proto3 enum same name prefix with alias numbers", 595*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 596*1c12ee1eSDan Willemsen syntax: "proto3" 597*1c12ee1eSDan Willemsen name: "test.proto" 598*1c12ee1eSDan Willemsen message_type: [{name:"M" enum_type:[{ 599*1c12ee1eSDan Willemsen name: "E" 600*1c12ee1eSDan Willemsen value: [{name:"e_Foo" number:0}, {name:"fOo" number:0}] 601*1c12ee1eSDan Willemsen options: {allow_alias: true} 602*1c12ee1eSDan Willemsen }]}] 603*1c12ee1eSDan Willemsen `), 604*1c12ee1eSDan Willemsen }, { 605*1c12ee1eSDan Willemsen label: "invalid message reserved names", 606*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 607*1c12ee1eSDan Willemsen name: "test.proto" 608*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 609*1c12ee1eSDan Willemsen name: "M" 610*1c12ee1eSDan Willemsen reserved_name: ["$"] 611*1c12ee1eSDan Willemsen }]}] 612*1c12ee1eSDan Willemsen `), 613*1c12ee1eSDan Willemsen // NOTE: In theory this should be an error. 614*1c12ee1eSDan Willemsen // See https://github.com/protocolbuffers/protobuf/issues/6335. 615*1c12ee1eSDan Willemsen /*wantErr: `message "M.M" reserved names has invalid name: "$"`,*/ 616*1c12ee1eSDan Willemsen }, { 617*1c12ee1eSDan Willemsen label: "valid message reserved names", 618*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 619*1c12ee1eSDan Willemsen name: "test.proto" 620*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 621*1c12ee1eSDan Willemsen name: "M" 622*1c12ee1eSDan Willemsen reserved_name: ["foo", "bar"] 623*1c12ee1eSDan Willemsen field: [{name:"foo" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}] 624*1c12ee1eSDan Willemsen }]}] 625*1c12ee1eSDan Willemsen `), 626*1c12ee1eSDan Willemsen wantErr: `message field "M.M.foo" must not use reserved name`, 627*1c12ee1eSDan Willemsen }, { 628*1c12ee1eSDan Willemsen label: "valid message reserved names", 629*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 630*1c12ee1eSDan Willemsen name: "test.proto" 631*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 632*1c12ee1eSDan Willemsen name: "M" 633*1c12ee1eSDan Willemsen reserved_name: ["foo", "bar"] 634*1c12ee1eSDan Willemsen field: [{name:"baz" number:1 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:0}] 635*1c12ee1eSDan Willemsen oneof_decl: [{name:"foo"}] # not affected by reserved_name 636*1c12ee1eSDan Willemsen }]}] 637*1c12ee1eSDan Willemsen `), 638*1c12ee1eSDan Willemsen }, { 639*1c12ee1eSDan Willemsen label: "invalid reserved number", 640*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 641*1c12ee1eSDan Willemsen name: "test.proto" 642*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 643*1c12ee1eSDan Willemsen name: "M" 644*1c12ee1eSDan Willemsen reserved_range: [{start:1 end:1}] 645*1c12ee1eSDan Willemsen field: [{name:"baz" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}] 646*1c12ee1eSDan Willemsen }]}] 647*1c12ee1eSDan Willemsen `), 648*1c12ee1eSDan Willemsen wantErr: `message "M.M" reserved ranges has invalid field number: 0`, 649*1c12ee1eSDan Willemsen }, { 650*1c12ee1eSDan Willemsen label: "invalid reserved ranges", 651*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 652*1c12ee1eSDan Willemsen name: "test.proto" 653*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 654*1c12ee1eSDan Willemsen name: "M" 655*1c12ee1eSDan Willemsen reserved_range: [{start:2 end:2}] 656*1c12ee1eSDan Willemsen field: [{name:"baz" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}] 657*1c12ee1eSDan Willemsen }]}] 658*1c12ee1eSDan Willemsen `), 659*1c12ee1eSDan Willemsen wantErr: `message "M.M" reserved ranges has invalid range: 2 to 1`, 660*1c12ee1eSDan Willemsen }, { 661*1c12ee1eSDan Willemsen label: "overlapping reserved ranges", 662*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 663*1c12ee1eSDan Willemsen name: "test.proto" 664*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 665*1c12ee1eSDan Willemsen name: "M" 666*1c12ee1eSDan Willemsen reserved_range: [{start:1 end:10}, {start:2 end:9}] 667*1c12ee1eSDan Willemsen field: [{name:"baz" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}] 668*1c12ee1eSDan Willemsen }]}] 669*1c12ee1eSDan Willemsen `), 670*1c12ee1eSDan Willemsen wantErr: `message "M.M" reserved ranges has overlapping ranges: 1 to 9 with 2 to 8`, 671*1c12ee1eSDan Willemsen }, { 672*1c12ee1eSDan Willemsen label: "use of reserved message field number", 673*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 674*1c12ee1eSDan Willemsen name: "test.proto" 675*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 676*1c12ee1eSDan Willemsen name: "M" 677*1c12ee1eSDan Willemsen reserved_range: [{start:10 end:20}, {start:20 end:30}, {start:30 end:31}] 678*1c12ee1eSDan Willemsen field: [{name:"baz" number:30 label:LABEL_OPTIONAL type:TYPE_STRING}] 679*1c12ee1eSDan Willemsen }]}] 680*1c12ee1eSDan Willemsen `), 681*1c12ee1eSDan Willemsen wantErr: `message field "M.M.baz" must not use reserved number 30`, 682*1c12ee1eSDan Willemsen }, { 683*1c12ee1eSDan Willemsen label: "invalid extension ranges", 684*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 685*1c12ee1eSDan Willemsen name: "test.proto" 686*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 687*1c12ee1eSDan Willemsen name: "M" 688*1c12ee1eSDan Willemsen extension_range: [{start:-500 end:2}] 689*1c12ee1eSDan Willemsen field: [{name:"baz" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}] 690*1c12ee1eSDan Willemsen }]}] 691*1c12ee1eSDan Willemsen `), 692*1c12ee1eSDan Willemsen wantErr: `message "M.M" extension ranges has invalid field number: -500`, 693*1c12ee1eSDan Willemsen }, { 694*1c12ee1eSDan Willemsen label: "overlapping reserved and extension ranges", 695*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 696*1c12ee1eSDan Willemsen name: "test.proto" 697*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 698*1c12ee1eSDan Willemsen name: "M" 699*1c12ee1eSDan Willemsen reserved_range: [{start:15 end:20}, {start:1 end:3}, {start:7 end:10}] 700*1c12ee1eSDan Willemsen extension_range: [{start:8 end:9}, {start:3 end:5}] 701*1c12ee1eSDan Willemsen }]}] 702*1c12ee1eSDan Willemsen `), 703*1c12ee1eSDan Willemsen wantErr: `message "M.M" reserved and extension ranges has overlapping ranges: 7 to 9 with 8`, 704*1c12ee1eSDan Willemsen }, { 705*1c12ee1eSDan Willemsen label: "message field conflicting number", 706*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 707*1c12ee1eSDan Willemsen name: "test.proto" 708*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 709*1c12ee1eSDan Willemsen name: "M" 710*1c12ee1eSDan Willemsen field: [ 711*1c12ee1eSDan Willemsen {name:"one" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, 712*1c12ee1eSDan Willemsen {name:"One" number:1 label:LABEL_OPTIONAL type:TYPE_STRING} 713*1c12ee1eSDan Willemsen ] 714*1c12ee1eSDan Willemsen }]}] 715*1c12ee1eSDan Willemsen `), 716*1c12ee1eSDan Willemsen wantErr: `message "M.M" has conflicting fields: "One" with "one"`, 717*1c12ee1eSDan Willemsen }, { 718*1c12ee1eSDan Willemsen label: "invalid MessageSet", 719*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 720*1c12ee1eSDan Willemsen syntax: "proto3" 721*1c12ee1eSDan Willemsen name: "test.proto" 722*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 723*1c12ee1eSDan Willemsen name: "M" 724*1c12ee1eSDan Willemsen options: {message_set_wire_format:true} 725*1c12ee1eSDan Willemsen }]}] 726*1c12ee1eSDan Willemsen `), 727*1c12ee1eSDan Willemsen wantErr: func() string { 728*1c12ee1eSDan Willemsen if flags.ProtoLegacy { 729*1c12ee1eSDan Willemsen return `message "M.M" is an invalid proto1 MessageSet` 730*1c12ee1eSDan Willemsen } else { 731*1c12ee1eSDan Willemsen return `message "M.M" is a MessageSet, which is a legacy proto1 feature that is no longer supported` 732*1c12ee1eSDan Willemsen } 733*1c12ee1eSDan Willemsen }(), 734*1c12ee1eSDan Willemsen }, { 735*1c12ee1eSDan Willemsen label: "valid MessageSet", 736*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 737*1c12ee1eSDan Willemsen name: "test.proto" 738*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 739*1c12ee1eSDan Willemsen name: "M" 740*1c12ee1eSDan Willemsen extension_range: [{start:1 end:100000}] 741*1c12ee1eSDan Willemsen options: {message_set_wire_format:true} 742*1c12ee1eSDan Willemsen }]}] 743*1c12ee1eSDan Willemsen `), 744*1c12ee1eSDan Willemsen wantErr: func() string { 745*1c12ee1eSDan Willemsen if flags.ProtoLegacy { 746*1c12ee1eSDan Willemsen return "" 747*1c12ee1eSDan Willemsen } else { 748*1c12ee1eSDan Willemsen return `message "M.M" is a MessageSet, which is a legacy proto1 feature that is no longer supported` 749*1c12ee1eSDan Willemsen } 750*1c12ee1eSDan Willemsen }(), 751*1c12ee1eSDan Willemsen }, { 752*1c12ee1eSDan Willemsen label: "invalid extension ranges in proto3", 753*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 754*1c12ee1eSDan Willemsen syntax: "proto3" 755*1c12ee1eSDan Willemsen name: "test.proto" 756*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 757*1c12ee1eSDan Willemsen name: "M" 758*1c12ee1eSDan Willemsen extension_range: [{start:1 end:100000}] 759*1c12ee1eSDan Willemsen }]}] 760*1c12ee1eSDan Willemsen `), 761*1c12ee1eSDan Willemsen wantErr: `message "M.M" using proto3 semantics cannot have extension ranges`, 762*1c12ee1eSDan Willemsen }, { 763*1c12ee1eSDan Willemsen label: "proto3 message fields conflict", 764*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 765*1c12ee1eSDan Willemsen syntax: "proto3" 766*1c12ee1eSDan Willemsen name: "test.proto" 767*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 768*1c12ee1eSDan Willemsen name: "M" 769*1c12ee1eSDan Willemsen field: [ 770*1c12ee1eSDan Willemsen {name:"_b_a_z_" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, 771*1c12ee1eSDan Willemsen {name:"baz" number:2 label:LABEL_OPTIONAL type:TYPE_STRING} 772*1c12ee1eSDan Willemsen ] 773*1c12ee1eSDan Willemsen }]}] 774*1c12ee1eSDan Willemsen `), 775*1c12ee1eSDan Willemsen wantErr: `message "M.M" using proto3 semantics has conflict: "baz" with "_b_a_z_"`, 776*1c12ee1eSDan Willemsen }, { 777*1c12ee1eSDan Willemsen label: "proto3 message fields", 778*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 779*1c12ee1eSDan Willemsen syntax: "proto3" 780*1c12ee1eSDan Willemsen name: "test.proto" 781*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 782*1c12ee1eSDan Willemsen name: "M" 783*1c12ee1eSDan Willemsen field: [{name:"_b_a_z_" number:1 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:0}] 784*1c12ee1eSDan Willemsen oneof_decl: [{name:"baz"}] # proto3 name conflict logic does not include oneof 785*1c12ee1eSDan Willemsen }]}] 786*1c12ee1eSDan Willemsen `), 787*1c12ee1eSDan Willemsen }, { 788*1c12ee1eSDan Willemsen label: "proto2 message fields with no conflict", 789*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 790*1c12ee1eSDan Willemsen name: "test.proto" 791*1c12ee1eSDan Willemsen message_type: [{name:"M" nested_type:[{ 792*1c12ee1eSDan Willemsen name: "M" 793*1c12ee1eSDan Willemsen field: [ 794*1c12ee1eSDan Willemsen {name:"_b_a_z_" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, 795*1c12ee1eSDan Willemsen {name:"baz" number:2 label:LABEL_OPTIONAL type:TYPE_STRING} 796*1c12ee1eSDan Willemsen ] 797*1c12ee1eSDan Willemsen }]}] 798*1c12ee1eSDan Willemsen `), 799*1c12ee1eSDan Willemsen }, { 800*1c12ee1eSDan Willemsen label: "proto3 message with unresolved enum", 801*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 802*1c12ee1eSDan Willemsen name: "test.proto" 803*1c12ee1eSDan Willemsen syntax: "proto3" 804*1c12ee1eSDan Willemsen message_type: [{ 805*1c12ee1eSDan Willemsen name: "M" 806*1c12ee1eSDan Willemsen field: [ 807*1c12ee1eSDan Willemsen {name:"enum" number:1 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".fizz.buzz.Enum"} 808*1c12ee1eSDan Willemsen ] 809*1c12ee1eSDan Willemsen }] 810*1c12ee1eSDan Willemsen `), 811*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 812*1c12ee1eSDan Willemsen // TODO: Test field and oneof handling in validateMessageDeclarations 813*1c12ee1eSDan Willemsen // TODO: Test unmarshalDefault 814*1c12ee1eSDan Willemsen // TODO: Test validateExtensionDeclarations 815*1c12ee1eSDan Willemsen // TODO: Test checkValidGroup 816*1c12ee1eSDan Willemsen // TODO: Test checkValidMap 817*1c12ee1eSDan Willemsen }, { 818*1c12ee1eSDan Willemsen label: "empty service", 819*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 820*1c12ee1eSDan Willemsen name: "test.proto" 821*1c12ee1eSDan Willemsen service: [{name:"service"}] 822*1c12ee1eSDan Willemsen `), 823*1c12ee1eSDan Willemsen }, { 824*1c12ee1eSDan Willemsen label: "service with method with unresolved", 825*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 826*1c12ee1eSDan Willemsen name: "test.proto" 827*1c12ee1eSDan Willemsen service: [{ 828*1c12ee1eSDan Willemsen name: "service" 829*1c12ee1eSDan Willemsen method: [{ 830*1c12ee1eSDan Willemsen name:"method" 831*1c12ee1eSDan Willemsen input_type:"foo" 832*1c12ee1eSDan Willemsen output_type:".foo.bar.baz" 833*1c12ee1eSDan Willemsen }] 834*1c12ee1eSDan Willemsen }] 835*1c12ee1eSDan Willemsen `), 836*1c12ee1eSDan Willemsen inOpts: FileOptions{AllowUnresolvable: true}, 837*1c12ee1eSDan Willemsen }, { 838*1c12ee1eSDan Willemsen label: "service with wrong reference type", 839*1c12ee1eSDan Willemsen inDeps: []*descriptorpb.FileDescriptorProto{ 840*1c12ee1eSDan Willemsen cloneFile(proto3Message), 841*1c12ee1eSDan Willemsen cloneFile(proto2Enum), 842*1c12ee1eSDan Willemsen }, 843*1c12ee1eSDan Willemsen inDesc: mustParseFile(` 844*1c12ee1eSDan Willemsen name: "test.proto" 845*1c12ee1eSDan Willemsen dependency: ["proto2_enum.proto", "proto3_message.proto"] 846*1c12ee1eSDan Willemsen service: [{ 847*1c12ee1eSDan Willemsen name: "service" 848*1c12ee1eSDan Willemsen method: [{ 849*1c12ee1eSDan Willemsen name: "method" 850*1c12ee1eSDan Willemsen input_type: ".test.proto2.Enum", 851*1c12ee1eSDan Willemsen output_type: ".test.proto3.Message" 852*1c12ee1eSDan Willemsen }] 853*1c12ee1eSDan Willemsen }] 854*1c12ee1eSDan Willemsen `), 855*1c12ee1eSDan Willemsen wantErr: `service method "service.method" cannot resolve input: resolved "test.proto2.Enum", but it is not an message`, 856*1c12ee1eSDan Willemsen }} 857*1c12ee1eSDan Willemsen 858*1c12ee1eSDan Willemsen for _, tt := range tests { 859*1c12ee1eSDan Willemsen t.Run(tt.label, func(t *testing.T) { 860*1c12ee1eSDan Willemsen r := new(protoregistry.Files) 861*1c12ee1eSDan Willemsen for i, dep := range tt.inDeps { 862*1c12ee1eSDan Willemsen f, err := tt.inOpts.New(dep, r) 863*1c12ee1eSDan Willemsen if err != nil { 864*1c12ee1eSDan Willemsen t.Fatalf("dependency %d: unexpected NewFile() error: %v", i, err) 865*1c12ee1eSDan Willemsen } 866*1c12ee1eSDan Willemsen if err := r.RegisterFile(f); err != nil { 867*1c12ee1eSDan Willemsen t.Fatalf("dependency %d: unexpected Register() error: %v", i, err) 868*1c12ee1eSDan Willemsen } 869*1c12ee1eSDan Willemsen } 870*1c12ee1eSDan Willemsen var gotDesc *descriptorpb.FileDescriptorProto 871*1c12ee1eSDan Willemsen if tt.wantErr == "" && tt.wantDesc == nil { 872*1c12ee1eSDan Willemsen tt.wantDesc = cloneFile(tt.inDesc) 873*1c12ee1eSDan Willemsen } 874*1c12ee1eSDan Willemsen gotFile, err := tt.inOpts.New(tt.inDesc, r) 875*1c12ee1eSDan Willemsen if gotFile != nil { 876*1c12ee1eSDan Willemsen gotDesc = ToFileDescriptorProto(gotFile) 877*1c12ee1eSDan Willemsen } 878*1c12ee1eSDan Willemsen if !proto.Equal(gotDesc, tt.wantDesc) { 879*1c12ee1eSDan Willemsen t.Errorf("NewFile() mismatch:\ngot %v\nwant %v", gotDesc, tt.wantDesc) 880*1c12ee1eSDan Willemsen } 881*1c12ee1eSDan Willemsen if ((err == nil) != (tt.wantErr == "")) || !strings.Contains(fmt.Sprint(err), tt.wantErr) { 882*1c12ee1eSDan Willemsen t.Errorf("NewFile() error:\ngot: %v\nwant: %v", err, tt.wantErr) 883*1c12ee1eSDan Willemsen } 884*1c12ee1eSDan Willemsen }) 885*1c12ee1eSDan Willemsen } 886*1c12ee1eSDan Willemsen} 887*1c12ee1eSDan Willemsen 888*1c12ee1eSDan Willemsenfunc TestNewFiles(t *testing.T) { 889*1c12ee1eSDan Willemsen fdset := &descriptorpb.FileDescriptorSet{ 890*1c12ee1eSDan Willemsen File: []*descriptorpb.FileDescriptorProto{ 891*1c12ee1eSDan Willemsen mustParseFile(` 892*1c12ee1eSDan Willemsen name: "test.proto" 893*1c12ee1eSDan Willemsen package: "fizz" 894*1c12ee1eSDan Willemsen dependency: "dep.proto" 895*1c12ee1eSDan Willemsen message_type: [{ 896*1c12ee1eSDan Willemsen name: "M2" 897*1c12ee1eSDan Willemsen field: [{name:"F" number:1 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:"M1"}] 898*1c12ee1eSDan Willemsen }] 899*1c12ee1eSDan Willemsen `), 900*1c12ee1eSDan Willemsen // Inputs deliberately out of order. 901*1c12ee1eSDan Willemsen mustParseFile(` 902*1c12ee1eSDan Willemsen name: "dep.proto" 903*1c12ee1eSDan Willemsen package: "fizz" 904*1c12ee1eSDan Willemsen message_type: [{name:"M1"}] 905*1c12ee1eSDan Willemsen `), 906*1c12ee1eSDan Willemsen }, 907*1c12ee1eSDan Willemsen } 908*1c12ee1eSDan Willemsen f, err := NewFiles(fdset) 909*1c12ee1eSDan Willemsen if err != nil { 910*1c12ee1eSDan Willemsen t.Fatal(err) 911*1c12ee1eSDan Willemsen } 912*1c12ee1eSDan Willemsen m1, err := f.FindDescriptorByName("fizz.M1") 913*1c12ee1eSDan Willemsen if err != nil { 914*1c12ee1eSDan Willemsen t.Fatalf(`f.FindDescriptorByName("fizz.M1") = %v`, err) 915*1c12ee1eSDan Willemsen } 916*1c12ee1eSDan Willemsen m2, err := f.FindDescriptorByName("fizz.M2") 917*1c12ee1eSDan Willemsen if err != nil { 918*1c12ee1eSDan Willemsen t.Fatalf(`f.FindDescriptorByName("fizz.M2") = %v`, err) 919*1c12ee1eSDan Willemsen } 920*1c12ee1eSDan Willemsen if m2.(protoreflect.MessageDescriptor).Fields().ByName("F").Message() != m1 { 921*1c12ee1eSDan Willemsen t.Fatalf(`m1.Fields().ByName("F").Message() != m2`) 922*1c12ee1eSDan Willemsen } 923*1c12ee1eSDan Willemsen} 924*1c12ee1eSDan Willemsen 925*1c12ee1eSDan Willemsenfunc TestNewFilesImportCycle(t *testing.T) { 926*1c12ee1eSDan Willemsen fdset := &descriptorpb.FileDescriptorSet{ 927*1c12ee1eSDan Willemsen File: []*descriptorpb.FileDescriptorProto{ 928*1c12ee1eSDan Willemsen mustParseFile(` 929*1c12ee1eSDan Willemsen name: "test.proto" 930*1c12ee1eSDan Willemsen package: "fizz" 931*1c12ee1eSDan Willemsen dependency: "dep.proto" 932*1c12ee1eSDan Willemsen `), 933*1c12ee1eSDan Willemsen mustParseFile(` 934*1c12ee1eSDan Willemsen name: "dep.proto" 935*1c12ee1eSDan Willemsen package: "fizz" 936*1c12ee1eSDan Willemsen dependency: "test.proto" 937*1c12ee1eSDan Willemsen `), 938*1c12ee1eSDan Willemsen }, 939*1c12ee1eSDan Willemsen } 940*1c12ee1eSDan Willemsen _, err := NewFiles(fdset) 941*1c12ee1eSDan Willemsen if err == nil { 942*1c12ee1eSDan Willemsen t.Fatal("NewFiles with import cycle: success, want error") 943*1c12ee1eSDan Willemsen } 944*1c12ee1eSDan Willemsen} 945*1c12ee1eSDan Willemsen 946*1c12ee1eSDan Willemsenfunc TestSourceLocations(t *testing.T) { 947*1c12ee1eSDan Willemsen fd := mustParseFile(` 948*1c12ee1eSDan Willemsen name: "comments.proto" 949*1c12ee1eSDan Willemsen message_type: [{ 950*1c12ee1eSDan Willemsen name: "Message1" 951*1c12ee1eSDan Willemsen field: [ 952*1c12ee1eSDan Willemsen {name:"field1" number:1 label:LABEL_OPTIONAL type:TYPE_STRING}, 953*1c12ee1eSDan Willemsen {name:"field2" number:2 label:LABEL_OPTIONAL type:TYPE_STRING}, 954*1c12ee1eSDan Willemsen {name:"field3" number:3 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:0}, 955*1c12ee1eSDan Willemsen {name:"field4" number:4 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:0}, 956*1c12ee1eSDan Willemsen {name:"field5" number:5 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:1}, 957*1c12ee1eSDan Willemsen {name:"field6" number:6 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:1} 958*1c12ee1eSDan Willemsen ] 959*1c12ee1eSDan Willemsen extension: [ 960*1c12ee1eSDan Willemsen {name:"extension1" number:100 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"}, 961*1c12ee1eSDan Willemsen {name:"extension2" number:101 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"} 962*1c12ee1eSDan Willemsen ] 963*1c12ee1eSDan Willemsen nested_type: [{name:"Message1"}, {name:"Message2"}] 964*1c12ee1eSDan Willemsen extension_range: {start:100 end:536870912} 965*1c12ee1eSDan Willemsen oneof_decl: [{name:"oneof1"}, {name:"oneof2"}] 966*1c12ee1eSDan Willemsen }, { 967*1c12ee1eSDan Willemsen name: "Message2" 968*1c12ee1eSDan Willemsen enum_type: { 969*1c12ee1eSDan Willemsen name: "Enum1" 970*1c12ee1eSDan Willemsen value: [ 971*1c12ee1eSDan Willemsen {name: "FOO", number: 0}, 972*1c12ee1eSDan Willemsen {name: "BAR", number: 1} 973*1c12ee1eSDan Willemsen ] 974*1c12ee1eSDan Willemsen } 975*1c12ee1eSDan Willemsen }] 976*1c12ee1eSDan Willemsen enum_type: { 977*1c12ee1eSDan Willemsen name: "Enum1" 978*1c12ee1eSDan Willemsen value: [ 979*1c12ee1eSDan Willemsen {name: "FOO", number: 0}, 980*1c12ee1eSDan Willemsen {name: "BAR", number: 1} 981*1c12ee1eSDan Willemsen ] 982*1c12ee1eSDan Willemsen } 983*1c12ee1eSDan Willemsen service: { 984*1c12ee1eSDan Willemsen name: "Service1" 985*1c12ee1eSDan Willemsen method: [ 986*1c12ee1eSDan Willemsen {name:"Method1" input_type:".Message1" output_type:".Message1"}, 987*1c12ee1eSDan Willemsen {name:"Method2" input_type:".Message2" output_type:".Message2"} 988*1c12ee1eSDan Willemsen ] 989*1c12ee1eSDan Willemsen } 990*1c12ee1eSDan Willemsen extension: [ 991*1c12ee1eSDan Willemsen {name:"extension1" number:102 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"}, 992*1c12ee1eSDan Willemsen {name:"extension2" number:103 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"} 993*1c12ee1eSDan Willemsen ] 994*1c12ee1eSDan Willemsen source_code_info: { 995*1c12ee1eSDan Willemsen location: [ 996*1c12ee1eSDan Willemsen {span:[0,0,69,1]}, 997*1c12ee1eSDan Willemsen {path:[12] span:[0,0,18]}, 998*1c12ee1eSDan Willemsen {path:[5,0] span:[3,0,8,1] leading_comments:" Enum1\r\n"}, 999*1c12ee1eSDan Willemsen {path:[5,0,1] span:[3,5,10]}, 1000*1c12ee1eSDan Willemsen {path:[5,0,2,0] span:[5,2,10] leading_comments:" FOO\r\n"}, 1001*1c12ee1eSDan Willemsen {path:[5,0,2,0,1] span:[5,2,5]}, 1002*1c12ee1eSDan Willemsen {path:[5,0,2,0,2] span:[5,8,9]}, 1003*1c12ee1eSDan Willemsen {path:[5,0,2,1] span:[7,2,10] leading_comments:" BAR\r\n"}, 1004*1c12ee1eSDan Willemsen {path:[5,0,2,1,1] span:[7,2,5]}, 1005*1c12ee1eSDan Willemsen {path:[5,0,2,1,2] span:[7,8,9]}, 1006*1c12ee1eSDan Willemsen {path:[4,0] span:[11,0,43,1] leading_comments:" Message1\r\n"}, 1007*1c12ee1eSDan Willemsen {path:[4,0,1] span:[11,8,16]}, 1008*1c12ee1eSDan Willemsen {path:[4,0,3,0] span:[13,2,21] leading_comments:" Message1.Message1\r\n"}, 1009*1c12ee1eSDan Willemsen {path:[4,0,3,0,1] span:[13,10,18]}, 1010*1c12ee1eSDan Willemsen {path:[4,0,3,1] span:[15,2,21] leading_comments:" Message1.Message2\r\n"}, 1011*1c12ee1eSDan Willemsen {path:[4,0,3,1,1] span:[15,10,18]}, 1012*1c12ee1eSDan Willemsen {path:[4,0,2,0] span:[18,2,29] leading_comments:" Message1.field1\r\n"}, 1013*1c12ee1eSDan Willemsen {path:[4,0,2,0,4] span:[18,2,10]}, 1014*1c12ee1eSDan Willemsen {path:[4,0,2,0,5] span:[18,11,17]}, 1015*1c12ee1eSDan Willemsen {path:[4,0,2,0,1] span:[18,18,24]}, 1016*1c12ee1eSDan Willemsen {path:[4,0,2,0,3] span:[18,27,28]}, 1017*1c12ee1eSDan Willemsen {path:[4,0,2,1] span:[20,2,29] leading_comments:" Message1.field2\r\n"}, 1018*1c12ee1eSDan Willemsen {path:[4,0,2,1,4] span:[20,2,10]}, 1019*1c12ee1eSDan Willemsen {path:[4,0,2,1,5] span:[20,11,17]}, 1020*1c12ee1eSDan Willemsen {path:[4,0,2,1,1] span:[20,18,24]}, 1021*1c12ee1eSDan Willemsen {path:[4,0,2,1,3] span:[20,27,28]}, 1022*1c12ee1eSDan Willemsen {path:[4,0,8,0] span:[22,2,27,3] leading_comments:" Message1.oneof1\r\n"}, 1023*1c12ee1eSDan Willemsen {path:[4,0,8,0,1] span:[22,8,14]}, 1024*1c12ee1eSDan Willemsen {path:[4,0,2,2] span:[24,4,22] leading_comments:" Message1.field3\r\n"}, 1025*1c12ee1eSDan Willemsen {path:[4,0,2,2,5] span:[24,4,10]}, 1026*1c12ee1eSDan Willemsen {path:[4,0,2,2,1] span:[24,11,17]}, 1027*1c12ee1eSDan Willemsen {path:[4,0,2,2,3] span:[24,20,21]}, 1028*1c12ee1eSDan Willemsen {path:[4,0,2,3] span:[26,4,22] leading_comments:" Message1.field4\r\n"}, 1029*1c12ee1eSDan Willemsen {path:[4,0,2,3,5] span:[26,4,10]}, 1030*1c12ee1eSDan Willemsen {path:[4,0,2,3,1] span:[26,11,17]}, 1031*1c12ee1eSDan Willemsen {path:[4,0,2,3,3] span:[26,20,21]}, 1032*1c12ee1eSDan Willemsen {path:[4,0,8,1] span:[29,2,34,3] leading_comments:" Message1.oneof2\r\n"}, 1033*1c12ee1eSDan Willemsen {path:[4,0,8,1,1] span:[29,8,14]}, 1034*1c12ee1eSDan Willemsen {path:[4,0,2,4] span:[31,4,22] leading_comments:" Message1.field5\r\n"}, 1035*1c12ee1eSDan Willemsen {path:[4,0,2,4,5] span:[31,4,10]}, 1036*1c12ee1eSDan Willemsen {path:[4,0,2,4,1] span:[31,11,17]}, 1037*1c12ee1eSDan Willemsen {path:[4,0,2,4,3] span:[31,20,21]}, 1038*1c12ee1eSDan Willemsen {path:[4,0,2,5] span:[33,4,22] leading_comments:" Message1.field6\r\n"}, 1039*1c12ee1eSDan Willemsen {path:[4,0,2,5,5] span:[33,4,10]}, 1040*1c12ee1eSDan Willemsen {path:[4,0,2,5,1] span:[33,11,17]}, 1041*1c12ee1eSDan Willemsen {path:[4,0,2,5,3] span:[33,20,21]}, 1042*1c12ee1eSDan Willemsen {path:[4,0,5] span:[36,2,24]}, 1043*1c12ee1eSDan Willemsen {path:[4,0,5,0] span:[36,13,23]}, 1044*1c12ee1eSDan Willemsen {path:[4,0,5,0,1] span:[36,13,16]}, 1045*1c12ee1eSDan Willemsen {path:[4,0,5,0,2] span:[36,20,23]}, 1046*1c12ee1eSDan Willemsen {path:[4,0,6] span:[37,2,42,3]}, 1047*1c12ee1eSDan Willemsen {path:[4,0,6,0] span:[39,4,37] leading_comments:" Message1.extension1\r\n"}, 1048*1c12ee1eSDan Willemsen {path:[4,0,6,0,2] span:[37,9,18]}, 1049*1c12ee1eSDan Willemsen {path:[4,0,6,0,4] span:[39,4,12]}, 1050*1c12ee1eSDan Willemsen {path:[4,0,6,0,5] span:[39,13,19]}, 1051*1c12ee1eSDan Willemsen {path:[4,0,6,0,1] span:[39,20,30]}, 1052*1c12ee1eSDan Willemsen {path:[4,0,6,0,3] span:[39,33,36]}, 1053*1c12ee1eSDan Willemsen {path:[4,0,6,1] span:[41,4,37] leading_comments:" Message1.extension2\r\n"}, 1054*1c12ee1eSDan Willemsen {path:[4,0,6,1,2] span:[37,9,18]}, 1055*1c12ee1eSDan Willemsen {path:[4,0,6,1,4] span:[41,4,12]}, 1056*1c12ee1eSDan Willemsen {path:[4,0,6,1,5] span:[41,13,19]}, 1057*1c12ee1eSDan Willemsen {path:[4,0,6,1,1] span:[41,20,30]}, 1058*1c12ee1eSDan Willemsen {path:[4,0,6,1,3] span:[41,33,36]}, 1059*1c12ee1eSDan Willemsen {path:[7] span:[45,0,50,1]}, 1060*1c12ee1eSDan Willemsen {path:[7,0] span:[47,2,35] leading_comments:" extension1\r\n"}, 1061*1c12ee1eSDan Willemsen {path:[7,0,2] span:[45,7,15]}, 1062*1c12ee1eSDan Willemsen {path:[7,0,4] span:[47,2,10]}, 1063*1c12ee1eSDan Willemsen {path:[7,0,5] span:[47,11,17]}, 1064*1c12ee1eSDan Willemsen {path:[7,0,1] span:[47,18,28]}, 1065*1c12ee1eSDan Willemsen {path:[7,0,3] span:[47,31,34]}, 1066*1c12ee1eSDan Willemsen {path:[7,1] span:[49,2,35] leading_comments:" extension2\r\n"}, 1067*1c12ee1eSDan Willemsen {path:[7,1,2] span:[45,7,15]}, 1068*1c12ee1eSDan Willemsen {path:[7,1,4] span:[49,2,10]}, 1069*1c12ee1eSDan Willemsen {path:[7,1,5] span:[49,11,17]}, 1070*1c12ee1eSDan Willemsen {path:[7,1,1] span:[49,18,28]}, 1071*1c12ee1eSDan Willemsen {path:[7,1,3] span:[49,31,34]}, 1072*1c12ee1eSDan Willemsen {path:[4,1] span:[53,0,61,1] leading_comments:" Message2\r\n"}, 1073*1c12ee1eSDan Willemsen {path:[4,1,1] span:[53,8,16]}, 1074*1c12ee1eSDan Willemsen {path:[4,1,4,0] span:[55,2,60,3] leading_comments:" Message2.Enum1\r\n"}, 1075*1c12ee1eSDan Willemsen {path:[4,1,4,0,1] span:[55,7,12]}, 1076*1c12ee1eSDan Willemsen {path:[4,1,4,0,2,0] span:[57,4,12] leading_comments:" Message2.FOO\r\n"}, 1077*1c12ee1eSDan Willemsen {path:[4,1,4,0,2,0,1] span:[57,4,7]}, 1078*1c12ee1eSDan Willemsen {path:[4,1,4,0,2,0,2] span:[57,10,11]}, 1079*1c12ee1eSDan Willemsen {path:[4,1,4,0,2,1] span:[59,4,12] leading_comments:" Message2.BAR\r\n"}, 1080*1c12ee1eSDan Willemsen {path:[4,1,4,0,2,1,1] span:[59,4,7]}, 1081*1c12ee1eSDan Willemsen {path:[4,1,4,0,2,1,2] span:[59,10,11]}, 1082*1c12ee1eSDan Willemsen {path:[6,0] span:[64,0,69,1] leading_comments:" Service1\r\n"}, 1083*1c12ee1eSDan Willemsen {path:[6,0,1] span:[64,8,16]}, 1084*1c12ee1eSDan Willemsen {path:[6,0,2,0] span:[66,2,43] leading_comments:" Service1.Method1\r\n"}, 1085*1c12ee1eSDan Willemsen {path:[6,0,2,0,1] span:[66,6,13]}, 1086*1c12ee1eSDan Willemsen {path:[6,0,2,0,2] span:[66,14,22]}, 1087*1c12ee1eSDan Willemsen {path:[6,0,2,0,3] span:[66,33,41]}, 1088*1c12ee1eSDan Willemsen {path:[6,0,2,1] span:[68,2,43] leading_comments:" Service1.Method2\r\n"}, 1089*1c12ee1eSDan Willemsen {path:[6,0,2,1,1] span:[68,6,13]}, 1090*1c12ee1eSDan Willemsen {path:[6,0,2,1,2] span:[68,14,22]}, 1091*1c12ee1eSDan Willemsen {path:[6,0,2,1,3] span:[68,33,41]} 1092*1c12ee1eSDan Willemsen ] 1093*1c12ee1eSDan Willemsen } 1094*1c12ee1eSDan Willemsen `) 1095*1c12ee1eSDan Willemsen fileDesc, err := NewFile(fd, nil) 1096*1c12ee1eSDan Willemsen if err != nil { 1097*1c12ee1eSDan Willemsen t.Fatalf("NewFile error: %v", err) 1098*1c12ee1eSDan Willemsen } 1099*1c12ee1eSDan Willemsen 1100*1c12ee1eSDan Willemsen var walkDescs func(protoreflect.Descriptor, func(protoreflect.Descriptor)) 1101*1c12ee1eSDan Willemsen walkDescs = func(d protoreflect.Descriptor, f func(protoreflect.Descriptor)) { 1102*1c12ee1eSDan Willemsen f(d) 1103*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1104*1c12ee1eSDan Willemsen Enums() protoreflect.EnumDescriptors 1105*1c12ee1eSDan Willemsen }); ok { 1106*1c12ee1eSDan Willemsen eds := d.Enums() 1107*1c12ee1eSDan Willemsen for i := 0; i < eds.Len(); i++ { 1108*1c12ee1eSDan Willemsen walkDescs(eds.Get(i), f) 1109*1c12ee1eSDan Willemsen } 1110*1c12ee1eSDan Willemsen } 1111*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1112*1c12ee1eSDan Willemsen Values() protoreflect.EnumValueDescriptors 1113*1c12ee1eSDan Willemsen }); ok { 1114*1c12ee1eSDan Willemsen vds := d.Values() 1115*1c12ee1eSDan Willemsen for i := 0; i < vds.Len(); i++ { 1116*1c12ee1eSDan Willemsen walkDescs(vds.Get(i), f) 1117*1c12ee1eSDan Willemsen } 1118*1c12ee1eSDan Willemsen } 1119*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1120*1c12ee1eSDan Willemsen Messages() protoreflect.MessageDescriptors 1121*1c12ee1eSDan Willemsen }); ok { 1122*1c12ee1eSDan Willemsen mds := d.Messages() 1123*1c12ee1eSDan Willemsen for i := 0; i < mds.Len(); i++ { 1124*1c12ee1eSDan Willemsen walkDescs(mds.Get(i), f) 1125*1c12ee1eSDan Willemsen } 1126*1c12ee1eSDan Willemsen } 1127*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1128*1c12ee1eSDan Willemsen Fields() protoreflect.FieldDescriptors 1129*1c12ee1eSDan Willemsen }); ok { 1130*1c12ee1eSDan Willemsen fds := d.Fields() 1131*1c12ee1eSDan Willemsen for i := 0; i < fds.Len(); i++ { 1132*1c12ee1eSDan Willemsen walkDescs(fds.Get(i), f) 1133*1c12ee1eSDan Willemsen } 1134*1c12ee1eSDan Willemsen } 1135*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1136*1c12ee1eSDan Willemsen Oneofs() protoreflect.OneofDescriptors 1137*1c12ee1eSDan Willemsen }); ok { 1138*1c12ee1eSDan Willemsen ods := d.Oneofs() 1139*1c12ee1eSDan Willemsen for i := 0; i < ods.Len(); i++ { 1140*1c12ee1eSDan Willemsen walkDescs(ods.Get(i), f) 1141*1c12ee1eSDan Willemsen } 1142*1c12ee1eSDan Willemsen } 1143*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1144*1c12ee1eSDan Willemsen Extensions() protoreflect.ExtensionDescriptors 1145*1c12ee1eSDan Willemsen }); ok { 1146*1c12ee1eSDan Willemsen xds := d.Extensions() 1147*1c12ee1eSDan Willemsen for i := 0; i < xds.Len(); i++ { 1148*1c12ee1eSDan Willemsen walkDescs(xds.Get(i), f) 1149*1c12ee1eSDan Willemsen } 1150*1c12ee1eSDan Willemsen } 1151*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1152*1c12ee1eSDan Willemsen Services() protoreflect.ServiceDescriptors 1153*1c12ee1eSDan Willemsen }); ok { 1154*1c12ee1eSDan Willemsen sds := d.Services() 1155*1c12ee1eSDan Willemsen for i := 0; i < sds.Len(); i++ { 1156*1c12ee1eSDan Willemsen walkDescs(sds.Get(i), f) 1157*1c12ee1eSDan Willemsen } 1158*1c12ee1eSDan Willemsen } 1159*1c12ee1eSDan Willemsen if d, ok := d.(interface { 1160*1c12ee1eSDan Willemsen Methods() protoreflect.MethodDescriptors 1161*1c12ee1eSDan Willemsen }); ok { 1162*1c12ee1eSDan Willemsen mds := d.Methods() 1163*1c12ee1eSDan Willemsen for i := 0; i < mds.Len(); i++ { 1164*1c12ee1eSDan Willemsen walkDescs(mds.Get(i), f) 1165*1c12ee1eSDan Willemsen } 1166*1c12ee1eSDan Willemsen } 1167*1c12ee1eSDan Willemsen } 1168*1c12ee1eSDan Willemsen 1169*1c12ee1eSDan Willemsen var numDescs int 1170*1c12ee1eSDan Willemsen walkDescs(fileDesc, func(d protoreflect.Descriptor) { 1171*1c12ee1eSDan Willemsen // The comment for every descriptor should be the full name itself. 1172*1c12ee1eSDan Willemsen got := strings.TrimSpace(fileDesc.SourceLocations().ByDescriptor(d).LeadingComments) 1173*1c12ee1eSDan Willemsen want := string(d.FullName()) 1174*1c12ee1eSDan Willemsen if got != want { 1175*1c12ee1eSDan Willemsen t.Errorf("comment mismatch: got %v, want %v", got, want) 1176*1c12ee1eSDan Willemsen } 1177*1c12ee1eSDan Willemsen numDescs++ 1178*1c12ee1eSDan Willemsen }) 1179*1c12ee1eSDan Willemsen if numDescs != 30 { 1180*1c12ee1eSDan Willemsen t.Errorf("visited %d descriptor, expected 30", numDescs) 1181*1c12ee1eSDan Willemsen } 1182*1c12ee1eSDan Willemsen} 1183