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 testgen plugin generates Test and Benchmark functions for each message. 31 32Tests are enabled using the following extensions: 33 34 - testgen 35 - testgen_all 36 37Benchmarks are enabled using the following extensions: 38 39 - benchgen 40 - benchgen_all 41 42Let us look at: 43 44 github.com/gogo/protobuf/test/example/example.proto 45 46Btw all the output can be seen at: 47 48 github.com/gogo/protobuf/test/example/* 49 50The following message: 51 52 option (gogoproto.testgen_all) = true; 53 option (gogoproto.benchgen_all) = true; 54 55 message A { 56 optional string Description = 1 [(gogoproto.nullable) = false]; 57 optional int64 Number = 2 [(gogoproto.nullable) = false]; 58 optional bytes Id = 3 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uuid", (gogoproto.nullable) = false]; 59 } 60 61given to the testgen plugin, will generate the following test code: 62 63 func TestAProto(t *testing.T) { 64 popr := math_rand.New(math_rand.NewSource(time.Now().UnixNano())) 65 p := NewPopulatedA(popr, false) 66 dAtA, err := github_com_gogo_protobuf_proto.Marshal(p) 67 if err != nil { 68 panic(err) 69 } 70 msg := &A{} 71 if err := github_com_gogo_protobuf_proto.Unmarshal(dAtA, msg); err != nil { 72 panic(err) 73 } 74 for i := range dAtA { 75 dAtA[i] = byte(popr.Intn(256)) 76 } 77 if err := p.VerboseEqual(msg); err != nil { 78 t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err) 79 } 80 if !p.Equal(msg) { 81 t.Fatalf("%#v !Proto %#v", msg, p) 82 } 83 } 84 85 func BenchmarkAProtoMarshal(b *testing.B) { 86 popr := math_rand.New(math_rand.NewSource(616)) 87 total := 0 88 pops := make([]*A, 10000) 89 for i := 0; i < 10000; i++ { 90 pops[i] = NewPopulatedA(popr, false) 91 } 92 b.ResetTimer() 93 for i := 0; i < b.N; i++ { 94 dAtA, err := github_com_gogo_protobuf_proto.Marshal(pops[i%10000]) 95 if err != nil { 96 panic(err) 97 } 98 total += len(dAtA) 99 } 100 b.SetBytes(int64(total / b.N)) 101 } 102 103 func BenchmarkAProtoUnmarshal(b *testing.B) { 104 popr := math_rand.New(math_rand.NewSource(616)) 105 total := 0 106 datas := make([][]byte, 10000) 107 for i := 0; i < 10000; i++ { 108 dAtA, err := github_com_gogo_protobuf_proto.Marshal(NewPopulatedA(popr, false)) 109 if err != nil { 110 panic(err) 111 } 112 datas[i] = dAtA 113 } 114 msg := &A{} 115 b.ResetTimer() 116 for i := 0; i < b.N; i++ { 117 total += len(datas[i%10000]) 118 if err := github_com_gogo_protobuf_proto.Unmarshal(datas[i%10000], msg); err != nil { 119 panic(err) 120 } 121 } 122 b.SetBytes(int64(total / b.N)) 123 } 124 125 126 func TestAJSON(t *testing1.T) { 127 popr := math_rand1.New(math_rand1.NewSource(time1.Now().UnixNano())) 128 p := NewPopulatedA(popr, true) 129 jsondata, err := encoding_json.Marshal(p) 130 if err != nil { 131 panic(err) 132 } 133 msg := &A{} 134 err = encoding_json.Unmarshal(jsondata, msg) 135 if err != nil { 136 panic(err) 137 } 138 if err := p.VerboseEqual(msg); err != nil { 139 t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err) 140 } 141 if !p.Equal(msg) { 142 t.Fatalf("%#v !Json Equal %#v", msg, p) 143 } 144 } 145 146 func TestAProtoText(t *testing2.T) { 147 popr := math_rand2.New(math_rand2.NewSource(time2.Now().UnixNano())) 148 p := NewPopulatedA(popr, true) 149 dAtA := github_com_gogo_protobuf_proto1.MarshalTextString(p) 150 msg := &A{} 151 if err := github_com_gogo_protobuf_proto1.UnmarshalText(dAtA, msg); err != nil { 152 panic(err) 153 } 154 if err := p.VerboseEqual(msg); err != nil { 155 t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err) 156 } 157 if !p.Equal(msg) { 158 t.Fatalf("%#v !Proto %#v", msg, p) 159 } 160 } 161 162 func TestAProtoCompactText(t *testing2.T) { 163 popr := math_rand2.New(math_rand2.NewSource(time2.Now().UnixNano())) 164 p := NewPopulatedA(popr, true) 165 dAtA := github_com_gogo_protobuf_proto1.CompactTextString(p) 166 msg := &A{} 167 if err := github_com_gogo_protobuf_proto1.UnmarshalText(dAtA, msg); err != nil { 168 panic(err) 169 } 170 if err := p.VerboseEqual(msg); err != nil { 171 t.Fatalf("%#v !VerboseProto %#v, since %v", msg, p, err) 172 } 173 if !p.Equal(msg) { 174 t.Fatalf("%#v !Proto %#v", msg, p) 175 } 176 } 177 178Other registered tests are also generated. 179Tests are registered to this test plugin by calling the following function. 180 181 func RegisterTestPlugin(newFunc NewTestPlugin) 182 183where NewTestPlugin is: 184 185 type NewTestPlugin func(g *generator.Generator) TestPlugin 186 187and TestPlugin is an interface: 188 189 type TestPlugin interface { 190 Generate(imports generator.PluginImports, file *generator.FileDescriptor) (used bool) 191 } 192 193Plugins that use this interface include: 194 195 - populate 196 - gostring 197 - equal 198 - union 199 - and more 200 201Please look at these plugins as examples of how to create your own. 202A good idea is to let each plugin generate its own tests. 203 204*/ 205package testgen 206 207import ( 208 "github.com/gogo/protobuf/gogoproto" 209 "github.com/gogo/protobuf/protoc-gen-gogo/generator" 210) 211 212type TestPlugin interface { 213 Generate(imports generator.PluginImports, file *generator.FileDescriptor) (used bool) 214} 215 216type NewTestPlugin func(g *generator.Generator) TestPlugin 217 218var testplugins = make([]NewTestPlugin, 0) 219 220func RegisterTestPlugin(newFunc NewTestPlugin) { 221 testplugins = append(testplugins, newFunc) 222} 223 224type plugin struct { 225 *generator.Generator 226 generator.PluginImports 227 tests []TestPlugin 228} 229 230func NewPlugin() *plugin { 231 return &plugin{} 232} 233 234func (p *plugin) Name() string { 235 return "testgen" 236} 237 238func (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 246func (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 260type testProto struct { 261 *generator.Generator 262} 263 264func newProto(g *generator.Generator) TestPlugin { 265 return &testProto{g} 266} 267 268func (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 458type testJson struct { 459 *generator.Generator 460} 461 462func newJson(g *generator.Generator) TestPlugin { 463 return &testJson{g} 464} 465 466func (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 517type testText struct { 518 *generator.Generator 519} 520 521func newText(g *generator.Generator) TestPlugin { 522 return &testText{g} 523} 524 525func (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 //fmtPkg := imports.NewImport("fmt") 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 604func init() { 605 RegisterTestPlugin(newProto) 606 RegisterTestPlugin(newJson) 607 RegisterTestPlugin(newText) 608} 609