1// Protocol Buffers for Go with Gadgets 2// 3// Copyright (c) 2013, The GoGo Authors. All rights reserved. 4// http://github.com/gogo/protobuf 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are 8// met: 9// 10// * Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// * Redistributions in binary form must reproduce the above 13// copyright notice, this list of conditions and the following disclaimer 14// in the documentation and/or other materials provided with the 15// distribution. 16// 17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29/* 30The populate plugin generates a NewPopulated function. 31This function returns a newly populated structure. 32 33It is enabled by the following extensions: 34 35 - populate 36 - populate_all 37 38Let us look at: 39 40 github.com/gogo/protobuf/test/example/example.proto 41 42Btw all the output can be seen at: 43 44 github.com/gogo/protobuf/test/example/* 45 46The following message: 47 48 option (gogoproto.populate_all) = true; 49 50 message B { 51 optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; 52 repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; 53 } 54 55given to the populate plugin, will generate code the following code: 56 57 func NewPopulatedB(r randyExample, easy bool) *B { 58 this := &B{} 59 v2 := NewPopulatedA(r, easy) 60 this.A = *v2 61 if r.Intn(10) != 0 { 62 v3 := r.Intn(10) 63 this.G = make([]github_com_gogo_protobuf_test_custom.Uint128, v3) 64 for i := 0; i < v3; i++ { 65 v4 := github_com_gogo_protobuf_test_custom.NewPopulatedUint128(r) 66 this.G[i] = *v4 67 } 68 } 69 if !easy && r.Intn(10) != 0 { 70 this.XXX_unrecognized = randUnrecognizedExample(r, 3) 71 } 72 return this 73 } 74 75The idea that is useful for testing. 76Most of the other plugins' generated test code uses it. 77You will still be able to use the generated test code of other packages 78if you turn off the popluate plugin and write your own custom NewPopulated function. 79 80If the easy flag is not set the XXX_unrecognized and XXX_extensions fields are also populated. 81These have caused problems with JSON marshalling and unmarshalling tests. 82 83*/ 84package populate 85 86import ( 87 "fmt" 88 "math" 89 "strconv" 90 "strings" 91 92 "github.com/gogo/protobuf/gogoproto" 93 "github.com/gogo/protobuf/proto" 94 descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" 95 "github.com/gogo/protobuf/protoc-gen-gogo/generator" 96 "github.com/gogo/protobuf/vanity" 97) 98 99type VarGen interface { 100 Next() string 101 Current() string 102} 103 104type varGen struct { 105 index int64 106} 107 108func NewVarGen() VarGen { 109 return &varGen{0} 110} 111 112func (this *varGen) Next() string { 113 this.index++ 114 return fmt.Sprintf("v%d", this.index) 115} 116 117func (this *varGen) Current() string { 118 return fmt.Sprintf("v%d", this.index) 119} 120 121type plugin struct { 122 *generator.Generator 123 generator.PluginImports 124 varGen VarGen 125 atleastOne bool 126 localName string 127 typesPkg generator.Single 128} 129 130func NewPlugin() *plugin { 131 return &plugin{} 132} 133 134func (p *plugin) Name() string { 135 return "populate" 136} 137 138func (p *plugin) Init(g *generator.Generator) { 139 p.Generator = g 140} 141 142func value(typeName string, fieldType descriptor.FieldDescriptorProto_Type) string { 143 switch fieldType { 144 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 145 return typeName + "(r.Float64())" 146 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 147 return typeName + "(r.Float32())" 148 case descriptor.FieldDescriptorProto_TYPE_INT64, 149 descriptor.FieldDescriptorProto_TYPE_SFIXED64, 150 descriptor.FieldDescriptorProto_TYPE_SINT64: 151 return typeName + "(r.Int63())" 152 case descriptor.FieldDescriptorProto_TYPE_UINT64, 153 descriptor.FieldDescriptorProto_TYPE_FIXED64: 154 return typeName + "(uint64(r.Uint32()))" 155 case descriptor.FieldDescriptorProto_TYPE_INT32, 156 descriptor.FieldDescriptorProto_TYPE_SINT32, 157 descriptor.FieldDescriptorProto_TYPE_SFIXED32, 158 descriptor.FieldDescriptorProto_TYPE_ENUM: 159 return typeName + "(r.Int31())" 160 case descriptor.FieldDescriptorProto_TYPE_UINT32, 161 descriptor.FieldDescriptorProto_TYPE_FIXED32: 162 return typeName + "(r.Uint32())" 163 case descriptor.FieldDescriptorProto_TYPE_BOOL: 164 return typeName + `(bool(r.Intn(2) == 0))` 165 case descriptor.FieldDescriptorProto_TYPE_STRING, 166 descriptor.FieldDescriptorProto_TYPE_GROUP, 167 descriptor.FieldDescriptorProto_TYPE_MESSAGE, 168 descriptor.FieldDescriptorProto_TYPE_BYTES: 169 } 170 panic(fmt.Errorf("unexpected type %v", typeName)) 171} 172 173func negative(fieldType descriptor.FieldDescriptorProto_Type) bool { 174 switch fieldType { 175 case descriptor.FieldDescriptorProto_TYPE_UINT64, 176 descriptor.FieldDescriptorProto_TYPE_FIXED64, 177 descriptor.FieldDescriptorProto_TYPE_UINT32, 178 descriptor.FieldDescriptorProto_TYPE_FIXED32, 179 descriptor.FieldDescriptorProto_TYPE_BOOL: 180 return false 181 } 182 return true 183} 184 185func (p *plugin) getFuncName(goTypName string) string { 186 funcName := "NewPopulated" + goTypName 187 goTypNames := strings.Split(goTypName, ".") 188 if len(goTypNames) == 2 { 189 funcName = goTypNames[0] + ".NewPopulated" + goTypNames[1] 190 } else if len(goTypNames) != 1 { 191 panic(fmt.Errorf("unreachable: too many dots in %v", goTypName)) 192 } 193 switch funcName { 194 case "time.NewPopulatedTime": 195 funcName = p.typesPkg.Use() + ".NewPopulatedStdTime" 196 case "time.NewPopulatedDuration": 197 funcName = p.typesPkg.Use() + ".NewPopulatedStdDuration" 198 } 199 return funcName 200} 201 202func (p *plugin) getFuncCall(goTypName string) string { 203 funcName := p.getFuncName(goTypName) 204 funcCall := funcName + "(r, easy)" 205 return funcCall 206} 207 208func (p *plugin) getCustomFuncCall(goTypName string) string { 209 funcName := p.getFuncName(goTypName) 210 funcCall := funcName + "(r)" 211 return funcCall 212} 213 214func (p *plugin) getEnumVal(field *descriptor.FieldDescriptorProto, goTyp string) string { 215 enum := p.ObjectNamed(field.GetTypeName()).(*generator.EnumDescriptor) 216 l := len(enum.Value) 217 values := make([]string, l) 218 for i := range enum.Value { 219 values[i] = strconv.Itoa(int(*enum.Value[i].Number)) 220 } 221 arr := "[]int32{" + strings.Join(values, ",") + "}" 222 val := strings.Join([]string{generator.GoTypeToName(goTyp), `(`, arr, `[r.Intn(`, fmt.Sprintf("%d", l), `)])`}, "") 223 return val 224} 225 226func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) { 227 proto3 := gogoproto.IsProto3(file.FileDescriptorProto) 228 goTyp, _ := p.GoType(message, field) 229 fieldname := p.GetOneOfFieldName(message, field) 230 goTypName := generator.GoTypeToName(goTyp) 231 if p.IsMap(field) { 232 m := p.GoMapType(nil, field) 233 keygoTyp, _ := p.GoType(nil, m.KeyField) 234 keygoTyp = strings.Replace(keygoTyp, "*", "", 1) 235 keygoAliasTyp, _ := p.GoType(nil, m.KeyAliasField) 236 keygoAliasTyp = strings.Replace(keygoAliasTyp, "*", "", 1) 237 238 valuegoTyp, _ := p.GoType(nil, m.ValueField) 239 valuegoAliasTyp, _ := p.GoType(nil, m.ValueAliasField) 240 keytypName := generator.GoTypeToName(keygoTyp) 241 keygoAliasTyp = generator.GoTypeToName(keygoAliasTyp) 242 valuetypAliasName := generator.GoTypeToName(valuegoAliasTyp) 243 244 nullable, valuegoTyp, valuegoAliasTyp := generator.GoMapValueTypes(field, m.ValueField, valuegoTyp, valuegoAliasTyp) 245 246 p.P(p.varGen.Next(), ` := r.Intn(10)`) 247 p.P(`this.`, fieldname, ` = make(`, m.GoType, `)`) 248 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 249 p.In() 250 keyval := "" 251 if m.KeyField.IsString() { 252 keyval = fmt.Sprintf("randString%v(r)", p.localName) 253 } else { 254 keyval = value(keytypName, m.KeyField.GetType()) 255 } 256 if keygoAliasTyp != keygoTyp { 257 keyval = keygoAliasTyp + `(` + keyval + `)` 258 } 259 if m.ValueField.IsMessage() || p.IsGroup(field) || 260 (m.ValueField.IsBytes() && gogoproto.IsCustomType(field)) { 261 s := `this.` + fieldname + `[` + keyval + `] = ` 262 if gogoproto.IsStdTime(field) || gogoproto.IsStdDuration(field) { 263 valuegoTyp = valuegoAliasTyp 264 } 265 funcCall := p.getCustomFuncCall(goTypName) 266 if !gogoproto.IsCustomType(field) { 267 goTypName = generator.GoTypeToName(valuegoTyp) 268 funcCall = p.getFuncCall(goTypName) 269 } 270 if !nullable { 271 funcCall = `*` + funcCall 272 } 273 if valuegoTyp != valuegoAliasTyp { 274 funcCall = `(` + valuegoAliasTyp + `)(` + funcCall + `)` 275 } 276 s += funcCall 277 p.P(s) 278 } else if m.ValueField.IsEnum() { 279 s := `this.` + fieldname + `[` + keyval + `]` + ` = ` + p.getEnumVal(m.ValueField, valuegoTyp) 280 p.P(s) 281 } else if m.ValueField.IsBytes() { 282 count := p.varGen.Next() 283 p.P(count, ` := r.Intn(100)`) 284 p.P(p.varGen.Next(), ` := `, keyval) 285 p.P(`this.`, fieldname, `[`, p.varGen.Current(), `] = make(`, valuegoTyp, `, `, count, `)`) 286 p.P(`for i := 0; i < `, count, `; i++ {`) 287 p.In() 288 p.P(`this.`, fieldname, `[`, p.varGen.Current(), `][i] = byte(r.Intn(256))`) 289 p.Out() 290 p.P(`}`) 291 } else if m.ValueField.IsString() { 292 s := `this.` + fieldname + `[` + keyval + `]` + ` = ` + fmt.Sprintf("randString%v(r)", p.localName) 293 p.P(s) 294 } else { 295 p.P(p.varGen.Next(), ` := `, keyval) 296 p.P(`this.`, fieldname, `[`, p.varGen.Current(), `] = `, value(valuetypAliasName, m.ValueField.GetType())) 297 if negative(m.ValueField.GetType()) { 298 p.P(`if r.Intn(2) == 0 {`) 299 p.In() 300 p.P(`this.`, fieldname, `[`, p.varGen.Current(), `] *= -1`) 301 p.Out() 302 p.P(`}`) 303 } 304 } 305 p.Out() 306 p.P(`}`) 307 } else if gogoproto.IsCustomType(field) { 308 funcCall := p.getCustomFuncCall(goTypName) 309 if field.IsRepeated() { 310 p.P(p.varGen.Next(), ` := r.Intn(10)`) 311 p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) 312 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 313 p.In() 314 p.P(p.varGen.Next(), `:= `, funcCall) 315 p.P(`this.`, fieldname, `[i] = *`, p.varGen.Current()) 316 p.Out() 317 p.P(`}`) 318 } else if gogoproto.IsNullable(field) { 319 p.P(`this.`, fieldname, ` = `, funcCall) 320 } else { 321 p.P(p.varGen.Next(), `:= `, funcCall) 322 p.P(`this.`, fieldname, ` = *`, p.varGen.Current()) 323 } 324 } else if field.IsMessage() || p.IsGroup(field) { 325 funcCall := p.getFuncCall(goTypName) 326 if field.IsRepeated() { 327 p.P(p.varGen.Next(), ` := r.Intn(5)`) 328 p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) 329 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 330 p.In() 331 if gogoproto.IsNullable(field) { 332 p.P(`this.`, fieldname, `[i] = `, funcCall) 333 } else { 334 p.P(p.varGen.Next(), `:= `, funcCall) 335 p.P(`this.`, fieldname, `[i] = *`, p.varGen.Current()) 336 } 337 p.Out() 338 p.P(`}`) 339 } else { 340 if gogoproto.IsNullable(field) { 341 p.P(`this.`, fieldname, ` = `, funcCall) 342 } else { 343 p.P(p.varGen.Next(), `:= `, funcCall) 344 p.P(`this.`, fieldname, ` = *`, p.varGen.Current()) 345 } 346 } 347 } else { 348 if field.IsEnum() { 349 val := p.getEnumVal(field, goTyp) 350 if field.IsRepeated() { 351 p.P(p.varGen.Next(), ` := r.Intn(10)`) 352 p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) 353 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 354 p.In() 355 p.P(`this.`, fieldname, `[i] = `, val) 356 p.Out() 357 p.P(`}`) 358 } else if !gogoproto.IsNullable(field) || proto3 { 359 p.P(`this.`, fieldname, ` = `, val) 360 } else { 361 p.P(p.varGen.Next(), ` := `, val) 362 p.P(`this.`, fieldname, ` = &`, p.varGen.Current()) 363 } 364 } else if field.IsBytes() { 365 if field.IsRepeated() { 366 p.P(p.varGen.Next(), ` := r.Intn(10)`) 367 p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) 368 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 369 p.In() 370 p.P(p.varGen.Next(), ` := r.Intn(100)`) 371 p.P(`this.`, fieldname, `[i] = make([]byte,`, p.varGen.Current(), `)`) 372 p.P(`for j := 0; j < `, p.varGen.Current(), `; j++ {`) 373 p.In() 374 p.P(`this.`, fieldname, `[i][j] = byte(r.Intn(256))`) 375 p.Out() 376 p.P(`}`) 377 p.Out() 378 p.P(`}`) 379 } else { 380 p.P(p.varGen.Next(), ` := r.Intn(100)`) 381 p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) 382 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 383 p.In() 384 p.P(`this.`, fieldname, `[i] = byte(r.Intn(256))`) 385 p.Out() 386 p.P(`}`) 387 } 388 } else if field.IsString() { 389 typName := generator.GoTypeToName(goTyp) 390 val := fmt.Sprintf("%s(randString%v(r))", typName, p.localName) 391 if field.IsRepeated() { 392 p.P(p.varGen.Next(), ` := r.Intn(10)`) 393 p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) 394 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 395 p.In() 396 p.P(`this.`, fieldname, `[i] = `, val) 397 p.Out() 398 p.P(`}`) 399 } else if !gogoproto.IsNullable(field) || proto3 { 400 p.P(`this.`, fieldname, ` = `, val) 401 } else { 402 p.P(p.varGen.Next(), `:= `, val) 403 p.P(`this.`, fieldname, ` = &`, p.varGen.Current()) 404 } 405 } else { 406 typName := generator.GoTypeToName(goTyp) 407 if field.IsRepeated() { 408 p.P(p.varGen.Next(), ` := r.Intn(10)`) 409 p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`) 410 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 411 p.In() 412 p.P(`this.`, fieldname, `[i] = `, value(typName, field.GetType())) 413 if negative(field.GetType()) { 414 p.P(`if r.Intn(2) == 0 {`) 415 p.In() 416 p.P(`this.`, fieldname, `[i] *= -1`) 417 p.Out() 418 p.P(`}`) 419 } 420 p.Out() 421 p.P(`}`) 422 } else if !gogoproto.IsNullable(field) || proto3 { 423 p.P(`this.`, fieldname, ` = `, value(typName, field.GetType())) 424 if negative(field.GetType()) { 425 p.P(`if r.Intn(2) == 0 {`) 426 p.In() 427 p.P(`this.`, fieldname, ` *= -1`) 428 p.Out() 429 p.P(`}`) 430 } 431 } else { 432 p.P(p.varGen.Next(), ` := `, value(typName, field.GetType())) 433 if negative(field.GetType()) { 434 p.P(`if r.Intn(2) == 0 {`) 435 p.In() 436 p.P(p.varGen.Current(), ` *= -1`) 437 p.Out() 438 p.P(`}`) 439 } 440 p.P(`this.`, fieldname, ` = &`, p.varGen.Current()) 441 } 442 } 443 } 444} 445 446func (p *plugin) hasLoop(pkg string, field *descriptor.FieldDescriptorProto, visited []*generator.Descriptor, excludes []*generator.Descriptor) *generator.Descriptor { 447 if field.IsMessage() || p.IsGroup(field) || p.IsMap(field) { 448 var fieldMessage *generator.Descriptor 449 if p.IsMap(field) { 450 m := p.GoMapType(nil, field) 451 if !m.ValueField.IsMessage() { 452 return nil 453 } 454 fieldMessage = p.ObjectNamed(m.ValueField.GetTypeName()).(*generator.Descriptor) 455 } else { 456 fieldMessage = p.ObjectNamed(field.GetTypeName()).(*generator.Descriptor) 457 } 458 fieldTypeName := generator.CamelCaseSlice(fieldMessage.TypeName()) 459 for _, message := range visited { 460 messageTypeName := generator.CamelCaseSlice(message.TypeName()) 461 if fieldTypeName == messageTypeName { 462 for _, e := range excludes { 463 if fieldTypeName == generator.CamelCaseSlice(e.TypeName()) { 464 return nil 465 } 466 } 467 return fieldMessage 468 } 469 } 470 471 for _, f := range fieldMessage.Field { 472 if strings.HasPrefix(f.GetTypeName(), "."+pkg) { 473 visited = append(visited, fieldMessage) 474 loopTo := p.hasLoop(pkg, f, visited, excludes) 475 if loopTo != nil { 476 return loopTo 477 } 478 } 479 } 480 } 481 return nil 482} 483 484func (p *plugin) loops(pkg string, field *descriptor.FieldDescriptorProto, message *generator.Descriptor) int { 485 //fmt.Fprintf(os.Stderr, "loops %v %v\n", field.GetTypeName(), generator.CamelCaseSlice(message.TypeName())) 486 excludes := []*generator.Descriptor{} 487 loops := 0 488 for { 489 visited := []*generator.Descriptor{} 490 loopTo := p.hasLoop(pkg, field, visited, excludes) 491 if loopTo == nil { 492 break 493 } 494 //fmt.Fprintf(os.Stderr, "loopTo %v\n", generator.CamelCaseSlice(loopTo.TypeName())) 495 excludes = append(excludes, loopTo) 496 loops++ 497 } 498 return loops 499} 500 501func (p *plugin) Generate(file *generator.FileDescriptor) { 502 p.atleastOne = false 503 p.PluginImports = generator.NewPluginImports(p.Generator) 504 p.varGen = NewVarGen() 505 proto3 := gogoproto.IsProto3(file.FileDescriptorProto) 506 p.typesPkg = p.NewImport("github.com/gogo/protobuf/types") 507 p.localName = generator.FileName(file) 508 protoPkg := p.NewImport("github.com/gogo/protobuf/proto") 509 if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) { 510 protoPkg = p.NewImport("github.com/golang/protobuf/proto") 511 } 512 513 for _, message := range file.Messages() { 514 if !gogoproto.HasPopulate(file.FileDescriptorProto, message.DescriptorProto) { 515 continue 516 } 517 if message.DescriptorProto.GetOptions().GetMapEntry() { 518 continue 519 } 520 p.atleastOne = true 521 ccTypeName := generator.CamelCaseSlice(message.TypeName()) 522 loopLevels := make([]int, len(message.Field)) 523 maxLoopLevel := 0 524 for i, field := range message.Field { 525 loopLevels[i] = p.loops(file.GetPackage(), field, message) 526 if loopLevels[i] > maxLoopLevel { 527 maxLoopLevel = loopLevels[i] 528 } 529 } 530 ranTotal := 0 531 for i := range loopLevels { 532 ranTotal += int(math.Pow10(maxLoopLevel - loopLevels[i])) 533 } 534 p.P(`func NewPopulated`, ccTypeName, `(r randy`, p.localName, `, easy bool) *`, ccTypeName, ` {`) 535 p.In() 536 p.P(`this := &`, ccTypeName, `{}`) 537 if gogoproto.IsUnion(message.File().FileDescriptorProto, message.DescriptorProto) && len(message.Field) > 0 { 538 p.P(`fieldNum := r.Intn(`, fmt.Sprintf("%d", ranTotal), `)`) 539 p.P(`switch fieldNum {`) 540 k := 0 541 for i, field := range message.Field { 542 is := []string{} 543 ran := int(math.Pow10(maxLoopLevel - loopLevels[i])) 544 for j := 0; j < ran; j++ { 545 is = append(is, fmt.Sprintf("%d", j+k)) 546 } 547 k += ran 548 p.P(`case `, strings.Join(is, ","), `:`) 549 p.In() 550 p.GenerateField(file, message, field) 551 p.Out() 552 } 553 p.P(`}`) 554 } else { 555 var maxFieldNumber int32 556 oneofs := make(map[string]struct{}) 557 for fieldIndex, field := range message.Field { 558 if field.GetNumber() > maxFieldNumber { 559 maxFieldNumber = field.GetNumber() 560 } 561 oneof := field.OneofIndex != nil 562 if !oneof { 563 if field.IsRequired() || (!gogoproto.IsNullable(field) && !field.IsRepeated()) || (proto3 && !field.IsMessage()) { 564 p.GenerateField(file, message, field) 565 } else { 566 if loopLevels[fieldIndex] > 0 { 567 p.P(`if r.Intn(10) == 0 {`) 568 } else { 569 p.P(`if r.Intn(10) != 0 {`) 570 } 571 p.In() 572 p.GenerateField(file, message, field) 573 p.Out() 574 p.P(`}`) 575 } 576 } else { 577 fieldname := p.GetFieldName(message, field) 578 if _, ok := oneofs[fieldname]; ok { 579 continue 580 } else { 581 oneofs[fieldname] = struct{}{} 582 } 583 fieldNumbers := []int32{} 584 for _, f := range message.Field { 585 fname := p.GetFieldName(message, f) 586 if fname == fieldname { 587 fieldNumbers = append(fieldNumbers, f.GetNumber()) 588 } 589 } 590 591 p.P(`oneofNumber_`, fieldname, ` := `, fmt.Sprintf("%#v", fieldNumbers), `[r.Intn(`, strconv.Itoa(len(fieldNumbers)), `)]`) 592 p.P(`switch oneofNumber_`, fieldname, ` {`) 593 for _, f := range message.Field { 594 fname := p.GetFieldName(message, f) 595 if fname != fieldname { 596 continue 597 } 598 p.P(`case `, strconv.Itoa(int(f.GetNumber())), `:`) 599 p.In() 600 ccTypeName := p.OneOfTypeName(message, f) 601 p.P(`this.`, fname, ` = NewPopulated`, ccTypeName, `(r, easy)`) 602 p.Out() 603 } 604 p.P(`}`) 605 } 606 } 607 if message.DescriptorProto.HasExtension() { 608 p.P(`if !easy && r.Intn(10) != 0 {`) 609 p.In() 610 p.P(`l := r.Intn(5)`) 611 p.P(`for i := 0; i < l; i++ {`) 612 p.In() 613 if len(message.DescriptorProto.GetExtensionRange()) > 1 { 614 p.P(`eIndex := r.Intn(`, strconv.Itoa(len(message.DescriptorProto.GetExtensionRange())), `)`) 615 p.P(`fieldNumber := 0`) 616 p.P(`switch eIndex {`) 617 for i, e := range message.DescriptorProto.GetExtensionRange() { 618 p.P(`case `, strconv.Itoa(i), `:`) 619 p.In() 620 p.P(`fieldNumber = r.Intn(`, strconv.Itoa(int(e.GetEnd()-e.GetStart())), `) + `, strconv.Itoa(int(e.GetStart()))) 621 p.Out() 622 if e.GetEnd() > maxFieldNumber { 623 maxFieldNumber = e.GetEnd() 624 } 625 } 626 p.P(`}`) 627 } else { 628 e := message.DescriptorProto.GetExtensionRange()[0] 629 p.P(`fieldNumber := r.Intn(`, strconv.Itoa(int(e.GetEnd()-e.GetStart())), `) + `, strconv.Itoa(int(e.GetStart()))) 630 if e.GetEnd() > maxFieldNumber { 631 maxFieldNumber = e.GetEnd() 632 } 633 } 634 p.P(`wire := r.Intn(4)`) 635 p.P(`if wire == 3 { wire = 5 }`) 636 p.P(`dAtA := randField`, p.localName, `(nil, r, fieldNumber, wire)`) 637 p.P(protoPkg.Use(), `.SetRawExtension(this, int32(fieldNumber), dAtA)`) 638 p.Out() 639 p.P(`}`) 640 p.Out() 641 p.P(`}`) 642 } 643 644 if maxFieldNumber < (1 << 10) { 645 p.P(`if !easy && r.Intn(10) != 0 {`) 646 p.In() 647 if gogoproto.HasUnrecognized(file.FileDescriptorProto, message.DescriptorProto) { 648 p.P(`this.XXX_unrecognized = randUnrecognized`, p.localName, `(r, `, strconv.Itoa(int(maxFieldNumber+1)), `)`) 649 } 650 p.Out() 651 p.P(`}`) 652 } 653 } 654 p.P(`return this`) 655 p.Out() 656 p.P(`}`) 657 p.P(``) 658 659 //Generate NewPopulated functions for oneof fields 660 m := proto.Clone(message.DescriptorProto).(*descriptor.DescriptorProto) 661 for _, f := range m.Field { 662 oneof := f.OneofIndex != nil 663 if !oneof { 664 continue 665 } 666 ccTypeName := p.OneOfTypeName(message, f) 667 p.P(`func NewPopulated`, ccTypeName, `(r randy`, p.localName, `, easy bool) *`, ccTypeName, ` {`) 668 p.In() 669 p.P(`this := &`, ccTypeName, `{}`) 670 vanity.TurnOffNullableForNativeTypes(f) 671 p.GenerateField(file, message, f) 672 p.P(`return this`) 673 p.Out() 674 p.P(`}`) 675 } 676 } 677 678 if !p.atleastOne { 679 return 680 } 681 682 p.P(`type randy`, p.localName, ` interface {`) 683 p.In() 684 p.P(`Float32() float32`) 685 p.P(`Float64() float64`) 686 p.P(`Int63() int64`) 687 p.P(`Int31() int32`) 688 p.P(`Uint32() uint32`) 689 p.P(`Intn(n int) int`) 690 p.Out() 691 p.P(`}`) 692 693 p.P(`func randUTF8Rune`, p.localName, `(r randy`, p.localName, `) rune {`) 694 p.In() 695 p.P(`ru := r.Intn(62)`) 696 p.P(`if ru < 10 {`) 697 p.In() 698 p.P(`return rune(ru+48)`) 699 p.Out() 700 p.P(`} else if ru < 36 {`) 701 p.In() 702 p.P(`return rune(ru+55)`) 703 p.Out() 704 p.P(`}`) 705 p.P(`return rune(ru+61)`) 706 p.Out() 707 p.P(`}`) 708 709 p.P(`func randString`, p.localName, `(r randy`, p.localName, `) string {`) 710 p.In() 711 p.P(p.varGen.Next(), ` := r.Intn(100)`) 712 p.P(`tmps := make([]rune, `, p.varGen.Current(), `)`) 713 p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`) 714 p.In() 715 p.P(`tmps[i] = randUTF8Rune`, p.localName, `(r)`) 716 p.Out() 717 p.P(`}`) 718 p.P(`return string(tmps)`) 719 p.Out() 720 p.P(`}`) 721 722 p.P(`func randUnrecognized`, p.localName, `(r randy`, p.localName, `, maxFieldNumber int) (dAtA []byte) {`) 723 p.In() 724 p.P(`l := r.Intn(5)`) 725 p.P(`for i := 0; i < l; i++ {`) 726 p.In() 727 p.P(`wire := r.Intn(4)`) 728 p.P(`if wire == 3 { wire = 5 }`) 729 p.P(`fieldNumber := maxFieldNumber + r.Intn(100)`) 730 p.P(`dAtA = randField`, p.localName, `(dAtA, r, fieldNumber, wire)`) 731 p.Out() 732 p.P(`}`) 733 p.P(`return dAtA`) 734 p.Out() 735 p.P(`}`) 736 737 p.P(`func randField`, p.localName, `(dAtA []byte, r randy`, p.localName, `, fieldNumber int, wire int) []byte {`) 738 p.In() 739 p.P(`key := uint32(fieldNumber)<<3 | uint32(wire)`) 740 p.P(`switch wire {`) 741 p.P(`case 0:`) 742 p.In() 743 p.P(`dAtA = encodeVarintPopulate`, p.localName, `(dAtA, uint64(key))`) 744 p.P(p.varGen.Next(), ` := r.Int63()`) 745 p.P(`if r.Intn(2) == 0 {`) 746 p.In() 747 p.P(p.varGen.Current(), ` *= -1`) 748 p.Out() 749 p.P(`}`) 750 p.P(`dAtA = encodeVarintPopulate`, p.localName, `(dAtA, uint64(`, p.varGen.Current(), `))`) 751 p.Out() 752 p.P(`case 1:`) 753 p.In() 754 p.P(`dAtA = encodeVarintPopulate`, p.localName, `(dAtA, uint64(key))`) 755 p.P(`dAtA = append(dAtA, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)))`) 756 p.Out() 757 p.P(`case 2:`) 758 p.In() 759 p.P(`dAtA = encodeVarintPopulate`, p.localName, `(dAtA, uint64(key))`) 760 p.P(`ll := r.Intn(100)`) 761 p.P(`dAtA = encodeVarintPopulate`, p.localName, `(dAtA, uint64(ll))`) 762 p.P(`for j := 0; j < ll; j++ {`) 763 p.In() 764 p.P(`dAtA = append(dAtA, byte(r.Intn(256)))`) 765 p.Out() 766 p.P(`}`) 767 p.Out() 768 p.P(`default:`) 769 p.In() 770 p.P(`dAtA = encodeVarintPopulate`, p.localName, `(dAtA, uint64(key))`) 771 p.P(`dAtA = append(dAtA, byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)), byte(r.Intn(256)))`) 772 p.Out() 773 p.P(`}`) 774 p.P(`return dAtA`) 775 p.Out() 776 p.P(`}`) 777 778 p.P(`func encodeVarintPopulate`, p.localName, `(dAtA []byte, v uint64) []byte {`) 779 p.In() 780 p.P(`for v >= 1<<7 {`) 781 p.In() 782 p.P(`dAtA = append(dAtA, uint8(uint64(v)&0x7f|0x80))`) 783 p.P(`v >>= 7`) 784 p.Out() 785 p.P(`}`) 786 p.P(`dAtA = append(dAtA, uint8(v))`) 787 p.P(`return dAtA`) 788 p.Out() 789 p.P(`}`) 790 791} 792 793func init() { 794 generator.RegisterPlugin(NewPlugin()) 795} 796