github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/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 }