1package e2e_test 2 3import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "regexp" 9 "strings" 10 "testing" 11 12 "github.com/fatih/color" 13 "github.com/google/go-cmp/cmp" 14 "github.com/ktr0731/evans/app" 15 "github.com/ktr0731/evans/cui" 16 "github.com/ktr0731/evans/meta" 17 "github.com/ktr0731/evans/mode" 18 "github.com/ktr0731/evans/usecase" 19 "github.com/pkg/errors" 20) 21 22var replacer = regexp.MustCompile(`access-control-expose-headers: .*\n`) 23 24func TestE2E_CLI(t *testing.T) { 25 commonFlags := []string{"--verbose"} 26 27 cases := map[string]struct { 28 // Common flags all sub-commands can have. 29 commonFlags string 30 cmd string 31 // Space separated arguments text. 32 args string 33 34 // The server enables TLS. 35 tls bool 36 37 // The server enables gRPC reflection. 38 reflection bool 39 40 // The server uses gRPC-Web protocol. 41 web bool 42 43 // Register a service that has no package. 44 registerEmptyPackageService bool 45 46 // beforeTest set up a testcase specific environment. 47 // If beforeTest is nil, it is ignored. 48 // beforeTest may return a function named afterTest that cleans up 49 // the environment. If afterTest is nil, it is ignored. 50 beforeTest func(t *testing.T) (afterTest func(t *testing.T)) 51 52 // assertTest checks whether the output is expected. 53 // If nil, it will be ignored. 54 assertTest func(t *testing.T, output string) 55 56 // The output we expected. It is ignored if expectedCode isn't 0. 57 expectedOut string 58 // assertWithGolden asserts the output with the golden file. 59 assertWithGolden bool 60 61 // The exit code we expected. 62 expectedCode int 63 64 // Each output is formatted by flatten() for remove break lines. 65 // But, if it is prefer to show as it is, you can it by specifying 66 // unflatten to true. 67 unflatten bool 68 69 deprecatedUsage bool 70 }{ 71 "print usage text to the Writer (common flag)": { 72 commonFlags: "--help", 73 assertWithGolden: true, 74 unflatten: true, 75 }, 76 "print usage text to the Writer": { 77 args: "--help", 78 assertWithGolden: true, 79 unflatten: true, 80 }, 81 "print version text to the Writer (common flag)": { 82 commonFlags: "--version", 83 expectedOut: fmt.Sprintf("evans %s\n", meta.Version), 84 unflatten: true, 85 }, 86 "print version text to the Writer": { 87 args: "--version", 88 expectedOut: fmt.Sprintf("evans %s\n", meta.Version), 89 unflatten: true, 90 }, 91 "cannot specify both of --cli and --repl": { 92 args: "--cli --repl", 93 expectedCode: 1, 94 }, 95 "cannot specify both of --tls and --web": { 96 args: "--web --tls testdata/test.proto", 97 expectedCode: 1, 98 }, 99 "cannot launch without proto files and reflection": { 100 args: "", 101 expectedCode: 1, 102 }, 103 104 // call command 105 106 "print call command usage": { 107 commonFlags: "", 108 cmd: "call", 109 args: "-h", 110 assertWithGolden: true, 111 }, 112 "cannot launch CLI mode because proto files didn't be passed": { 113 cmd: "call", 114 args: "--file testdata/unary_call.in api.Example.Unary", 115 expectedCode: 1, 116 }, 117 "cannot launch CLI mode because package name is invalid value": { 118 commonFlags: "--proto testdata/test.proto", 119 cmd: "call", 120 args: "--file testdata/unary_call.in foo.Example.Unary", 121 expectedCode: 1, 122 }, 123 "cannot launch CLI mode because service name is invalid value": { 124 commonFlags: "--proto testdata/test.proto", 125 cmd: "call", 126 args: "--file testdata/unary_call.in api.Foo.Unary", 127 expectedCode: 1, 128 }, 129 "cannot launch CLI mode because method name is missing": { 130 commonFlags: "--proto testdata/test.proto", 131 cmd: "call", 132 args: "--file testdata/unary_call.in api.Example", 133 expectedCode: 1, 134 }, 135 "cannot launch CLI mode because method name is invalid value": { 136 commonFlags: "--proto testdata/test.proto", 137 cmd: "call", 138 args: "--file testdata/unary_call.in api.Example.Foo", 139 expectedCode: 1, 140 }, 141 "cannot launch CLI mode because the path of --file is invalid path": { 142 commonFlags: "--proto testdata/test.proto", 143 cmd: "call", 144 args: "--file foo api.Example.Unary", 145 expectedCode: 1, 146 }, 147 "cannot launch CLI mode because the path of --file is invalid input": { 148 commonFlags: "--proto testdata/test.proto", 149 cmd: "call", 150 args: "--file testdata/invalid.in api.Example.Unary", 151 expectedCode: 1, 152 }, 153 "cannot launch CLI mode because --header didn't have value": { 154 commonFlags: "--header foo --proto testdata/test.proto", 155 cmd: "call", 156 args: "--file testdata/unary_call.in api.Example.Unary", 157 expectedCode: 1, 158 }, 159 "call unary RPC with an input file by CLI mode (backward-compatibility)": { 160 commonFlags: "--package api --service Example --proto testdata/test.proto", 161 cmd: "call", 162 args: "--file testdata/unary_call.in Unary", 163 deprecatedUsage: true, 164 expectedOut: `{ "message": "hello, oumae" }`, 165 }, 166 "call unary RPC with an input file by CLI mode": { 167 commonFlags: "--proto testdata/test.proto", 168 cmd: "call", 169 args: "--file testdata/unary_call.in api.Example.Unary", 170 expectedOut: `{ "message": "hello, oumae" }`, 171 }, 172 "call fully-qualified unary RPC with an input file by CLI mode": { 173 commonFlags: "--proto testdata/test.proto", 174 cmd: "call", 175 args: "--file testdata/unary_call.in api.Example.Unary", 176 expectedOut: `{ "message": "hello, oumae" }`, 177 }, 178 "call unary RPC with --call flag (backward-compatibility)": { 179 commonFlags: "--package api --service Example --proto testdata/test.proto", 180 cmd: "", 181 args: "--file testdata/unary_call.in --call Unary", 182 deprecatedUsage: true, 183 expectedOut: `{ "message": "hello, oumae" }`, 184 }, 185 "call unary RPC without package name because the size of packages is 1 (backward-compatibility)": { 186 commonFlags: "--service Example --proto testdata/test.proto", 187 cmd: "call", 188 args: "--file testdata/unary_call.in Unary", 189 deprecatedUsage: true, 190 expectedOut: `{ "message": "hello, oumae" }`, 191 }, 192 "call unary RPC without package and service name because the size of packages and services are 1": { 193 commonFlags: "--proto testdata/test.proto", 194 cmd: "call", 195 args: "--file testdata/unary_call.in Unary", 196 expectedOut: `{ "message": "hello, oumae" }`, 197 }, 198 "call unary RPC with an input reader by CLI mode": { 199 commonFlags: "--proto testdata/test.proto", 200 cmd: "call", 201 args: "api.Example.Unary", 202 beforeTest: func(t *testing.T) func(*testing.T) { 203 old := mode.DefaultCLIReader 204 mode.DefaultCLIReader = strings.NewReader(`{"name": "oumae"}`) 205 return func(t *testing.T) { 206 mode.DefaultCLIReader = old 207 } 208 }, 209 expectedOut: `{ "message": "hello, oumae" }`, 210 }, 211 "call client streaming RPC by CLI mode": { 212 commonFlags: "--proto testdata/test.proto", 213 cmd: "call", 214 args: "--file testdata/client_streaming.in api.Example.ClientStreaming", 215 expectedOut: `{ "message": "you sent requests 4 times (oumae, kousaka, kawashima, kato)." }`, 216 }, 217 "call server streaming RPC by CLI mode": { 218 commonFlags: "--proto testdata/test.proto", 219 cmd: "call", 220 args: "--file testdata/server_streaming.in api.Example.ServerStreaming", 221 expectedOut: `{ "message": "hello oumae, I greet 1 times." } { "message": "hello oumae, I greet 2 times." } { "message": "hello oumae, I greet 3 times." }`, 222 }, 223 "call bidi streaming RPC by CLI mode": { 224 commonFlags: "--proto testdata/test.proto", 225 cmd: "call", 226 args: "--file testdata/bidi_streaming.in api.Example.BidiStreaming", 227 assertTest: func(t *testing.T, output string) { 228 dec := json.NewDecoder(strings.NewReader(output)) 229 for { 230 var iface interface{} 231 err := dec.Decode(&iface) 232 if errors.Is(err, io.EOF) { 233 return 234 } 235 if err != nil { 236 t.Errorf("expected no errors, but got '%s'", err) 237 } 238 } 239 }, 240 }, 241 "call unary RPC with an input file and custom headers by CLI mode": { 242 commonFlags: "--header ogiso=setsuna --header touma=kazusa,youko --header sound=of=destiny --proto testdata/test.proto", 243 cmd: "call", 244 args: "--file testdata/unary_header.in api.Example.UnaryHeader", 245 assertTest: func(t *testing.T, output string) { 246 expectedStrings := []string{ 247 "key = ogiso", 248 "val = setsuna", 249 "key = touma", 250 "val = kazusa, youko", 251 "key = sound", 252 "val = of=destiny", 253 } 254 for _, s := range expectedStrings { 255 if !strings.Contains(output, s) { 256 t.Errorf("expected to contain '%s', but missing in '%s'", s, output) 257 } 258 } 259 }, 260 }, 261 262 // call command with reflection 263 264 "cannot launch CLI mode with reflection because method name is missing": { 265 commonFlags: "--reflection --proto testdata/test.proto", 266 cmd: "call", 267 args: "--file testdata/unary_call.in api.Example", 268 reflection: true, 269 expectedCode: 1, 270 }, 271 "cannot launch CLI mode with reflection because server didn't enable reflection": { 272 commonFlags: "--reflection", 273 cmd: "call", 274 args: "--file testdata/unary_call.in api.Example.Unary", 275 reflection: false, 276 expectedCode: 1, 277 }, 278 "call unary RPC by CLI mode with reflection with an input file (backward-compatibility)": { 279 commonFlags: "--reflection --package api --service Example", 280 cmd: "call", 281 args: "--file testdata/unary_call.in Unary", 282 reflection: true, 283 deprecatedUsage: true, 284 expectedOut: `{ "message": "hello, oumae" }`, 285 }, 286 "call unary RPC by CLI mode with reflection with an input file": { 287 commonFlags: "--reflection", 288 cmd: "call", 289 args: "--file testdata/unary_call.in api.Example.Unary", 290 reflection: true, 291 expectedOut: `{ "message": "hello, oumae" }`, 292 }, 293 294 // call command with TLS 295 296 "cannot launch CLI mode with TLS because the server didn't enable TLS": { 297 commonFlags: "--tls --proto testdata/test.proto", 298 cmd: "call", 299 args: "--file testdata/unary_call.in api.Example.Unary", 300 tls: false, 301 expectedCode: 1, 302 }, 303 "cannot launch CLI mode with TLS because the client didn't enable TLS": { 304 commonFlags: "--proto testdata/test.proto", 305 cmd: "call", 306 args: "--file testdata/unary_call.in api.Example.Unary", 307 tls: true, 308 expectedCode: 1, 309 }, 310 "cannot launch CLI mode with TLS because cannot validate certs for 127.0.0.1 (default value)": { 311 commonFlags: "--tls --proto testdata/test.proto", 312 cmd: "call", 313 args: "--file testdata/unary_call.in api.Example.Unary", 314 tls: true, 315 expectedCode: 1, 316 }, 317 "cannot launch CLI mode with TLS because signed authority is unknown": { 318 commonFlags: "--tls --host localhost --proto testdata/test.proto", 319 cmd: "call", 320 args: "--file testdata/unary_call.in api.Example.Unary", 321 tls: true, 322 expectedCode: 1, 323 }, 324 "call unary RPC with TLS by CLI mode": { 325 commonFlags: "--tls --host localhost --cacert testdata/rootCA.pem --proto testdata/test.proto", 326 cmd: "call", 327 args: "--file testdata/unary_call.in api.Example.Unary", 328 tls: true, 329 expectedOut: `{ "message": "hello, oumae" }`, 330 }, 331 "cannot launch CLI mode with TLS and reflection by CLI mode because server didn't enable TLS": { 332 commonFlags: "--tls -r --host localhost --cacert testdata/rootCA.pem", 333 cmd: "call", 334 args: "--file testdata/unary_call.in api.Example.Unary", 335 tls: false, 336 reflection: true, 337 expectedCode: 1, 338 }, 339 "call unary RPC with TLS and reflection by CLI mode": { 340 commonFlags: "--tls -r --host localhost --cacert testdata/rootCA.pem", 341 cmd: "call", 342 args: "--file testdata/unary_call.in api.Example.Unary", 343 tls: true, 344 reflection: true, 345 expectedOut: `{ "message": "hello, oumae" }`, 346 }, 347 "call unary RPC with TLS and --servername by CLI mode": { 348 commonFlags: "--tls --servername localhost --cacert testdata/rootCA.pem --proto testdata/test.proto", 349 cmd: "call", 350 args: "--file testdata/unary_call.in api.Example.Unary", 351 tls: true, 352 expectedOut: `{ "message": "hello, oumae" }`, 353 }, 354 "cannot launch CLI mode with mutual TLS auth because --certkey is missing": { 355 commonFlags: "--tls --host localhost --cacert testdata/rootCA.pem --cert testdata/localhost.pem --proto testdata/test.proto", 356 cmd: "call", 357 args: "--file testdata/unary_call.in api.Example.Unary", 358 tls: true, 359 expectedCode: 1, 360 }, 361 "cannot launch CLI mode with mutual TLS auth because --cert is missing": { 362 commonFlags: "--tls --host localhost --cacert testdata/rootCA.pem --certkey testdata/localhost-key.pem --proto testdata/test.proto", 363 cmd: "call", 364 args: "--file testdata/unary_call.in api.Example.Unary", 365 tls: true, 366 expectedCode: 1, 367 }, 368 "call unary RPC with mutual TLS auth by CLI mode": { 369 commonFlags: "--tls --host localhost --cacert testdata/rootCA.pem --cert testdata/localhost.pem --certkey testdata/localhost-key.pem --proto testdata/test.proto", 370 cmd: "call", 371 args: "--file testdata/unary_call.in api.Example.Unary", 372 tls: true, 373 expectedOut: `{ "message": "hello, oumae" }`, 374 }, 375 376 // call command with gRPC-Web 377 378 "cannot send a request to gRPC-Web server because the server didn't enable gRPC-Web": { 379 commonFlags: "--web --proto testdata/test.proto", 380 cmd: "call", 381 args: "--file testdata/unary_call.in api.Example.Unary", 382 web: false, 383 expectedCode: 1, 384 }, 385 "call unary RPC with an input file by CLI mode against to gRPC-Web server": { 386 commonFlags: "--web --proto testdata/test.proto", 387 cmd: "call", 388 args: "--file testdata/unary_call.in api.Example.Unary", 389 web: true, 390 expectedOut: `{ "message": "hello, oumae" }`, 391 }, 392 "call unary RPC with an input file by CLI mode and reflection against to gRPC-Web server": { 393 commonFlags: "--web -r", 394 cmd: "call", 395 args: "--file testdata/unary_call.in api.Example.Unary", 396 web: true, 397 reflection: true, 398 expectedOut: `{ "message": "hello, oumae" }`, 399 }, 400 "call client streaming RPC by CLI mode against to gRPC-Web server": { 401 commonFlags: "--web --proto testdata/test.proto", 402 cmd: "call", 403 args: "--file testdata/client_streaming.in api.Example.ClientStreaming", 404 web: true, 405 expectedOut: `{ "message": "you sent requests 4 times (oumae, kousaka, kawashima, kato)." }`, 406 }, 407 "call server streaming RPC by CLI mode against to gRPC-Web server": { 408 commonFlags: "--web --proto testdata/test.proto", 409 cmd: "call", 410 args: "--file testdata/server_streaming.in api.Example.ServerStreaming", 411 web: true, 412 expectedOut: `{ "message": "hello oumae, I greet 1 times." } { "message": "hello oumae, I greet 2 times." } { "message": "hello oumae, I greet 3 times." }`, 413 }, 414 "call bidi streaming RPC by CLI mode against to gRPC-Web server": { 415 commonFlags: "--web --proto testdata/test.proto", 416 cmd: "call", 417 args: "--file testdata/bidi_streaming.in api.Example.BidiStreaming", 418 web: true, 419 assertTest: func(t *testing.T, output string) { 420 dec := json.NewDecoder(strings.NewReader(output)) 421 for { 422 var iface interface{} 423 err := dec.Decode(&iface) 424 if errors.Is(err, io.EOF) { 425 return 426 } 427 if err != nil { 428 t.Errorf("expected no errors, but got '%s'", err) 429 } 430 } 431 }, 432 }, 433 "call unary RPC with --enrich flag": { 434 commonFlags: "-r", 435 cmd: "call", 436 args: "--file testdata/unary_call.in --enrich api.Example.UnaryHeaderTrailer", 437 reflection: true, 438 unflatten: true, 439 assertWithGolden: true, 440 }, 441 "call unary RPC with --enrich flag and JSON format": { 442 commonFlags: "-r", 443 cmd: "call", 444 args: "--file testdata/unary_call.in --enrich --output json api.Example.UnaryHeaderTrailer", 445 reflection: true, 446 unflatten: true, 447 assertWithGolden: true, 448 }, 449 "call failure unary RPC with --enrich flag": { 450 commonFlags: "-r", 451 cmd: "call", 452 args: "--file testdata/unary_call.in --enrich api.Example.UnaryHeaderTrailerFailure", 453 reflection: true, 454 unflatten: true, 455 assertWithGolden: true, 456 expectedCode: 1, 457 }, 458 "call failure unary RPC with --enrich and JSON format": { 459 commonFlags: "-r", 460 cmd: "call", 461 args: "--file testdata/unary_call.in --enrich --output json api.Example.UnaryHeaderTrailerFailure", 462 reflection: true, 463 unflatten: true, 464 assertWithGolden: true, 465 expectedCode: 1, 466 }, 467 "call unary RPC with --enrich flag against to gRPC-Web server": { 468 commonFlags: "--web -r", 469 cmd: "call", 470 args: "--file testdata/unary_call.in --enrich api.Example.UnaryHeaderTrailer", 471 web: true, 472 reflection: true, 473 unflatten: true, 474 assertWithGolden: true, 475 }, 476 "call failure unary RPC with --enrich flag against to gRPC-Web server": { 477 commonFlags: "--web -r", 478 cmd: "call", 479 args: "--file testdata/unary_call.in --enrich api.Example.UnaryHeaderTrailerFailure", 480 web: true, 481 reflection: true, 482 unflatten: true, 483 assertWithGolden: true, 484 expectedCode: 1, 485 }, 486 487 // list command 488 "print list command usage": { 489 commonFlags: "", 490 cmd: "list", 491 args: "-h", 492 assertWithGolden: true, 493 }, 494 "list services without args": { 495 commonFlags: "--proto testdata/test.proto", 496 cmd: "list", 497 args: "", 498 expectedOut: `api.Example`, 499 }, 500 "list services without args and two protos": { 501 commonFlags: "--proto testdata/test.proto,testdata/empty_package.proto", 502 cmd: "list", 503 args: "", 504 expectedOut: `EmptyPackageService api.Example`, 505 }, 506 "list services with name format": { 507 commonFlags: "--proto testdata/test.proto", 508 cmd: "list", 509 args: "-o name", 510 expectedOut: `api.Example`, 511 }, 512 "list services with JSON format": { 513 commonFlags: "--proto testdata/test.proto", 514 cmd: "list", 515 args: "-o json", 516 expectedOut: `{ "services": [ { "name": "api.Example" } ] }`, 517 }, 518 "list methods with name format": { 519 commonFlags: "--proto testdata/test.proto", 520 cmd: "list", 521 args: "-o name api.Example", 522 assertWithGolden: true, 523 }, 524 "list methods with JSON format": { 525 commonFlags: "--proto testdata/test.proto", 526 cmd: "list", 527 args: "-o json api.Example", 528 assertWithGolden: true, 529 }, 530 "list methods that have empty name": { 531 commonFlags: "--proto testdata/empty_package.proto", 532 cmd: "list", 533 args: "EmptyPackageService", 534 expectedOut: `EmptyPackageService.Unary`, 535 }, 536 "list a method with name format": { 537 commonFlags: "--proto testdata/test.proto,testdata/empty_package.proto", 538 cmd: "list", 539 args: "-o name api.Example.Unary", 540 expectedOut: `api.Example.Unary`, 541 }, 542 "list a method with JSON format": { 543 commonFlags: "--proto testdata/test.proto", 544 cmd: "list", 545 args: "-o json api.Example.Unary", 546 expectedOut: `{ "name": "Unary", "fully_qualified_name": "api.Example.Unary", "request_type": "api.SimpleRequest", "response_type": "api.SimpleResponse" }`, 547 }, 548 "cannot list because of invalid package name": { 549 commonFlags: "--proto testdata/test.proto", 550 cmd: "list", 551 args: "Foo", 552 expectedCode: 1, 553 }, 554 "cannot list because of invalid service name": { 555 commonFlags: "--proto testdata/test.proto", 556 cmd: "list", 557 args: "api.Foo", 558 expectedCode: 1, 559 }, 560 "cannot list because of invalid method name": { 561 commonFlags: "--proto testdata/test.proto", 562 cmd: "list", 563 args: "api.Example.UnaryFoo", 564 expectedCode: 1, 565 }, 566 567 // desc command 568 569 "print desc command usage": { 570 commonFlags: "", 571 cmd: "desc", 572 args: "-h", 573 assertWithGolden: true, 574 }, 575 "describe all service descriptors": { 576 commonFlags: "--proto testdata/test.proto,testdata/empty_package.proto", 577 cmd: "desc", 578 args: "", 579 assertWithGolden: true, 580 }, 581 "describe a service descriptor": { 582 commonFlags: "--proto testdata/test.proto,testdata/empty_package.proto", 583 cmd: "desc", 584 args: "api.Example", 585 assertWithGolden: true, 586 }, 587 "describe a method descriptor": { 588 commonFlags: "--proto testdata/test.proto,testdata/empty_package.proto", 589 cmd: "desc", 590 args: "api.Example.Unary", 591 assertWithGolden: true, 592 }, 593 "describe a message descriptor": { 594 commonFlags: "--proto testdata/test.proto,testdata/empty_package.proto", 595 cmd: "desc", 596 args: "api.SimpleRequest", 597 assertWithGolden: true, 598 }, 599 "invalid symbol": { 600 commonFlags: "--proto testdata/test.proto,testdata/empty_package.proto", 601 cmd: "desc", 602 args: "api.Foo", 603 expectedCode: 1, 604 }, 605 } 606 for name, c := range cases { 607 c := c 608 t.Run(name, func(t *testing.T) { 609 defer usecase.Clear() 610 611 stopServer, port := startServer(t, c.tls, c.reflection, c.web, c.registerEmptyPackageService) 612 defer stopServer() 613 614 outBuf, eoutBuf := new(bytes.Buffer), new(bytes.Buffer) 615 cui := cui.New(cui.Writer(outBuf), cui.ErrWriter(eoutBuf)) 616 617 args := commonFlags 618 args = append([]string{"--port", port}, args...) 619 if c.commonFlags != "" { 620 args = append(args, strings.Split(c.commonFlags, " ")...) 621 } 622 args = append(args, "cli") 623 if c.cmd != "" { 624 args = append(args, c.cmd) 625 } 626 if c.args != "" { 627 args = append(args, strings.Split(c.args, " ")...) 628 } 629 630 if c.beforeTest != nil { 631 afterTest := c.beforeTest(t) 632 if afterTest != nil { 633 defer afterTest(t) 634 } 635 } 636 637 a := app.New(cui) 638 code := a.Run(args) 639 if code != c.expectedCode { 640 t.Errorf("unexpected code returned: expected = %d, actual = %d", c.expectedCode, code) 641 } 642 643 actual := outBuf.String() 644 if !c.unflatten { 645 actual = flatten(actual) 646 } 647 648 if c.expectedCode == 0 { 649 if c.expectedOut != "" && actual != c.expectedOut { 650 t.Errorf("unexpected output:\n%s", cmp.Diff(c.expectedOut, actual)) 651 } 652 eout := eoutBuf.String() 653 if c.deprecatedUsage { 654 // Trim "deprecated" message. 655 eout = strings.Replace(eout, color.YellowString("evans: deprecated usage, please use sub-commands. see `evans -h` for more details.")+"\n", "", -1) 656 } 657 if eout != "" { 658 t.Errorf("expected code is 0, but got an error message: '%s'", eoutBuf.String()) 659 } 660 } 661 if c.assertTest != nil { 662 c.assertTest(t, actual) 663 } 664 if c.assertWithGolden { 665 s := outBuf.String() 666 s = replacer.ReplaceAllString(s, "") 667 compareWithGolden(t, s) 668 } 669 }) 670 } 671} 672