1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
205 package testgen
206
207 import (
208 "github.com/gogo/protobuf/gogoproto"
209 "github.com/gogo/protobuf/protoc-gen-gogo/generator"
210 )
211
212 type TestPlugin interface {
213 Generate(imports generator.PluginImports, file *generator.FileDescriptor) (used bool)
214 }
215
216 type NewTestPlugin func(g *generator.Generator) TestPlugin
217
218 var testplugins = make([]NewTestPlugin, 0)
219
220 func RegisterTestPlugin(newFunc NewTestPlugin) {
221 testplugins = append(testplugins, newFunc)
222 }
223
224 type plugin struct {
225 *generator.Generator
226 generator.PluginImports
227 tests []TestPlugin
228 }
229
230 func NewPlugin() *plugin {
231 return &plugin{}
232 }
233
234 func (p *plugin) Name() string {
235 return "testgen"
236 }
237
238 func (p *plugin) Init(g *generator.Generator) {
239 p.Generator = g
240 p.tests = make([]TestPlugin, 0, len(testplugins))
241 for i := range testplugins {
242 p.tests = append(p.tests, testplugins[i](g))
243 }
244 }
245
246 func (p *plugin) Generate(file *generator.FileDescriptor) {
247 p.PluginImports = generator.NewPluginImports(p.Generator)
248 atLeastOne := false
249 for i := range p.tests {
250 used := p.tests[i].Generate(p.PluginImports, file)
251 if used {
252 atLeastOne = true
253 }
254 }
255 if atLeastOne {
256 p.P(`//These tests are generated by github.com/gogo/protobuf/plugin/testgen`)
257 }
258 }
259
260 type testProto struct {
261 *generator.Generator
262 }
263
264 func newProto(g *generator.Generator) TestPlugin {
265 return &testProto{g}
266 }
267
268 func (p *testProto) Generate(imports generator.PluginImports, file *generator.FileDescriptor) bool {
269 used := false
270 testingPkg := imports.NewImport("testing")
271 randPkg := imports.NewImport("math/rand")
272 timePkg := imports.NewImport("time")
273 protoPkg := imports.NewImport("github.com/gogo/protobuf/proto")
274 if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
275 protoPkg = imports.NewImport("github.com/golang/protobuf/proto")
276 }
277 for _, message := range file.Messages() {
278 ccTypeName := generator.CamelCaseSlice(message.TypeName())
279 if message.DescriptorProto.GetOptions().GetMapEntry() {
280 continue
281 }
282 if gogoproto.HasTestGen(file.FileDescriptorProto, message.DescriptorProto) {
283 used = true
284
285 p.P(`func Test`, ccTypeName, `Proto(t *`, testingPkg.Use(), `.T) {`)
286 p.In()
287 p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
288 p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
289 p.P(`p := NewPopulated`, ccTypeName, `(popr, false)`)
290 p.P(`dAtA, err := `, protoPkg.Use(), `.Marshal(p)`)
291 p.P(`if err != nil {`)
292 p.In()
293 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
294 p.Out()
295 p.P(`}`)
296 p.P(`msg := &`, ccTypeName, `{}`)
297 p.P(`if err := `, protoPkg.Use(), `.Unmarshal(dAtA, msg); err != nil {`)
298 p.In()
299 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
300 p.Out()
301 p.P(`}`)
302 p.P(`littlefuzz := make([]byte, len(dAtA))`)
303 p.P(`copy(littlefuzz, dAtA)`)
304 p.P(`for i := range dAtA {`)
305 p.In()
306 p.P(`dAtA[i] = byte(popr.Intn(256))`)
307 p.Out()
308 p.P(`}`)
309 if gogoproto.HasVerboseEqual(file.FileDescriptorProto, message.DescriptorProto) {
310 p.P(`if err := p.VerboseEqual(msg); err != nil {`)
311 p.In()
312 p.P(`t.Fatalf("seed = %d, %#v !VerboseProto %#v, since %v", seed, msg, p, err)`)
313 p.Out()
314 p.P(`}`)
315 }
316 p.P(`if !p.Equal(msg) {`)
317 p.In()
318 p.P(`t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)`)
319 p.Out()
320 p.P(`}`)
321 p.P(`if len(littlefuzz) > 0 {`)
322 p.In()
323 p.P(`fuzzamount := 100`)
324 p.P(`for i := 0; i < fuzzamount; i++ {`)
325 p.In()
326 p.P(`littlefuzz[popr.Intn(len(littlefuzz))] = byte(popr.Intn(256))`)
327 p.P(`littlefuzz = append(littlefuzz, byte(popr.Intn(256)))`)
328 p.Out()
329 p.P(`}`)
330 p.P(`// shouldn't panic`)
331 p.P(`_ = `, protoPkg.Use(), `.Unmarshal(littlefuzz, msg)`)
332 p.Out()
333 p.P(`}`)
334 p.Out()
335 p.P(`}`)
336 p.P()
337 }
338
339 if gogoproto.HasTestGen(file.FileDescriptorProto, message.DescriptorProto) {
340 if gogoproto.IsMarshaler(file.FileDescriptorProto, message.DescriptorProto) || gogoproto.IsUnsafeMarshaler(file.FileDescriptorProto, message.DescriptorProto) {
341 p.P(`func Test`, ccTypeName, `MarshalTo(t *`, testingPkg.Use(), `.T) {`)
342 p.In()
343 p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
344 p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
345 p.P(`p := NewPopulated`, ccTypeName, `(popr, false)`)
346 if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) {
347 p.P(`size := p.ProtoSize()`)
348 } else {
349 p.P(`size := p.Size()`)
350 }
351 p.P(`dAtA := make([]byte, size)`)
352 p.P(`for i := range dAtA {`)
353 p.In()
354 p.P(`dAtA[i] = byte(popr.Intn(256))`)
355 p.Out()
356 p.P(`}`)
357 p.P(`_, err := p.MarshalTo(dAtA)`)
358 p.P(`if err != nil {`)
359 p.In()
360 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
361 p.Out()
362 p.P(`}`)
363 p.P(`msg := &`, ccTypeName, `{}`)
364 p.P(`if err := `, protoPkg.Use(), `.Unmarshal(dAtA, msg); err != nil {`)
365 p.In()
366 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
367 p.Out()
368 p.P(`}`)
369 p.P(`for i := range dAtA {`)
370 p.In()
371 p.P(`dAtA[i] = byte(popr.Intn(256))`)
372 p.Out()
373 p.P(`}`)
374 if gogoproto.HasVerboseEqual(file.FileDescriptorProto, message.DescriptorProto) {
375 p.P(`if err := p.VerboseEqual(msg); err != nil {`)
376 p.In()
377 p.P(`t.Fatalf("seed = %d, %#v !VerboseProto %#v, since %v", seed, msg, p, err)`)
378 p.Out()
379 p.P(`}`)
380 }
381 p.P(`if !p.Equal(msg) {`)
382 p.In()
383 p.P(`t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)`)
384 p.Out()
385 p.P(`}`)
386 p.Out()
387 p.P(`}`)
388 p.P()
389 }
390 }
391
392 if gogoproto.HasBenchGen(file.FileDescriptorProto, message.DescriptorProto) {
393 used = true
394 p.P(`func Benchmark`, ccTypeName, `ProtoMarshal(b *`, testingPkg.Use(), `.B) {`)
395 p.In()
396 p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(616))`)
397 p.P(`total := 0`)
398 p.P(`pops := make([]*`, ccTypeName, `, 10000)`)
399 p.P(`for i := 0; i < 10000; i++ {`)
400 p.In()
401 p.P(`pops[i] = NewPopulated`, ccTypeName, `(popr, false)`)
402 p.Out()
403 p.P(`}`)
404 p.P(`b.ResetTimer()`)
405 p.P(`for i := 0; i < b.N; i++ {`)
406 p.In()
407 p.P(`dAtA, err := `, protoPkg.Use(), `.Marshal(pops[i%10000])`)
408 p.P(`if err != nil {`)
409 p.In()
410 p.P(`panic(err)`)
411 p.Out()
412 p.P(`}`)
413 p.P(`total += len(dAtA)`)
414 p.Out()
415 p.P(`}`)
416 p.P(`b.SetBytes(int64(total / b.N))`)
417 p.Out()
418 p.P(`}`)
419 p.P()
420
421 p.P(`func Benchmark`, ccTypeName, `ProtoUnmarshal(b *`, testingPkg.Use(), `.B) {`)
422 p.In()
423 p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(616))`)
424 p.P(`total := 0`)
425 p.P(`datas := make([][]byte, 10000)`)
426 p.P(`for i := 0; i < 10000; i++ {`)
427 p.In()
428 p.P(`dAtA, err := `, protoPkg.Use(), `.Marshal(NewPopulated`, ccTypeName, `(popr, false))`)
429 p.P(`if err != nil {`)
430 p.In()
431 p.P(`panic(err)`)
432 p.Out()
433 p.P(`}`)
434 p.P(`datas[i] = dAtA`)
435 p.Out()
436 p.P(`}`)
437 p.P(`msg := &`, ccTypeName, `{}`)
438 p.P(`b.ResetTimer()`)
439 p.P(`for i := 0; i < b.N; i++ {`)
440 p.In()
441 p.P(`total += len(datas[i%10000])`)
442 p.P(`if err := `, protoPkg.Use(), `.Unmarshal(datas[i%10000], msg); err != nil {`)
443 p.In()
444 p.P(`panic(err)`)
445 p.Out()
446 p.P(`}`)
447 p.Out()
448 p.P(`}`)
449 p.P(`b.SetBytes(int64(total / b.N))`)
450 p.Out()
451 p.P(`}`)
452 p.P()
453 }
454 }
455 return used
456 }
457
458 type testJson struct {
459 *generator.Generator
460 }
461
462 func newJson(g *generator.Generator) TestPlugin {
463 return &testJson{g}
464 }
465
466 func (p *testJson) Generate(imports generator.PluginImports, file *generator.FileDescriptor) bool {
467 used := false
468 testingPkg := imports.NewImport("testing")
469 randPkg := imports.NewImport("math/rand")
470 timePkg := imports.NewImport("time")
471 jsonPkg := imports.NewImport("github.com/gogo/protobuf/jsonpb")
472 for _, message := range file.Messages() {
473 ccTypeName := generator.CamelCaseSlice(message.TypeName())
474 if message.DescriptorProto.GetOptions().GetMapEntry() {
475 continue
476 }
477 if gogoproto.HasTestGen(file.FileDescriptorProto, message.DescriptorProto) {
478 used = true
479 p.P(`func Test`, ccTypeName, `JSON(t *`, testingPkg.Use(), `.T) {`)
480 p.In()
481 p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
482 p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
483 p.P(`p := NewPopulated`, ccTypeName, `(popr, true)`)
484 p.P(`marshaler := `, jsonPkg.Use(), `.Marshaler{}`)
485 p.P(`jsondata, err := marshaler.MarshalToString(p)`)
486 p.P(`if err != nil {`)
487 p.In()
488 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
489 p.Out()
490 p.P(`}`)
491 p.P(`msg := &`, ccTypeName, `{}`)
492 p.P(`err = `, jsonPkg.Use(), `.UnmarshalString(jsondata, msg)`)
493 p.P(`if err != nil {`)
494 p.In()
495 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
496 p.Out()
497 p.P(`}`)
498 if gogoproto.HasVerboseEqual(file.FileDescriptorProto, message.DescriptorProto) {
499 p.P(`if err := p.VerboseEqual(msg); err != nil {`)
500 p.In()
501 p.P(`t.Fatalf("seed = %d, %#v !VerboseProto %#v, since %v", seed, msg, p, err)`)
502 p.Out()
503 p.P(`}`)
504 }
505 p.P(`if !p.Equal(msg) {`)
506 p.In()
507 p.P(`t.Fatalf("seed = %d, %#v !Json Equal %#v", seed, msg, p)`)
508 p.Out()
509 p.P(`}`)
510 p.Out()
511 p.P(`}`)
512 }
513 }
514 return used
515 }
516
517 type testText struct {
518 *generator.Generator
519 }
520
521 func newText(g *generator.Generator) TestPlugin {
522 return &testText{g}
523 }
524
525 func (p *testText) Generate(imports generator.PluginImports, file *generator.FileDescriptor) bool {
526 used := false
527 testingPkg := imports.NewImport("testing")
528 randPkg := imports.NewImport("math/rand")
529 timePkg := imports.NewImport("time")
530 protoPkg := imports.NewImport("github.com/gogo/protobuf/proto")
531 if !gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
532 protoPkg = imports.NewImport("github.com/golang/protobuf/proto")
533 }
534
535 for _, message := range file.Messages() {
536 ccTypeName := generator.CamelCaseSlice(message.TypeName())
537 if message.DescriptorProto.GetOptions().GetMapEntry() {
538 continue
539 }
540 if gogoproto.HasTestGen(file.FileDescriptorProto, message.DescriptorProto) {
541 used = true
542
543 p.P(`func Test`, ccTypeName, `ProtoText(t *`, testingPkg.Use(), `.T) {`)
544 p.In()
545 p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
546 p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
547 p.P(`p := NewPopulated`, ccTypeName, `(popr, true)`)
548 p.P(`dAtA := `, protoPkg.Use(), `.MarshalTextString(p)`)
549 p.P(`msg := &`, ccTypeName, `{}`)
550 p.P(`if err := `, protoPkg.Use(), `.UnmarshalText(dAtA, msg); err != nil {`)
551 p.In()
552 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
553 p.Out()
554 p.P(`}`)
555 if gogoproto.HasVerboseEqual(file.FileDescriptorProto, message.DescriptorProto) {
556 p.P(`if err := p.VerboseEqual(msg); err != nil {`)
557 p.In()
558 p.P(`t.Fatalf("seed = %d, %#v !VerboseProto %#v, since %v", seed, msg, p, err)`)
559 p.Out()
560 p.P(`}`)
561 }
562 p.P(`if !p.Equal(msg) {`)
563 p.In()
564 p.P(`t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)`)
565 p.Out()
566 p.P(`}`)
567 p.Out()
568 p.P(`}`)
569 p.P()
570
571 p.P(`func Test`, ccTypeName, `ProtoCompactText(t *`, testingPkg.Use(), `.T) {`)
572 p.In()
573 p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
574 p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
575 p.P(`p := NewPopulated`, ccTypeName, `(popr, true)`)
576 p.P(`dAtA := `, protoPkg.Use(), `.CompactTextString(p)`)
577 p.P(`msg := &`, ccTypeName, `{}`)
578 p.P(`if err := `, protoPkg.Use(), `.UnmarshalText(dAtA, msg); err != nil {`)
579 p.In()
580 p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
581 p.Out()
582 p.P(`}`)
583 if gogoproto.HasVerboseEqual(file.FileDescriptorProto, message.DescriptorProto) {
584 p.P(`if err := p.VerboseEqual(msg); err != nil {`)
585 p.In()
586 p.P(`t.Fatalf("seed = %d, %#v !VerboseProto %#v, since %v", seed, msg, p, err)`)
587 p.Out()
588 p.P(`}`)
589 }
590 p.P(`if !p.Equal(msg) {`)
591 p.In()
592 p.P(`t.Fatalf("seed = %d, %#v !Proto %#v", seed, msg, p)`)
593 p.Out()
594 p.P(`}`)
595 p.Out()
596 p.P(`}`)
597 p.P()
598
599 }
600 }
601 return used
602 }
603
604 func init() {
605 RegisterTestPlugin(newProto)
606 RegisterTestPlugin(newJson)
607 RegisterTestPlugin(newText)
608 }
609
View as plain text