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