github.com/ledgerwatch/erigon-lib@v1.0.0/compress/decompress_test.go (about) 1 /* 2 Copyright 2021 Erigon contributors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package compress 18 19 import ( 20 "bytes" 21 "context" 22 "fmt" 23 "math/rand" 24 "os" 25 "path/filepath" 26 "strings" 27 "testing" 28 "time" 29 30 "github.com/ledgerwatch/log/v3" 31 "github.com/stretchr/testify/require" 32 ) 33 34 func prepareLoremDict(t *testing.T) *Decompressor { 35 t.Helper() 36 logger := log.New() 37 tmpDir := t.TempDir() 38 file := filepath.Join(tmpDir, "compressed") 39 t.Name() 40 c, err := NewCompressor(context.Background(), t.Name(), file, tmpDir, 1, 2, log.LvlDebug, logger) 41 if err != nil { 42 t.Fatal(err) 43 } 44 defer c.Close() 45 for k, w := range loremStrings { 46 if err = c.AddWord([]byte(fmt.Sprintf("%s %d", w, k))); err != nil { 47 t.Fatal(err) 48 } 49 } 50 if err = c.Compress(); err != nil { 51 t.Fatal(err) 52 } 53 var d *Decompressor 54 if d, err = NewDecompressor(file); err != nil { 55 t.Fatal(err) 56 } 57 return d 58 } 59 60 func TestDecompressSkip(t *testing.T) { 61 d := prepareLoremDict(t) 62 defer d.Close() 63 g := d.MakeGetter() 64 i := 0 65 for g.HasNext() { 66 w := loremStrings[i] 67 if i%2 == 0 { 68 g.Skip() 69 } else { 70 word, _ := g.Next(nil) 71 expected := fmt.Sprintf("%s %d", w, i) 72 if string(word) != expected { 73 t.Errorf("expected %s, got (hex) %s", expected, word) 74 } 75 } 76 i++ 77 } 78 } 79 80 func TestDecompressMatchOK(t *testing.T) { 81 d := prepareLoremDict(t) 82 defer d.Close() 83 g := d.MakeGetter() 84 i := 0 85 for g.HasNext() { 86 w := loremStrings[i] 87 if i%2 != 0 { 88 expected := fmt.Sprintf("%s %d", w, i) 89 ok, _ := g.Match([]byte(expected)) 90 if !ok { 91 t.Errorf("expexted match with %s", expected) 92 } 93 } else { 94 word, _ := g.Next(nil) 95 expected := fmt.Sprintf("%s %d", w, i) 96 if string(word) != expected { 97 t.Errorf("expected %s, got (hex) %s", expected, word) 98 } 99 } 100 i++ 101 } 102 } 103 104 func TestDecompressMatchCmpOK(t *testing.T) { 105 d := prepareLoremDict(t) 106 defer d.Close() 107 g := d.MakeGetter() 108 i := 0 109 for g.HasNext() { 110 w := loremStrings[i] 111 if i%2 != 0 { 112 expected := fmt.Sprintf("%s %d", w, i) 113 result := g.MatchCmp([]byte(expected)) 114 if result != 0 { 115 t.Errorf("expexted match with %s", expected) 116 } 117 } else { 118 word, _ := g.Next(nil) 119 expected := fmt.Sprintf("%s %d", w, i) 120 if string(word) != expected { 121 t.Errorf("expected %s, got (hex) %s", expected, word) 122 } 123 } 124 i++ 125 } 126 } 127 128 func prepareStupidDict(t *testing.T, size int) *Decompressor { 129 t.Helper() 130 logger := log.New() 131 tmpDir := t.TempDir() 132 file := filepath.Join(tmpDir, "compressed2") 133 t.Name() 134 c, err := NewCompressor(context.Background(), t.Name(), file, tmpDir, 1, 2, log.LvlDebug, logger) 135 if err != nil { 136 t.Fatal(err) 137 } 138 defer c.Close() 139 for i := 0; i < size; i++ { 140 if err = c.AddWord([]byte(fmt.Sprintf("word-%d", i))); err != nil { 141 t.Fatal(err) 142 } 143 } 144 if err = c.Compress(); err != nil { 145 t.Fatal(err) 146 } 147 var d *Decompressor 148 if d, err = NewDecompressor(file); err != nil { 149 t.Fatal(err) 150 } 151 return d 152 } 153 154 func TestDecompressMatchOKCondensed(t *testing.T) { 155 condensePatternTableBitThreshold = 4 156 d := prepareStupidDict(t, 10000) 157 defer func() { condensePatternTableBitThreshold = 9 }() 158 defer d.Close() 159 160 g := d.MakeGetter() 161 i := 0 162 for g.HasNext() { 163 if i%2 != 0 { 164 expected := fmt.Sprintf("word-%d", i) 165 ok, _ := g.Match([]byte(expected)) 166 if !ok { 167 t.Errorf("expexted match with %s", expected) 168 } 169 } else { 170 word, _ := g.Next(nil) 171 expected := fmt.Sprintf("word-%d", i) 172 if string(word) != expected { 173 t.Errorf("expected %s, got (hex) %s", expected, word) 174 } 175 } 176 i++ 177 } 178 } 179 180 func TestDecompressMatchNotOK(t *testing.T) { 181 d := prepareLoremDict(t) 182 defer d.Close() 183 g := d.MakeGetter() 184 i := 0 185 skipCount := 0 186 for g.HasNext() { 187 w := loremStrings[i] 188 expected := fmt.Sprintf("%s %d", w, i+1) 189 ok, _ := g.Match([]byte(expected)) 190 if ok { 191 t.Errorf("not expexted match with %s", expected) 192 } else { 193 g.Skip() 194 skipCount++ 195 } 196 i++ 197 } 198 if skipCount != i { 199 t.Errorf("something wrong with match logic") 200 } 201 } 202 203 func TestDecompressMatchPrefix(t *testing.T) { 204 d := prepareLoremDict(t) 205 defer d.Close() 206 g := d.MakeGetter() 207 i := 0 208 skipCount := 0 209 for g.HasNext() { 210 w := loremStrings[i] 211 expected := []byte(fmt.Sprintf("%s %d", w, i+1)) 212 expected = expected[:len(expected)/2] 213 if !g.MatchPrefix(expected) { 214 t.Errorf("expexted match with %s", expected) 215 } 216 g.Skip() 217 skipCount++ 218 i++ 219 } 220 if skipCount != i { 221 t.Errorf("something wrong with match logic") 222 } 223 g.Reset(0) 224 skipCount = 0 225 i = 0 226 for g.HasNext() { 227 w := loremStrings[i] 228 expected := []byte(fmt.Sprintf("%s %d", w, i+1)) 229 expected = expected[:len(expected)/2] 230 if len(expected) > 0 { 231 expected[len(expected)-1]++ 232 if g.MatchPrefix(expected) { 233 t.Errorf("not expexted match with %s", expected) 234 } 235 } 236 g.Skip() 237 skipCount++ 238 i++ 239 } 240 } 241 242 func TestDecompressMatchPrefixCmp(t *testing.T) { 243 d := prepareLoremDict(t) 244 defer d.Close() 245 g := d.MakeGetter() 246 i := 0 247 skipCount := 0 248 for g.HasNext() { 249 w := loremStrings[i] 250 expected := []byte(fmt.Sprintf("%s %d", w, i+1)) 251 expected = expected[:len(expected)/2] 252 cmp := g.MatchPrefixCmp(expected) 253 if cmp != 0 { 254 t.Errorf("expexted match with %s", expected) 255 } 256 g.Skip() 257 skipCount++ 258 i++ 259 } 260 if skipCount != i { 261 t.Errorf("something wrong with match logic") 262 } 263 g.Reset(0) 264 skipCount = 0 265 i = 0 266 for g.HasNext() { 267 w := loremStrings[i] 268 expected := []byte(fmt.Sprintf("%s %d", w, i+1)) 269 expected = expected[:len(expected)/2] 270 if len(expected) > 0 { 271 expected[len(expected)-1]++ 272 cmp := g.MatchPrefixCmp(expected) 273 if cmp == 0 { 274 t.Errorf("not expexted match with %s", expected) 275 } 276 } 277 g.Skip() 278 skipCount++ 279 i++ 280 } 281 } 282 283 func prepareLoremDictUncompressed(t *testing.T) *Decompressor { 284 t.Helper() 285 logger := log.New() 286 tmpDir := t.TempDir() 287 file := filepath.Join(tmpDir, "compressed") 288 t.Name() 289 c, err := NewCompressor(context.Background(), t.Name(), file, tmpDir, 1, 2, log.LvlDebug, logger) 290 if err != nil { 291 t.Fatal(err) 292 } 293 defer c.Close() 294 for k, w := range loremStrings { 295 if err = c.AddUncompressedWord([]byte(fmt.Sprintf("%s %d", w, k))); err != nil { 296 t.Fatal(err) 297 } 298 } 299 if err = c.Compress(); err != nil { 300 t.Fatal(err) 301 } 302 var d *Decompressor 303 if d, err = NewDecompressor(file); err != nil { 304 t.Fatal(err) 305 } 306 return d 307 } 308 309 func TestUncompressed(t *testing.T) { 310 d := prepareLoremDictUncompressed(t) 311 defer d.Close() 312 g := d.MakeGetter() 313 i := 0 314 for g.HasNext() { 315 w := loremStrings[i] 316 expected := []byte(fmt.Sprintf("%s %d", w, i+1)) 317 expected = expected[:len(expected)/2] 318 actual, _ := g.NextUncompressed() 319 if bytes.Equal(expected, actual) { 320 t.Errorf("expected %s, actual %s", expected, actual) 321 } 322 i++ 323 } 324 } 325 326 const lorem = `Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et 327 dolore magna aliqua Ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 328 consequat Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur 329 Excepteur sint occaecat cupidatat non proident sunt in culpa qui officia deserunt mollit anim id est laborum` 330 331 var loremStrings = strings.Split(lorem, " ") 332 333 func TestDecompressTorrent(t *testing.T) { 334 t.Skip() 335 336 fpath := "/mnt/data/chains/mainnet/snapshots/v1-014000-014500-transactions.seg" 337 st, err := os.Stat(fpath) 338 require.NoError(t, err) 339 fmt.Printf("file: %v, size: %d\n", st.Name(), st.Size()) 340 341 condensePatternTableBitThreshold = 9 342 fmt.Printf("bit threshold: %d\n", condensePatternTableBitThreshold) 343 d, err := NewDecompressor(fpath) 344 345 require.NoError(t, err) 346 defer d.Close() 347 348 getter := d.MakeGetter() 349 _ = getter 350 351 for getter.HasNext() { 352 _, sz := getter.Next(nil) 353 // fmt.Printf("%x\n", buf) 354 require.NotZero(t, sz) 355 } 356 } 357 358 const N = 100 359 360 var WORDS = [N][]byte{} 361 var WORD_FLAGS = [N]bool{} // false - uncompressed word, true - compressed word 362 var INPUT_FLAGS = []int{} // []byte or nil input 363 364 func randWord() []byte { 365 size := rand.Intn(256) // size of the word 366 word := make([]byte, size) 367 for i := 0; i < size; i++ { 368 word[i] = byte(rand.Intn(256)) 369 } 370 return word 371 } 372 373 func generateRandWords() { 374 for i := 0; i < N-2; i++ { 375 WORDS[i] = randWord() 376 } 377 // make sure we have at least 2 emtpy []byte 378 WORDS[N-2] = []byte{} 379 WORDS[N-1] = []byte{} 380 } 381 382 func randIntInRange(min, max int) int { 383 return (rand.Intn(max-min) + min) 384 } 385 386 func clearPrevDict() { 387 WORDS = [N][]byte{} 388 WORD_FLAGS = [N]bool{} 389 INPUT_FLAGS = []int{} 390 } 391 392 func prepareRandomDict(t *testing.T) *Decompressor { 393 t.Helper() 394 logger := log.New() 395 tmpDir := t.TempDir() 396 file := filepath.Join(tmpDir, "complex") 397 t.Name() 398 c, err := NewCompressor(context.Background(), t.Name(), file, tmpDir, 1, 2, log.LvlDebug, logger) 399 if err != nil { 400 t.Fatal(err) 401 } 402 // c.DisableFsync() 403 defer c.Close() 404 clearPrevDict() 405 rand.Seed(time.Now().UnixNano()) 406 generateRandWords() 407 408 idx := 0 409 for idx < N { 410 n := rand.Intn(2) 411 switch n { 412 case 0: // input case 413 word := WORDS[idx] 414 m := rand.Intn(2) 415 if m == 1 { 416 if err = c.AddWord(word); err != nil { 417 t.Fatal(err) 418 } 419 WORD_FLAGS[idx] = true 420 } else { 421 if err = c.AddUncompressedWord(word); err != nil { 422 t.Fatal(err) 423 } 424 } 425 idx++ 426 INPUT_FLAGS = append(INPUT_FLAGS, n) 427 case 1: // nil word 428 if err = c.AddWord(nil); err != nil { 429 t.Fatal(err) 430 } 431 INPUT_FLAGS = append(INPUT_FLAGS, n) 432 default: 433 t.Fatal(fmt.Errorf("case %d\n", n)) 434 } 435 } 436 437 if err = c.Compress(); err != nil { 438 t.Fatal(err) 439 } 440 var d *Decompressor 441 if d, err = NewDecompressor(file); err != nil { 442 t.Fatal(err) 443 } 444 return d 445 } 446 447 func TestDecompressRandomMatchCmp(t *testing.T) { 448 d := prepareRandomDict(t) 449 defer d.Close() 450 451 if d.wordsCount != uint64(len(INPUT_FLAGS)) { 452 t.Fatalf("TestDecompressRandomDict: d.wordsCount != len(INPUT_FLAGS)") 453 } 454 455 g := d.MakeGetter() 456 457 word_idx := 0 458 input_idx := 0 459 total := 0 460 // check for existing and non existing keys 461 for g.HasNext() { 462 pos := g.dataP 463 if INPUT_FLAGS[input_idx] == 0 { // []byte input 464 notExpected := string(WORDS[word_idx]) + "z" 465 cmp := g.MatchCmp([]byte(notExpected)) 466 if cmp == 0 { 467 t.Fatalf("not expected match: %v\n got: %v\n", []byte(notExpected), WORDS[word_idx]) 468 } 469 470 expected := WORDS[word_idx] 471 cmp = g.MatchCmp(expected) // move offset to the next pos 472 if cmp != 0 { 473 savePos := g.dataP 474 g.Reset(pos) 475 word, nextPos := g.Next(nil) 476 if nextPos != savePos { 477 t.Fatalf("nextPos %d != savePos %d\n", nextPos, savePos) 478 } 479 if bytes.Compare(expected, word) != cmp { 480 fmt.Printf("1 expected: %v, acutal %v, cmp %d\n", expected, word, cmp) 481 } 482 t.Fatalf("expected match: %v\n got: %v\n", expected, word) 483 } 484 word_idx++ 485 } else { // nil input 486 notExpected := []byte{0} 487 cmp := g.MatchCmp(notExpected) 488 if cmp == 0 { 489 t.Fatal("not expected match []byte{0} with nil\n") 490 } 491 492 expected := []byte{} 493 cmp = g.MatchCmp(nil) 494 if cmp != 0 { 495 savePos := g.dataP 496 g.Reset(pos) 497 word, nextPos := g.Next(nil) 498 if nextPos != savePos { 499 t.Fatalf("nextPos %d != savePos %d\n", nextPos, savePos) 500 } 501 if bytes.Compare(expected, word) != cmp { 502 fmt.Printf("2 expected: %v, acutal %v, cmp %d\n", expected, word, cmp) 503 } 504 t.Fatalf("expected match: %v\n got: %v\n", expected, word) 505 } 506 } 507 input_idx++ 508 total++ 509 } 510 if total != int(d.wordsCount) { 511 t.Fatalf("expected word count: %d, got %d\n", int(d.wordsCount), total) 512 } 513 } 514 515 func TestDecompressRandomMatchBool(t *testing.T) { 516 d := prepareRandomDict(t) 517 defer d.Close() 518 519 if d.wordsCount != uint64(len(INPUT_FLAGS)) { 520 t.Fatalf("TestDecompressRandomDict: d.wordsCount != len(INPUT_FLAGS)") 521 } 522 523 g := d.MakeGetter() 524 525 word_idx := 0 526 input_idx := 0 527 total := 0 528 // check for existing and non existing keys 529 for g.HasNext() { 530 pos := g.dataP 531 if INPUT_FLAGS[input_idx] == 0 { // []byte input 532 notExpected := string(WORDS[word_idx]) + "z" 533 ok, _ := g.Match([]byte(notExpected)) 534 if ok { 535 t.Fatalf("not expected match: %v\n got: %v\n", []byte(notExpected), WORDS[word_idx]) 536 } 537 538 expected := WORDS[word_idx] 539 ok, _ = g.Match(expected) 540 if !ok { 541 g.Reset(pos) 542 word, _ := g.Next(nil) 543 if bytes.Compare(expected, word) != 0 { 544 fmt.Printf("1 expected: %v, acutal %v, ok %v\n", expected, word, ok) 545 } 546 t.Fatalf("expected match: %v\n got: %v\n", expected, word) 547 } 548 word_idx++ 549 } else { // nil input 550 notExpected := []byte{0} 551 ok, _ := g.Match(notExpected) 552 if ok { 553 t.Fatal("not expected match []byte{0} with nil\n") 554 } 555 556 expected := []byte{} 557 ok, _ = g.Match(nil) 558 if !ok { 559 g.Reset(pos) 560 word, _ := g.Next(nil) 561 if bytes.Compare(expected, word) != 0 { 562 fmt.Printf("2 expected: %v, acutal %v, ok %v\n", expected, word, ok) 563 } 564 t.Fatalf("expected match: %v\n got: %v\n", expected, word) 565 } 566 } 567 input_idx++ 568 total++ 569 } 570 if total != int(d.wordsCount) { 571 t.Fatalf("expected word count: %d, got %d\n", int(d.wordsCount), total) 572 } 573 } 574 575 func TestDecompressRandomFastNext(t *testing.T) { 576 d := prepareRandomDict(t) 577 defer d.Close() 578 579 if d.wordsCount != uint64(len(INPUT_FLAGS)) { 580 t.Fatalf("TestDecompressRandomDict: d.wordsCount != len(INPUT_FLAGS)") 581 } 582 583 g := d.MakeGetter() 584 585 word_idx := 0 586 input_idx := 0 587 total := 0 588 buf := make([]byte, (1 << 23)) 589 // check for existing and non existing keys 590 for g.HasNext() { 591 if INPUT_FLAGS[input_idx] == 0 { // []byte input 592 expected := WORDS[word_idx] 593 word, _ := g.FastNext(buf) 594 if bytes.Compare(expected, word) != 0 { 595 t.Fatalf("1 expected: %v, got %v\n", expected, word) 596 } 597 word_idx++ 598 } else { // nil input 599 expected := []byte{} 600 word, _ := g.FastNext(buf) 601 if bytes.Compare(expected, word) != 0 { 602 t.Fatalf("2 expected: %v, got %v\n", expected, word) 603 } 604 } 605 input_idx++ 606 total++ 607 } 608 if total != int(d.wordsCount) { 609 t.Fatalf("expected word count: %d, got %d\n", int(d.wordsCount), total) 610 } 611 } 612 613 // func TestDecompressRandomDict(t *testing.T) { 614 // d := prepareRandomDict(t) 615 // defer d.Close() 616 617 // if d.wordsCount != uint64(len(INPUT_FLAGS)) { 618 // t.Fatalf("TestDecompressRandomDict: d.wordsCount != len(INPUT_FLAGS)") 619 // } 620 621 // g := d.MakeGetter() 622 623 // word_idx := 0 624 // input_idx := 0 625 // total := 0 626 // // check for existing and non existing keys 627 // for g.HasNext() { 628 // pos := g.dataP 629 // if INPUT_FLAGS[input_idx] == 0 { // []byte input 630 // notExpected := string(WORDS[word_idx]) + "z" 631 // ok, _ := g.Match([]byte(notExpected)) 632 // if ok { 633 // t.Fatalf("not expected match: %s\n got: %s\n", notExpected, WORDS[word_idx]) 634 // } 635 636 // expected := WORDS[word_idx] 637 // ok, _ = g.Match(expected) 638 // if !ok { 639 // g.Reset(pos) 640 // word, _ := g.Next(nil) 641 // t.Fatalf("expected match: %s\n got: %s\n", expected, word) 642 // } 643 // word_idx++ 644 // } else { // nil input 645 // notExpected := []byte{0} 646 // ok, _ := g.Match(notExpected) 647 // if ok { 648 // t.Fatal("not expected match []byte{0} with nil\n") 649 // } 650 651 // expected := []byte{} 652 // ok, _ = g.Match(nil) 653 // if !ok { 654 // g.Reset(pos) 655 // word, _ := g.Next(nil) 656 // t.Fatalf("expected match: %s\n got: %s\n", expected, word) 657 // } 658 // } 659 // input_idx++ 660 // total++ 661 // } 662 // if total != int(d.wordsCount) { 663 // t.Fatalf("expected word count: %d, got %d\n", int(d.wordsCount), total) 664 // } 665 666 // // TODO: check for non existing keys, suffixes, prefixes 667 // g.Reset(0) 668 669 // word_idx = 0 670 // input_idx = 0 671 // // check for existing and non existing prefixes 672 // var notExpected = []byte{2, 3, 4} 673 // for g.HasNext() { 674 675 // if INPUT_FLAGS[input_idx] == 0 { // []byte input 676 // expected := WORDS[word_idx] 677 // prefix_size := len(expected) / 2 678 // if len(expected)/2 > 3 { 679 // prefix_size = randIntInRange(3, len(expected)/2) 680 // } 681 // expected = expected[:prefix_size] 682 // if len(expected) > 0 { 683 // if !g.MatchPrefix(expected) { 684 // t.Errorf("expected match with %s", expected) 685 // } 686 // expected[len(expected)-1]++ 687 // if g.MatchPrefix(expected) { 688 // t.Errorf("not expected match with %s", expected) 689 // } 690 // } else { 691 // if !g.MatchPrefix([]byte{}) { 692 // t.Error("expected match with empty []byte") 693 // } 694 // if g.MatchPrefix(notExpected) { 695 // t.Error("not expected empty []byte to match with []byte{2, 3, 4}") 696 // } 697 // } 698 // word_idx++ 699 // } else { // nil input 700 // if !g.MatchPrefix(nil) { 701 // t.Error("expected match with nil") 702 // } 703 // if g.MatchPrefix(notExpected) { 704 // t.Error("not expected nil to match with []byte{2, 3, 4}") 705 // } 706 // } 707 708 // g.Skip() 709 // input_idx++ 710 // } 711 712 // g.Reset(0) 713 714 // word_idx = 0 715 // input_idx = 0 716 // // check for existing and non existing suffixes 717 // notExpected = []byte{2, 3, 4} 718 // for g.HasNext() { 719 720 // if INPUT_FLAGS[input_idx] == 0 { // []byte input 721 // suffix := WORDS[word_idx] 722 // if len(suffix) > 1 { 723 // prefix := suffix[:len(suffix)/2] 724 // suffix = suffix[len(suffix)/2:] 725 // equal := reflect.DeepEqual(prefix, suffix) 726 // // check existing suffixes 727 // if g.MatchPrefix(suffix) { // suffix has to be equal to prefix 728 // if !equal { 729 // t.Fatalf("MatchPrefix(suffix) expected match: prefix is unequal to suffix %v != %v, full slice %v\n", prefix, suffix, WORDS[word_idx]) 730 // } 731 // } else { // suffix has not to be the same as prefix 732 // if equal { 733 // t.Fatalf("MatchPrefix(suffix) expected unmatch: prefix is equal to suffix %v != %v, full slice %v\n", prefix, suffix, WORDS[word_idx]) 734 // } 735 // } 736 737 // if len(suffix) > 0 { 738 // suffix[0]++ 739 // if g.MatchPrefix(suffix) && reflect.DeepEqual(prefix, suffix) { 740 // t.Fatalf("MatchPrefix(suffix) not expected match: prefix is unequal to suffix %v != %v, full slice %v\n", prefix, suffix, WORDS[word_idx]) 741 // } 742 // } 743 744 // g.Skip() 745 // } else { 746 // ok, _ := g.Match(suffix) 747 // if !ok { 748 // t.Fatal("Match(suffix): expected match suffix") 749 // } 750 // } 751 // word_idx++ 752 // } else { // nil input 753 // if !g.MatchPrefix(nil) { 754 // t.Error("MatchPrefix(suffix): expected match with nil") 755 // } 756 // if g.MatchPrefix(notExpected) { 757 // t.Error("MatchPrefix(suffix): not expected nil to match with []byte{2, 3, 4}") 758 // } 759 // ok, _ := g.Match(nil) 760 // if !ok { 761 // t.Errorf("Match(suffix): expected to match with nil") 762 // } 763 // } 764 765 // input_idx++ 766 // } 767 // }