github.com/sunvim/utils@v0.1.0/patricia/patricia_dense_test.go (about)

     1  // Copyright (c) 2014 The go-patricia AUTHORS
     2  //
     3  // Use of this source code is governed by The MIT License
     4  // that can be found in the LICENSE file.
     5  
     6  package patricia
     7  
     8  import (
     9  	"math/rand"
    10  	"runtime"
    11  	"strconv"
    12  	"testing"
    13  )
    14  
    15  // Tests -----------------------------------------------------------------------
    16  
    17  // overhead is allowed tolerance for Go's runtime/GC to increase the allocated memory
    18  // (to avoid failing tests on insignificant growth amounts)
    19  const overhead = 4000
    20  
    21  func TestTrie_InsertDense(t *testing.T) {
    22  	trie := NewTrie()
    23  
    24  	data := []testData{
    25  		{"aba", 0, success},
    26  		{"abb", 1, success},
    27  		{"abc", 2, success},
    28  		{"abd", 3, success},
    29  		{"abe", 4, success},
    30  		{"abf", 5, success},
    31  		{"abg", 6, success},
    32  		{"abh", 7, success},
    33  		{"abi", 8, success},
    34  		{"abj", 9, success},
    35  		{"abk", 0, success},
    36  		{"abl", 1, success},
    37  		{"abm", 2, success},
    38  		{"abn", 3, success},
    39  		{"abo", 4, success},
    40  		{"abp", 5, success},
    41  		{"abq", 6, success},
    42  		{"abr", 7, success},
    43  		{"abs", 8, success},
    44  		{"abt", 9, success},
    45  		{"abu", 0, success},
    46  		{"abv", 1, success},
    47  		{"abw", 2, success},
    48  		{"abx", 3, success},
    49  		{"aby", 4, success},
    50  		{"abz", 5, success},
    51  	}
    52  
    53  	for _, v := range data {
    54  		t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
    55  		if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
    56  			t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
    57  		}
    58  	}
    59  }
    60  
    61  func TestTrie_InsertDensePreceeding(t *testing.T) {
    62  	trie := NewTrie()
    63  	start := byte(70)
    64  	// create a dense node
    65  	for i := byte(0); i <= DefaultMaxChildrenPerSparseNode; i++ {
    66  		if !trie.Insert(Prefix([]byte{start + i}), true) {
    67  			t.Errorf("insert failed, prefix=%v", start+i)
    68  		}
    69  	}
    70  	// insert some preceding keys
    71  	for i := byte(1); i < start; i *= i + 1 {
    72  		if !trie.Insert(Prefix([]byte{start - i}), true) {
    73  			t.Errorf("insert failed, prefix=%v", start-i)
    74  		}
    75  	}
    76  }
    77  
    78  func TestTrie_InsertDenseDuplicatePrefixes(t *testing.T) {
    79  	trie := NewTrie()
    80  
    81  	data := []testData{
    82  		{"aba", 0, success},
    83  		{"abb", 1, success},
    84  		{"abc", 2, success},
    85  		{"abd", 3, success},
    86  		{"abe", 4, success},
    87  		{"abf", 5, success},
    88  		{"abg", 6, success},
    89  		{"abh", 7, success},
    90  		{"abi", 8, success},
    91  		{"abj", 9, success},
    92  		{"abk", 0, success},
    93  		{"abl", 1, success},
    94  		{"abm", 2, success},
    95  		{"abn", 3, success},
    96  		{"abo", 4, success},
    97  		{"abp", 5, success},
    98  		{"abq", 6, success},
    99  		{"abr", 7, success},
   100  		{"abs", 8, success},
   101  		{"abt", 9, success},
   102  		{"abu", 0, success},
   103  		{"abv", 1, success},
   104  		{"abw", 2, success},
   105  		{"abx", 3, success},
   106  		{"aby", 4, success},
   107  		{"abz", 5, success},
   108  		{"aba", 0, failure},
   109  		{"abb", 1, failure},
   110  		{"abc", 2, failure},
   111  		{"abd", 3, failure},
   112  		{"abe", 4, failure},
   113  	}
   114  
   115  	for _, v := range data {
   116  		t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
   117  		if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
   118  			t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
   119  		}
   120  	}
   121  }
   122  
   123  func TestTrie_CloneDense(t *testing.T) {
   124  	trie := NewTrie()
   125  
   126  	data := []testData{
   127  		{"aba", 0, success},
   128  		{"abb", 1, success},
   129  		{"abc", 2, success},
   130  		{"abd", 3, success},
   131  		{"abe", 4, success},
   132  		{"abf", 5, success},
   133  		{"abg", 6, success},
   134  		{"abh", 7, success},
   135  		{"abi", 8, success},
   136  		{"abj", 9, success},
   137  		{"abk", 0, success},
   138  		{"abl", 1, success},
   139  		{"abm", 2, success},
   140  		{"abn", 3, success},
   141  		{"abo", 4, success},
   142  		{"abp", 5, success},
   143  		{"abq", 6, success},
   144  		{"abr", 7, success},
   145  		{"abs", 8, success},
   146  		{"abt", 9, success},
   147  		{"abu", 0, success},
   148  		{"abv", 1, success},
   149  		{"abw", 2, success},
   150  		{"abx", 3, success},
   151  		{"aby", 4, success},
   152  		{"abz", 5, success},
   153  	}
   154  
   155  	for _, v := range data {
   156  		t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
   157  		if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
   158  			t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
   159  		}
   160  	}
   161  
   162  	t.Log("CLONE")
   163  	clone := trie.Clone()
   164  
   165  	for _, v := range data {
   166  		t.Logf("GET prefix=%v, item=%v", v.key, v.value)
   167  		if item := clone.Get(Prefix(v.key)); item != v.value {
   168  			t.Errorf("Unexpected return value, expected=%v, got=%v", v.value, item)
   169  		}
   170  	}
   171  
   172  	prefix := "xxx"
   173  	item := 666
   174  	t.Logf("INSERT prefix=%v, item=%v", prefix, item)
   175  	if ok := trie.Insert(Prefix(prefix), item); !ok {
   176  		t.Errorf("Unexpected return value, expected=true, got=%v", ok)
   177  	}
   178  	t.Logf("GET cloned prefix=%v", prefix)
   179  	if item := clone.Get(Prefix(prefix)); item != nil {
   180  		t.Errorf("Unexpected return value, expected=nil, got=%v", item)
   181  	}
   182  }
   183  
   184  func TestTrie_DeleteDense(t *testing.T) {
   185  	trie := NewTrie()
   186  
   187  	data := []testData{
   188  		{"aba", 0, success},
   189  		{"abb", 1, success},
   190  		{"abc", 2, success},
   191  		{"abd", 3, success},
   192  		{"abe", 4, success},
   193  		{"abf", 5, success},
   194  		{"abg", 6, success},
   195  		{"abh", 7, success},
   196  		{"abi", 8, success},
   197  		{"abj", 9, success},
   198  		{"abk", 0, success},
   199  		{"abl", 1, success},
   200  		{"abm", 2, success},
   201  		{"abn", 3, success},
   202  		{"abo", 4, success},
   203  		{"abp", 5, success},
   204  		{"abq", 6, success},
   205  		{"abr", 7, success},
   206  		{"abs", 8, success},
   207  		{"abt", 9, success},
   208  		{"abu", 0, success},
   209  		{"abv", 1, success},
   210  		{"abw", 2, success},
   211  		{"abx", 3, success},
   212  		{"aby", 4, success},
   213  		{"abz", 5, success},
   214  	}
   215  
   216  	for _, v := range data {
   217  		t.Logf("INSERT prefix=%v, item=%v, success=%v", v.key, v.value, v.retVal)
   218  		if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
   219  			t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
   220  		}
   221  	}
   222  
   223  	for _, v := range data {
   224  		t.Logf("DELETE word=%v, success=%v", v.key, v.retVal)
   225  		if ok := trie.Delete([]byte(v.key)); ok != v.retVal {
   226  			t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
   227  		}
   228  	}
   229  }
   230  
   231  func TestTrie_DeleteLeakageDense(t *testing.T) {
   232  	trie := NewTrie()
   233  
   234  	genTestData := func() *testData {
   235  		// Generate a random integer as a key.
   236  		key := strconv.FormatUint(rand.Uint64(), 10)
   237  		return &testData{key: key, value: "v", retVal: success}
   238  	}
   239  
   240  	testSize := 100
   241  	data := make([]*testData, 0, testSize)
   242  	for i := 0; i < testSize; i++ {
   243  		data = append(data, genTestData())
   244  	}
   245  
   246  	oldBytes := heapAllocatedBytes()
   247  
   248  	// repeat insertion/deletion for 10K times to catch possible memory issues
   249  	for i := 0; i < 10000; i++ {
   250  		for _, v := range data {
   251  			if ok := trie.Insert(Prefix(v.key), v.value); ok != v.retVal {
   252  				t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
   253  			}
   254  		}
   255  
   256  		for _, v := range data {
   257  			if ok := trie.Delete([]byte(v.key)); ok != v.retVal {
   258  				t.Errorf("Unexpected return value, expected=%v, got=%v", v.retVal, ok)
   259  			}
   260  		}
   261  	}
   262  
   263  	if newBytes := heapAllocatedBytes(); newBytes > oldBytes+overhead {
   264  		t.Logf("Size=%d, Total=%d, Trie state:\n%s\n", trie.size(), trie.total(), trie.dump())
   265  		t.Errorf("Heap space leak, grew %d bytes (%d to %d)\n", newBytes-oldBytes, oldBytes, newBytes)
   266  	}
   267  
   268  	if numChildren := trie.children.length(); numChildren != 0 {
   269  		t.Errorf("Trie is not empty: %v children found", numChildren)
   270  	}
   271  }
   272  
   273  func heapAllocatedBytes() uint64 {
   274  	runtime.GC()
   275  
   276  	ms := runtime.MemStats{}
   277  	runtime.ReadMemStats(&ms)
   278  	return ms.Alloc
   279  }