github.com/dpifke/golang-fastmatch@v0.0.0-20170222002913-6bd661ebeb8c/generate_test.go (about) 1 // Copyright (c) 2014-2016 Dave Pifke. 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, is permitted provided that the following conditions are met: 5 // 6 // 1. Redistributions of source code must retain the above copyright notice, 7 // this list of conditions and the following disclaimer. 8 // 9 // 2. Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // 13 // 3. Neither the name of the copyright holder nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 // POSSIBILITY OF SUCH DAMAGE. 28 29 package fastmatch 30 31 import ( 32 "fmt" 33 "io" 34 "io/ioutil" 35 "os" 36 "os/exec" 37 "strings" 38 "testing" 39 ) 40 41 // testDirection is passed to generateRunnable to specify whether we should 42 // use Generate or GenerateReverse for a particular test. 43 type testDirection bool 44 45 const ( 46 match testDirection = true // use Generate 47 reverseMatch testDirection = false // use GenerateReverse 48 ) 49 50 // generateRunnable creates a temporary directory, adds it GOPATH, and uses 51 // Generate or GenerateReverse to create runnable string matcher code therein. 52 // 53 // GenerateTest is also run, to generate and run the automated self-test; 54 // failures are reported, however are non-fatal. 55 // 56 // A cleanup function is returned, which should be executed by the caller at 57 // the completion of the test. This removes the temporary directory and 58 // restores GOPATH and the current working directory. 59 func generateRunnable(t *testing.T, which testDirection, retType string, cases map[string]string, none string, flags ...*Flag) (func(), error) { 60 cleanup := func() {} 61 62 var out, testOut io.Writer 63 dir, err := ioutil.TempDir("", "fastmatch_test") 64 if err == nil { 65 savedWd, _ := os.Getwd() 66 err = os.Chdir(dir) 67 if err == nil { 68 savedGopath := os.Getenv("GOPATH") 69 os.Setenv("GOPATH", fmt.Sprintf("%s:%s", dir, savedGopath)) 70 cleanup = func() { 71 os.Setenv("GOPATH", savedGopath) 72 os.Chdir(savedWd) 73 os.RemoveAll(dir) 74 } 75 out, err = os.Create("generated.go") 76 if err == nil { 77 testOut, err = os.Create("generated_test.go") 78 } 79 } 80 } 81 if err != nil { 82 return cleanup, err 83 } 84 85 _, err = fmt.Fprintln(out, "package main") 86 if err != nil { 87 return cleanup, err 88 } 89 fmt.Fprintln(out) 90 fmt.Fprintln(out, "import (") 91 fmt.Fprintln(out, "\t\"fmt\"") 92 fmt.Fprintln(out, "\t\"os\"") 93 fmt.Fprintln(out, ")") 94 fmt.Fprintln(out) 95 96 fmt.Fprintln(out, "func match(input string)", retType, "{") 97 if which == match { 98 err = Generate(out, cases, none, flags...) 99 } else { 100 err = GenerateReverse(out, cases, none, flags...) 101 } 102 if err != nil { 103 return cleanup, err 104 } 105 fmt.Fprintln(out) 106 107 fmt.Fprintln(out, "func main() {") 108 fmt.Fprintln(out, "\tfmt.Println(match(os.Args[1]))") 109 _, err = fmt.Fprintln(out, "}") 110 111 // Also generate and run the self-test. Errors generating or running 112 // the automated tests are recorded, but are not fatal. 113 var fwd, rev string 114 if which == match { 115 fwd = "match(%q)" 116 rev = "" 117 } else { 118 fwd = "" 119 rev = "match(%s)" 120 } 121 _, testErr := fmt.Fprintln(testOut, "package main") 122 if testErr == nil { 123 fmt.Fprintln(testOut) 124 fmt.Fprintln(testOut, "import \"testing\"") 125 fmt.Fprintln(testOut) 126 fmt.Fprintln(testOut, "func TestMatch(t *testing.T) {") 127 testErr = GenerateTest(testOut, fwd, rev, cases, flags...) 128 } 129 if testErr == nil { 130 testResult, err := exec.Command("go", "test").CombinedOutput() 131 if err != nil { 132 t.Errorf("%s: %s", err.Error(), strings.TrimSpace(string(testResult))) 133 } 134 } else { 135 t.Errorf("failed to generate test: %s", testErr.Error()) 136 } 137 138 return cleanup, err 139 } 140 141 // expectMatch uses `go run` to execute our generated test.go file. It passes 142 // the provided input and compares the output to what the test expects. 143 func expectMatch(t *testing.T, input, expect string) { 144 cmd := exec.Command("go", "run", "generated.go", input) 145 out, err := cmd.CombinedOutput() 146 if err != nil { 147 t.Fatalf("%s: %s", err.Error(), strings.TrimSpace(string(out))) 148 } 149 150 outs := strings.TrimSpace(string(out)) 151 if outs != expect { 152 t.Errorf("expected %q, got %q for input %q", expect, outs, input) 153 } 154 } 155 156 // TestNoFlags tests a simple matcher. 157 func TestNoFlags(t *testing.T) { 158 if testing.Short() { 159 t.Skip("skipping compiled tests in short mode") 160 } 161 162 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 163 "foo": "1", 164 "bar": "2", 165 "baz": "3", 166 }, "0") 167 defer cleanup() 168 if err != nil { 169 t.Fatalf(err.Error()) 170 } 171 172 expectMatch(t, "foo", "1") 173 expectMatch(t, "bar", "2") 174 expectMatch(t, "baz", "3") 175 expectMatch(t, "bat", "0") 176 expectMatch(t, "bazz", "0") 177 } 178 179 // TestNoState tests matching a single string, no state machine required. 180 func TestNoState(t *testing.T) { 181 if testing.Short() { 182 t.Skip("skipping compiled tests in short mode") 183 } 184 185 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 186 "foo": "1", 187 }, "0") 188 defer cleanup() 189 if err != nil { 190 t.Fatalf(err.Error()) 191 } 192 193 expectMatch(t, "foo", "1") 194 } 195 196 // TestInsensitive tests a case-insensitive matcher. 197 func TestInsensitive(t *testing.T) { 198 if testing.Short() { 199 t.Skip("skipping compiled tests in short mode") 200 } 201 202 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 203 "foo": "1", 204 "Bar": "2", 205 "baz": "3", 206 }, "0", Insensitive) 207 defer cleanup() 208 if err != nil { 209 t.Fatalf(err.Error()) 210 } 211 212 expectMatch(t, "Foo", "1") 213 expectMatch(t, "BAR", "2") 214 expectMatch(t, "baz", "3") 215 expectMatch(t, "bat", "0") 216 } 217 218 // TestEquivalent tests a matcher which makes use of the Equivalent flag. 219 func TestEquivalent(t *testing.T) { 220 if testing.Short() { 221 t.Skip("skipping compiled tests in short mode") 222 } 223 224 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 225 "foo00000": "1", 226 "bar11111": "2", 227 }, "0", Equivalent('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')) 228 defer cleanup() 229 if err != nil { 230 t.Fatalf(err.Error()) 231 } 232 233 expectMatch(t, "foo90210", "1") 234 expectMatch(t, "foo11111", "1") 235 expectMatch(t, "bar00000", "2") 236 expectMatch(t, "bar12345", "2") 237 expectMatch(t, "fooabcde", "0") 238 expectMatch(t, "barzyxwv", "0") 239 } 240 241 // TestHasPrefix tests a prefix matcher. 242 func TestHasPrefix(t *testing.T) { 243 if testing.Short() { 244 t.Skip("skipping compiled tests in short mode") 245 } 246 247 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 248 "f": "1", 249 "Bar": "2", 250 "baz": "3", 251 }, "0", HasPrefix, Insensitive) 252 defer cleanup() 253 if err != nil { 254 t.Fatalf(err.Error()) 255 } 256 257 expectMatch(t, "f", "1") 258 expectMatch(t, "foo", "1") 259 expectMatch(t, "FOO", "1") 260 expectMatch(t, "bar", "2") 261 expectMatch(t, "bart", "2") 262 expectMatch(t, "bz", "0") 263 expectMatch(t, "bzz", "0") 264 } 265 266 // TestHasSuffix tests a suffix matcher. 267 func TestHasSuffix(t *testing.T) { 268 if testing.Short() { 269 t.Skip("skipping compiled tests in short mode") 270 } 271 272 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 273 "o": "1", 274 "ar": "2", 275 }, "0", HasSuffix, Insensitive) 276 defer cleanup() 277 if err != nil { 278 t.Fatalf(err.Error()) 279 } 280 281 expectMatch(t, "o", "1") 282 expectMatch(t, "flo", "1") 283 expectMatch(t, "FLO", "1") 284 expectMatch(t, "bao", "1") 285 expectMatch(t, "bar", "2") 286 expectMatch(t, "baz", "0") 287 } 288 289 // TestStopUpon tests a matcher that's been directed to stop when a certain 290 // rune is encountered. 291 func TestStopUpon(t *testing.T) { 292 if testing.Short() { 293 t.Skip("skipping compiled tests in short mode") 294 } 295 296 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 297 "foo": "1", 298 "bar": "2", 299 }, "0", StopUpon('.')) 300 defer cleanup() 301 if err != nil { 302 t.Fatalf(err.Error()) 303 } 304 305 expectMatch(t, "foo", "1") 306 expectMatch(t, "foo.", "1") 307 expectMatch(t, "foofoo", "0") 308 expectMatch(t, "bar.xyz", "2") 309 expectMatch(t, "baz", "0") 310 expectMatch(t, "b.az", "0") 311 } 312 313 // TestMultipleStopUpon tests that multiple StopUpon runes can be specified 314 // and all will be honored. 315 func TestMultipleStopUpon(t *testing.T) { 316 if testing.Short() { 317 t.Skip("skipping compiled tests in short mode") 318 } 319 320 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 321 "foo?bar": "1", 322 "bar!foo": "2", 323 }, "0", StopUpon('.', '!'), StopUpon('?')) 324 defer cleanup() 325 if err != nil { 326 t.Fatalf(err.Error()) 327 } 328 329 expectMatch(t, "foo", "1") 330 expectMatch(t, "foo.quix", "1") 331 expectMatch(t, "bar?!?", "2") 332 } 333 334 // TestPrefixStopUpon tests combining StopUpon and HasPrefix flags. This is 335 // basically the same as HasPrefix, except inputs are truncated if the stop 336 // rune is encountered. 337 func TestPrefixStopUpon(t *testing.T) { 338 if testing.Short() { 339 t.Skip("skipping compiled tests in short mode") 340 } 341 342 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 343 "foo": "1", 344 "b.ar": "2", 345 }, "0", HasPrefix, StopUpon('.')) 346 defer cleanup() 347 if err != nil { 348 t.Fatalf(err.Error()) 349 } 350 351 expectMatch(t, "foo", "1") 352 expectMatch(t, "foo.", "1") 353 expectMatch(t, "foofoo", "1") 354 expectMatch(t, "baz", "2") 355 expectMatch(t, "b.az", "2") 356 expectMatch(t, "quix", "0") 357 expectMatch(t, "q.uix", "0") 358 } 359 360 // TestSuffixStopUpon tests combining StopUpon and HasSuffix flags. 361 func TestSuffixStopUpon(t *testing.T) { 362 if testing.Short() { 363 t.Skip("skipping compiled tests in short mode") 364 } 365 366 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 367 ".foo": "1", 368 "bar": "2", 369 }, "0", HasSuffix, StopUpon('.')) 370 defer cleanup() 371 if err != nil { 372 t.Fatalf(err.Error()) 373 } 374 375 expectMatch(t, "foo", "1") 376 expectMatch(t, ".foo", "1") 377 expectMatch(t, "foofoo", "1") 378 expectMatch(t, "foo.bar", "2") 379 expectMatch(t, "bar", "2") 380 expectMatch(t, "barfar", "0") 381 expectMatch(t, ".", "0") 382 } 383 384 // TestStopUponEquivalent tests combining StopUpon and Equivalent flags. 385 func TestStopUponEquivalent(t *testing.T) { 386 if testing.Short() { 387 t.Skip("skipping compiled tests in short mode") 388 } 389 390 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 391 "foo!bar": "1", 392 "bar.foo": "2", 393 }, "0", StopUpon('.'), Equivalent('.', '!')) 394 defer cleanup() 395 if err != nil { 396 t.Fatalf(err.Error()) 397 } 398 399 expectMatch(t, "foo", "1") 400 expectMatch(t, "foo.", "1") 401 expectMatch(t, "foo!lala", "1") 402 expectMatch(t, "bar", "2") 403 expectMatch(t, "bar.", "2") 404 expectMatch(t, "bar!lala", "2") 405 expectMatch(t, "baz", "0") 406 } 407 408 // TestIgnore tests matching with ignored runes. 409 func TestIgnore(t *testing.T) { 410 if testing.Short() { 411 t.Skip("skipping compiled tests in short mode") 412 } 413 414 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 415 ".f.o.o.": "1", 416 "bar": "2", 417 }, "0", Ignore('.')) 418 defer cleanup() 419 if err != nil { 420 t.Fatalf(err.Error()) 421 } 422 423 expectMatch(t, "foo", "1") 424 expectMatch(t, "f....o...o", "1") 425 expectMatch(t, "...foo...", "1") 426 expectMatch(t, ".bar", "2") 427 expectMatch(t, "bar.", "2") 428 expectMatch(t, "bar.f", "0") 429 expectMatch(t, "...", "0") 430 } 431 432 // TestMultipleIgnore tests that multiple Ignore runes can be specified. 433 func TestMultipleIgnore(t *testing.T) { 434 if testing.Short() { 435 t.Skip("skipping compiled tests in short mode") 436 } 437 438 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 439 "foo?bar": "1", 440 "bar!foo": "2", 441 }, "0", Ignore('.', '!'), Ignore('?')) 442 defer cleanup() 443 if err != nil { 444 t.Fatalf(err.Error()) 445 } 446 447 expectMatch(t, "foo...bar", "1") 448 expectMatch(t, "bar?!foo", "2") 449 } 450 451 // TestPrefixIgnore tests combining Ignore and HasPrefix. 452 func TestPrefixIgnore(t *testing.T) { 453 if testing.Short() { 454 t.Skip("skipping compiled tests in short mode") 455 } 456 457 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 458 ".f.o.o.": "1", 459 "bar": "2", 460 }, "0", Ignore('.'), HasPrefix) 461 defer cleanup() 462 if err != nil { 463 t.Fatalf(err.Error()) 464 } 465 466 expectMatch(t, "foobar", "1") 467 expectMatch(t, "f....o...o....b....a.....r", "1") 468 expectMatch(t, "...bar", "2") 469 expectMatch(t, "f.a.r.", "0") 470 } 471 472 // TestSuffixIgnore tests combining Ignore and HasSuffix. 473 func TestSuffixIgnore(t *testing.T) { 474 if testing.Short() { 475 t.Skip("skipping compiled tests in short mode") 476 } 477 478 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 479 ".foo": "1", 480 "bar": "2", 481 }, "0", Ignore('.'), HasSuffix) 482 defer cleanup() 483 if err != nil { 484 t.Fatalf(err.Error()) 485 } 486 487 expectMatch(t, "barfoo", "1") 488 expectMatch(t, "bar.foo.", "1") 489 expectMatch(t, "z.z.z.b.a.r", "2") 490 expectMatch(t, "f.a.r.", "0") 491 } 492 493 // TestIgnoreEquivalent tests combining Ignore and Equivalent flags. 494 func TestIgnoreEquivalent(t *testing.T) { 495 if testing.Short() { 496 t.Skip("skipping compiled tests in short mode") 497 } 498 499 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 500 "foo-bar": "1", 501 "bar_foo": "2", 502 }, "0", Ignore('-'), Equivalent('-', '_')) 503 defer cleanup() 504 if err != nil { 505 t.Fatalf(err.Error()) 506 } 507 508 expectMatch(t, "foobar", "1") 509 expectMatch(t, "f-o-ob_a_r", "1") 510 expectMatch(t, "barfoo", "2") 511 expectMatch(t, "___barfoo---", "2") 512 expectMatch(t, "bar", "0") 513 } 514 515 // TestIgnoreExcept tests matching where all but a subset of runes are 516 // ignored. 517 func TestIgnoreExcept(t *testing.T) { 518 if testing.Short() { 519 t.Skip("skipping compiled tests in short mode") 520 } 521 522 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 523 "1x0x1x0x1": "1", 524 "zz00110zz": "2", 525 }, "0", IgnoreExcept('0', '1', '2')) 526 defer cleanup() 527 if err != nil { 528 t.Fatalf(err.Error()) 529 } 530 531 expectMatch(t, "10101", "1") 532 expectMatch(t, "foo10101", "1") 533 expectMatch(t, "10101foo", "1") 534 expectMatch(t, "00-11-0", "2") 535 expectMatch(t, "abcdef", "0") 536 expectMatch(t, "101011", "0") 537 } 538 539 // TestMultipleIgnoreExcept tests that multiple IgnoreExcept flags get 540 // combined properly. 541 func TestMultipleIgnoreExcept(t *testing.T) { 542 if testing.Short() { 543 t.Skip("skipping compiled tests in short mode") 544 } 545 546 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 547 "1x0x1x0x2": "1", 548 "zz22110zz": "2", 549 }, "0", IgnoreExcept('0', '1'), IgnoreExcept('2')) 550 defer cleanup() 551 if err != nil { 552 t.Fatalf(err.Error()) 553 } 554 555 expectMatch(t, "foo10102", "1") 556 expectMatch(t, "22110bar", "2") 557 } 558 559 // TestIgnoreExceptEquivalent tests that Equivalent applies transitively to 560 // IgnoreExcept. 561 func TestIgnoreExceptEquvialent(t *testing.T) { 562 if testing.Short() { 563 t.Skip("skipping compiled tests in short mode") 564 } 565 566 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 567 "0202": "1", 568 "1111": "2", 569 }, "0", IgnoreExcept('0', '3'), Equivalent('0', '1'), Equivalent('2', '3')) 570 defer cleanup() 571 if err != nil { 572 t.Fatalf(err.Error()) 573 } 574 575 expectMatch(t, "1313", "1") 576 expectMatch(t, "0000", "2") 577 } 578 579 // TestIgnoreExceptStopUpon tests combining IgnoreExcept and StopUpon. 580 func TestIgnoreExceptStopUpon(t *testing.T) { 581 if testing.Short() { 582 t.Skip("skipping compiled tests in short mode") 583 } 584 585 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 586 "abc123.321": "1", 587 "111def": "2", 588 }, "0", IgnoreExcept('1', '2', '3'), StopUpon('.')) 589 defer cleanup() 590 if err != nil { 591 t.Fatalf(err.Error()) 592 } 593 594 expectMatch(t, "123", "1") 595 expectMatch(t, "xxx111.bar", "2") 596 expectMatch(t, "123321", "0") 597 expectMatch(t, "1111", "0") 598 } 599 600 // TestPrefixIgnoreExcept tests combining IgnoreExcept and HasPrefix. 601 func TestPrefixIgnoreExcept(t *testing.T) { 602 if testing.Short() { 603 t.Skip("skipping compiled tests in short mode") 604 } 605 606 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 607 "123": "1", 608 "111": "2", 609 }, "0", IgnoreExcept('1', '2', '3'), HasPrefix) 610 defer cleanup() 611 if err != nil { 612 t.Fatalf(err.Error()) 613 } 614 615 expectMatch(t, "123321", "1") 616 expectMatch(t, "foo111", "2") 617 expectMatch(t, "222", "0") 618 } 619 620 // TestSuffixIgnoreExcept tests combining IgnoreExcept and HasSuffix. 621 func TestSuffixIgnoreExcept(t *testing.T) { 622 if testing.Short() { 623 t.Skip("skipping compiled tests in short mode") 624 } 625 626 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 627 "123": "1", 628 "111": "2", 629 }, "0", IgnoreExcept('1', '2', '3'), HasSuffix) 630 defer cleanup() 631 if err != nil { 632 t.Fatalf(err.Error()) 633 } 634 635 expectMatch(t, "321123", "1") 636 expectMatch(t, "foo111bar", "2") 637 expectMatch(t, "222", "0") 638 } 639 640 // TestChained tests chaining multiple state machines together, to match 641 // longer strings. 642 func TestChained(t *testing.T) { 643 if testing.Short() { 644 t.Skip("skipping compiled tests in short mode") 645 } 646 647 oldMaxState := maxState 648 defer func() { maxState = oldMaxState }() 649 maxState = 16 650 651 cleanup, err := generateRunnable(t, match, "int", map[string]string{ 652 "abcdef": "1", 653 "ghijkl": "2", 654 }, "0") 655 defer cleanup() 656 if err != nil { 657 t.Fatalf(err.Error()) 658 } 659 660 expectMatch(t, "abcdef", "1") 661 expectMatch(t, "ghijkl", "2") 662 expectMatch(t, "123456", "0") 663 } 664 665 // TestReverse tests a simple reverse matcher. 666 func TestReverse(t *testing.T) { 667 if testing.Short() { 668 t.Skip("skipping compiled tests in short mode") 669 } 670 671 cleanup, err := generateRunnable(t, reverseMatch, "string", map[string]string{ 672 "foo": `"1"`, 673 "bar": `"2"`, 674 }, `"baz"`) 675 defer cleanup() 676 if err != nil { 677 t.Fatalf(err.Error()) 678 } 679 680 expectMatch(t, "1", "foo") 681 expectMatch(t, "2", "bar") 682 expectMatch(t, "0", "baz") 683 } 684 685 // TestBadWriter tests that Generate and GenerateReverse return an error 686 // if passed an unusable io.Writer. 687 func TestBadWriter(t *testing.T) { 688 f, _ := ioutil.TempFile("", "fastmatch_test") 689 f.Close() 690 os.Remove(f.Name()) 691 692 if err := Generate(f, map[string]string{"a": "1"}, "0"); err == nil { 693 t.Errorf("no error from Generate on closed io.Writer") 694 } 695 if err := Generate(f, map[string]string{"a": "1"}, "0", HasPrefix); err == nil { 696 t.Errorf("no error from Generate (with HasPrefix) on closed io.Writer") 697 } 698 if err := GenerateReverse(f, map[string]string{"a": "1"}, `""`); err == nil { 699 t.Errorf("no error from GenerateReverse on closed io.Writer") 700 } 701 if err := GenerateTest(f, "Match", "", map[string]string{"a": "1"}); err == nil { 702 t.Errorf("no error from GenerateTest (forward matcher) on closed io.Writer") 703 } 704 if err := GenerateTest(f, "", "MatchReverse", map[string]string{"a": "1"}); err == nil { 705 t.Errorf("no error from GenerateTest (reverse matcher) on closed io.Writer") 706 } 707 }