github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/database/internal/treap/immutable_test.go (about)

     1  // Copyright (c) 2015-2016 The btcsuite developers
     2  // Copyright (c) 2016 The Dash developers
     3  // Use of this source code is governed by an ISC
     4  // license that can be found in the LICENSE file.
     5  
     6  package treap
     7  
     8  import (
     9  	"bytes"
    10  	"crypto/sha256"
    11  	"testing"
    12  )
    13  
    14  // TestImmutableEmpty ensures calling functions on an empty immutable treap
    15  // works as expected.
    16  func TestImmutableEmpty(t *testing.T) {
    17  	t.Parallel()
    18  
    19  	// Ensure the treap length is the expected value.
    20  	testTreap := NewImmutable()
    21  	if gotLen := testTreap.Len(); gotLen != 0 {
    22  		t.Fatalf("Len: unexpected length - got %d, want %d", gotLen, 0)
    23  	}
    24  
    25  	// Ensure the reported size is 0.
    26  	if gotSize := testTreap.Size(); gotSize != 0 {
    27  		t.Fatalf("Size: unexpected byte size - got %d, want 0",
    28  			gotSize)
    29  	}
    30  
    31  	// Ensure there are no errors with requesting keys from an empty treap.
    32  	key := serializeUint32(0)
    33  	if gotVal := testTreap.Has(key); gotVal != false {
    34  		t.Fatalf("Has: unexpected result - got %v, want false", gotVal)
    35  	}
    36  	if gotVal := testTreap.Get(key); gotVal != nil {
    37  		t.Fatalf("Get: unexpected result - got %x, want nil", gotVal)
    38  	}
    39  
    40  	// Ensure there are no panics when deleting keys from an empty treap.
    41  	testTreap.Delete(key)
    42  
    43  	// Ensure the number of keys iterated by ForEach on an empty treap is
    44  	// zero.
    45  	var numIterated int
    46  	testTreap.ForEach(func(k, v []byte) bool {
    47  		numIterated++
    48  		return true
    49  	})
    50  	if numIterated != 0 {
    51  		t.Fatalf("ForEach: unexpected iterate count - got %d, want 0",
    52  			numIterated)
    53  	}
    54  }
    55  
    56  // TestImmutableSequential ensures that putting keys into an immutable treap in
    57  // sequential order works as expected.
    58  func TestImmutableSequential(t *testing.T) {
    59  	t.Parallel()
    60  
    61  	// Insert a bunch of sequential keys while checking several of the treap
    62  	// functions work as expected.
    63  	expectedSize := uint64(0)
    64  	numItems := 1000
    65  	testTreap := NewImmutable()
    66  	for i := 0; i < numItems; i++ {
    67  		key := serializeUint32(uint32(i))
    68  		testTreap = testTreap.Put(key, key)
    69  
    70  		// Ensure the treap length is the expected value.
    71  		if gotLen := testTreap.Len(); gotLen != i+1 {
    72  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
    73  				i, gotLen, i+1)
    74  		}
    75  
    76  		// Ensure the treap has the key.
    77  		if !testTreap.Has(key) {
    78  			t.Fatalf("Has #%d: key %q is not in treap", i, key)
    79  		}
    80  
    81  		// Get the key from the treap and ensure it is the expected
    82  		// value.
    83  		if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) {
    84  			t.Fatalf("Get #%d: unexpected value - got %x, want %x",
    85  				i, gotVal, key)
    86  		}
    87  
    88  		// Ensure the expected size is reported.
    89  		expectedSize += (nodeFieldsSize + 8)
    90  		if gotSize := testTreap.Size(); gotSize != expectedSize {
    91  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
    92  				"want %d", i, gotSize, expectedSize)
    93  		}
    94  	}
    95  
    96  	// Ensure the all keys are iterated by ForEach in order.
    97  	var numIterated int
    98  	testTreap.ForEach(func(k, v []byte) bool {
    99  		wantKey := serializeUint32(uint32(numIterated))
   100  
   101  		// Ensure the key is as expected.
   102  		if !bytes.Equal(k, wantKey) {
   103  			t.Fatalf("ForEach #%d: unexpected key - got %x, want %x",
   104  				numIterated, k, wantKey)
   105  		}
   106  
   107  		// Ensure the value is as expected.
   108  		if !bytes.Equal(v, wantKey) {
   109  			t.Fatalf("ForEach #%d: unexpected value - got %x, want %x",
   110  				numIterated, v, wantKey)
   111  		}
   112  
   113  		numIterated++
   114  		return true
   115  	})
   116  
   117  	// Ensure all items were iterated.
   118  	if numIterated != numItems {
   119  		t.Fatalf("ForEach: unexpected iterate count - got %d, want %d",
   120  			numIterated, numItems)
   121  	}
   122  
   123  	// Delete the keys one-by-one while checking several of the treap
   124  	// functions work as expected.
   125  	for i := 0; i < numItems; i++ {
   126  		key := serializeUint32(uint32(i))
   127  		testTreap = testTreap.Delete(key)
   128  
   129  		// Ensure the treap length is the expected value.
   130  		if gotLen := testTreap.Len(); gotLen != numItems-i-1 {
   131  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
   132  				i, gotLen, numItems-i-1)
   133  		}
   134  
   135  		// Ensure the treap no longer has the key.
   136  		if testTreap.Has(key) {
   137  			t.Fatalf("Has #%d: key %q is in treap", i, key)
   138  		}
   139  
   140  		// Get the key that no longer exists from the treap and ensure
   141  		// it is nil.
   142  		if gotVal := testTreap.Get(key); gotVal != nil {
   143  			t.Fatalf("Get #%d: unexpected value - got %x, want nil",
   144  				i, gotVal)
   145  		}
   146  
   147  		// Ensure the expected size is reported.
   148  		expectedSize -= (nodeFieldsSize + 8)
   149  		if gotSize := testTreap.Size(); gotSize != expectedSize {
   150  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
   151  				"want %d", i, gotSize, expectedSize)
   152  		}
   153  	}
   154  }
   155  
   156  // TestImmutableReverseSequential ensures that putting keys into an immutable
   157  // treap in reverse sequential order works as expected.
   158  func TestImmutableReverseSequential(t *testing.T) {
   159  	t.Parallel()
   160  
   161  	// Insert a bunch of sequential keys while checking several of the treap
   162  	// functions work as expected.
   163  	expectedSize := uint64(0)
   164  	numItems := 1000
   165  	testTreap := NewImmutable()
   166  	for i := 0; i < numItems; i++ {
   167  		key := serializeUint32(uint32(numItems - i - 1))
   168  		testTreap = testTreap.Put(key, key)
   169  
   170  		// Ensure the treap length is the expected value.
   171  		if gotLen := testTreap.Len(); gotLen != i+1 {
   172  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
   173  				i, gotLen, i+1)
   174  		}
   175  
   176  		// Ensure the treap has the key.
   177  		if !testTreap.Has(key) {
   178  			t.Fatalf("Has #%d: key %q is not in treap", i, key)
   179  		}
   180  
   181  		// Get the key from the treap and ensure it is the expected
   182  		// value.
   183  		if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) {
   184  			t.Fatalf("Get #%d: unexpected value - got %x, want %x",
   185  				i, gotVal, key)
   186  		}
   187  
   188  		// Ensure the expected size is reported.
   189  		expectedSize += (nodeFieldsSize + 8)
   190  		if gotSize := testTreap.Size(); gotSize != expectedSize {
   191  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
   192  				"want %d", i, gotSize, expectedSize)
   193  		}
   194  	}
   195  
   196  	// Ensure the all keys are iterated by ForEach in order.
   197  	var numIterated int
   198  	testTreap.ForEach(func(k, v []byte) bool {
   199  		wantKey := serializeUint32(uint32(numIterated))
   200  
   201  		// Ensure the key is as expected.
   202  		if !bytes.Equal(k, wantKey) {
   203  			t.Fatalf("ForEach #%d: unexpected key - got %x, want %x",
   204  				numIterated, k, wantKey)
   205  		}
   206  
   207  		// Ensure the value is as expected.
   208  		if !bytes.Equal(v, wantKey) {
   209  			t.Fatalf("ForEach #%d: unexpected value - got %x, want %x",
   210  				numIterated, v, wantKey)
   211  		}
   212  
   213  		numIterated++
   214  		return true
   215  	})
   216  
   217  	// Ensure all items were iterated.
   218  	if numIterated != numItems {
   219  		t.Fatalf("ForEach: unexpected iterate count - got %d, want %d",
   220  			numIterated, numItems)
   221  	}
   222  
   223  	// Delete the keys one-by-one while checking several of the treap
   224  	// functions work as expected.
   225  	for i := 0; i < numItems; i++ {
   226  		// Intentionally use the reverse order they were inserted here.
   227  		key := serializeUint32(uint32(i))
   228  		testTreap = testTreap.Delete(key)
   229  
   230  		// Ensure the treap length is the expected value.
   231  		if gotLen := testTreap.Len(); gotLen != numItems-i-1 {
   232  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
   233  				i, gotLen, numItems-i-1)
   234  		}
   235  
   236  		// Ensure the treap no longer has the key.
   237  		if testTreap.Has(key) {
   238  			t.Fatalf("Has #%d: key %q is in treap", i, key)
   239  		}
   240  
   241  		// Get the key that no longer exists from the treap and ensure
   242  		// it is nil.
   243  		if gotVal := testTreap.Get(key); gotVal != nil {
   244  			t.Fatalf("Get #%d: unexpected value - got %x, want nil",
   245  				i, gotVal)
   246  		}
   247  
   248  		// Ensure the expected size is reported.
   249  		expectedSize -= (nodeFieldsSize + 8)
   250  		if gotSize := testTreap.Size(); gotSize != expectedSize {
   251  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
   252  				"want %d", i, gotSize, expectedSize)
   253  		}
   254  	}
   255  }
   256  
   257  // TestImmutableUnordered ensures that putting keys into an immutable treap in
   258  // no paritcular order works as expected.
   259  func TestImmutableUnordered(t *testing.T) {
   260  	t.Parallel()
   261  
   262  	// Insert a bunch of out-of-order keys while checking several of the
   263  	// treap functions work as expected.
   264  	expectedSize := uint64(0)
   265  	numItems := 1000
   266  	testTreap := NewImmutable()
   267  	for i := 0; i < numItems; i++ {
   268  		// Hash the serialized int to generate out-of-order keys.
   269  		hash := sha256.Sum256(serializeUint32(uint32(i)))
   270  		key := hash[:]
   271  		testTreap = testTreap.Put(key, key)
   272  
   273  		// Ensure the treap length is the expected value.
   274  		if gotLen := testTreap.Len(); gotLen != i+1 {
   275  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
   276  				i, gotLen, i+1)
   277  		}
   278  
   279  		// Ensure the treap has the key.
   280  		if !testTreap.Has(key) {
   281  			t.Fatalf("Has #%d: key %q is not in treap", i, key)
   282  		}
   283  
   284  		// Get the key from the treap and ensure it is the expected
   285  		// value.
   286  		if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, key) {
   287  			t.Fatalf("Get #%d: unexpected value - got %x, want %x",
   288  				i, gotVal, key)
   289  		}
   290  
   291  		// Ensure the expected size is reported.
   292  		expectedSize += nodeFieldsSize + uint64(len(key)+len(key))
   293  		if gotSize := testTreap.Size(); gotSize != expectedSize {
   294  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
   295  				"want %d", i, gotSize, expectedSize)
   296  		}
   297  	}
   298  
   299  	// Delete the keys one-by-one while checking several of the treap
   300  	// functions work as expected.
   301  	for i := 0; i < numItems; i++ {
   302  		// Hash the serialized int to generate out-of-order keys.
   303  		hash := sha256.Sum256(serializeUint32(uint32(i)))
   304  		key := hash[:]
   305  		testTreap = testTreap.Delete(key)
   306  
   307  		// Ensure the treap length is the expected value.
   308  		if gotLen := testTreap.Len(); gotLen != numItems-i-1 {
   309  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
   310  				i, gotLen, numItems-i-1)
   311  		}
   312  
   313  		// Ensure the treap no longer has the key.
   314  		if testTreap.Has(key) {
   315  			t.Fatalf("Has #%d: key %q is in treap", i, key)
   316  		}
   317  
   318  		// Get the key that no longer exists from the treap and ensure
   319  		// it is nil.
   320  		if gotVal := testTreap.Get(key); gotVal != nil {
   321  			t.Fatalf("Get #%d: unexpected value - got %x, want nil",
   322  				i, gotVal)
   323  		}
   324  
   325  		// Ensure the expected size is reported.
   326  		expectedSize -= (nodeFieldsSize + 64)
   327  		if gotSize := testTreap.Size(); gotSize != expectedSize {
   328  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
   329  				"want %d", i, gotSize, expectedSize)
   330  		}
   331  	}
   332  }
   333  
   334  // TestImmutableDuplicatePut ensures that putting a duplicate key into an
   335  // immutable treap works as expected.
   336  func TestImmutableDuplicatePut(t *testing.T) {
   337  	t.Parallel()
   338  
   339  	expectedVal := []byte("testval")
   340  	expectedSize := uint64(0)
   341  	numItems := 1000
   342  	testTreap := NewImmutable()
   343  	for i := 0; i < numItems; i++ {
   344  		key := serializeUint32(uint32(i))
   345  		testTreap = testTreap.Put(key, key)
   346  		expectedSize += nodeFieldsSize + uint64(len(key)+len(key))
   347  
   348  		// Put a duplicate key with the the expected final value.
   349  		testTreap = testTreap.Put(key, expectedVal)
   350  
   351  		// Ensure the key still exists and is the new value.
   352  		if gotVal := testTreap.Has(key); gotVal != true {
   353  			t.Fatalf("Has: unexpected result - got %v, want false",
   354  				gotVal)
   355  		}
   356  		if gotVal := testTreap.Get(key); !bytes.Equal(gotVal, expectedVal) {
   357  			t.Fatalf("Get: unexpected result - got %x, want %x",
   358  				gotVal, expectedVal)
   359  		}
   360  
   361  		// Ensure the expected size is reported.
   362  		expectedSize -= uint64(len(key))
   363  		expectedSize += uint64(len(expectedVal))
   364  		if gotSize := testTreap.Size(); gotSize != expectedSize {
   365  			t.Fatalf("Size: unexpected byte size - got %d, want %d",
   366  				gotSize, expectedSize)
   367  		}
   368  	}
   369  }
   370  
   371  // TestImmutableNilValue ensures that putting a nil value into an immutable
   372  // treap results in a key being added with an empty byte slice.
   373  func TestImmutableNilValue(t *testing.T) {
   374  	t.Parallel()
   375  
   376  	key := serializeUint32(0)
   377  
   378  	// Put the key with a nil value.
   379  	testTreap := NewImmutable()
   380  	testTreap = testTreap.Put(key, nil)
   381  
   382  	// Ensure the key exists and is an empty byte slice.
   383  	if gotVal := testTreap.Has(key); gotVal != true {
   384  		t.Fatalf("Has: unexpected result - got %v, want false", gotVal)
   385  	}
   386  	if gotVal := testTreap.Get(key); gotVal == nil {
   387  		t.Fatalf("Get: unexpected result - got nil, want empty slice")
   388  	}
   389  	if gotVal := testTreap.Get(key); len(gotVal) != 0 {
   390  		t.Fatalf("Get: unexpected result - got %x, want empty slice",
   391  			gotVal)
   392  	}
   393  }
   394  
   395  // TestImmutableForEachStopIterator ensures that returning false from the ForEach
   396  // callback on an immutable treap stops iteration early.
   397  func TestImmutableForEachStopIterator(t *testing.T) {
   398  	t.Parallel()
   399  
   400  	// Insert a few keys.
   401  	numItems := 10
   402  	testTreap := NewImmutable()
   403  	for i := 0; i < numItems; i++ {
   404  		key := serializeUint32(uint32(i))
   405  		testTreap = testTreap.Put(key, key)
   406  	}
   407  
   408  	// Ensure ForEach exits early on false return by caller.
   409  	var numIterated int
   410  	testTreap.ForEach(func(k, v []byte) bool {
   411  		numIterated++
   412  		if numIterated == numItems/2 {
   413  			return false
   414  		}
   415  		return true
   416  	})
   417  	if numIterated != numItems/2 {
   418  		t.Fatalf("ForEach: unexpected iterate count - got %d, want %d",
   419  			numIterated, numItems/2)
   420  	}
   421  }
   422  
   423  // TestImmutableSnapshot ensures that immutable treaps are actually immutable by
   424  // keeping a reference to the previous treap, performing a mutation, and then
   425  // ensuring the referenced treap does not have the mutation applied.
   426  func TestImmutableSnapshot(t *testing.T) {
   427  	t.Parallel()
   428  
   429  	// Insert a bunch of sequential keys while checking several of the treap
   430  	// functions work as expected.
   431  	expectedSize := uint64(0)
   432  	numItems := 1000
   433  	testTreap := NewImmutable()
   434  	for i := 0; i < numItems; i++ {
   435  		treapSnap := testTreap
   436  
   437  		key := serializeUint32(uint32(i))
   438  		testTreap = testTreap.Put(key, key)
   439  
   440  		// Ensure the length of the treap snapshot is the expected
   441  		// value.
   442  		if gotLen := treapSnap.Len(); gotLen != i {
   443  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
   444  				i, gotLen, i)
   445  		}
   446  
   447  		// Ensure the treap snapshot does not have the key.
   448  		if treapSnap.Has(key) {
   449  			t.Fatalf("Has #%d: key %q is in treap", i, key)
   450  		}
   451  
   452  		// Get the key that doesn't exist in the treap snapshot and
   453  		// ensure it is nil.
   454  		if gotVal := treapSnap.Get(key); gotVal != nil {
   455  			t.Fatalf("Get #%d: unexpected value - got %x, want nil",
   456  				i, gotVal)
   457  		}
   458  
   459  		// Ensure the expected size is reported.
   460  		if gotSize := treapSnap.Size(); gotSize != expectedSize {
   461  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
   462  				"want %d", i, gotSize, expectedSize)
   463  		}
   464  		expectedSize += (nodeFieldsSize + 8)
   465  	}
   466  
   467  	// Delete the keys one-by-one while checking several of the treap
   468  	// functions work as expected.
   469  	for i := 0; i < numItems; i++ {
   470  		treapSnap := testTreap
   471  
   472  		key := serializeUint32(uint32(i))
   473  		testTreap = testTreap.Delete(key)
   474  
   475  		// Ensure the length of the treap snapshot is the expected
   476  		// value.
   477  		if gotLen := treapSnap.Len(); gotLen != numItems-i {
   478  			t.Fatalf("Len #%d: unexpected length - got %d, want %d",
   479  				i, gotLen, numItems-i)
   480  		}
   481  
   482  		// Ensure the treap snapshot still has the key.
   483  		if !treapSnap.Has(key) {
   484  			t.Fatalf("Has #%d: key %q is not in treap", i, key)
   485  		}
   486  
   487  		// Get the key from the treap snapshot and ensure it is still
   488  		// the expected value.
   489  		if gotVal := treapSnap.Get(key); !bytes.Equal(gotVal, key) {
   490  			t.Fatalf("Get #%d: unexpected value - got %x, want %x",
   491  				i, gotVal, key)
   492  		}
   493  
   494  		// Ensure the expected size is reported.
   495  		if gotSize := treapSnap.Size(); gotSize != expectedSize {
   496  			t.Fatalf("Size #%d: unexpected byte size - got %d, "+
   497  				"want %d", i, gotSize, expectedSize)
   498  		}
   499  		expectedSize -= (nodeFieldsSize + 8)
   500  	}
   501  }