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  // }