+++ /dev/null
-// Copyright (c) 2015-2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package treap
-
-import (
- "bytes"
- "encoding/binary"
- "testing"
-)
-
-// TestMutableIterator ensures that the general behavior of mutable treap
-// iterators is as expected including tests for first, last, ordered and reverse
-// ordered iteration, limiting the range, seeking, and initially unpositioned.
-func TestMutableIterator(t *testing.T) {
- t.Parallel()
-
- tests := []struct {
- numKeys int
- step int
- startKey []byte
- limitKey []byte
- expectedFirst []byte
- expectedLast []byte
- seekKey []byte
- expectedSeek []byte
- }{
- // No range limits. Values are the set (0, 1, 2, ..., 49).
- // Seek existing value.
- {
- numKeys: 50,
- step: 1,
- expectedFirst: serializeUint32(0),
- expectedLast: serializeUint32(49),
- seekKey: serializeUint32(12),
- expectedSeek: serializeUint32(12),
- },
-
- // Limited to range [24, end]. Values are the set
- // (0, 2, 4, ..., 48). Seek value that doesn't exist and is
- // greater than largest existing key.
- {
- numKeys: 50,
- step: 2,
- startKey: serializeUint32(24),
- expectedFirst: serializeUint32(24),
- expectedLast: serializeUint32(48),
- seekKey: serializeUint32(49),
- expectedSeek: nil,
- },
-
- // Limited to range [start, 25). Values are the set
- // (0, 3, 6, ..., 48). Seek value that doesn't exist but is
- // before an existing value within the range.
- {
- numKeys: 50,
- step: 3,
- limitKey: serializeUint32(25),
- expectedFirst: serializeUint32(0),
- expectedLast: serializeUint32(24),
- seekKey: serializeUint32(17),
- expectedSeek: serializeUint32(18),
- },
-
- // Limited to range [10, 21). Values are the set
- // (0, 4, ..., 48). Seek value that exists, but is before the
- // minimum allowed range.
- {
- numKeys: 50,
- step: 4,
- startKey: serializeUint32(10),
- limitKey: serializeUint32(21),
- expectedFirst: serializeUint32(12),
- expectedLast: serializeUint32(20),
- seekKey: serializeUint32(4),
- expectedSeek: nil,
- },
-
- // Limited by prefix {0,0,0}, range [{0,0,0}, {0,0,1}).
- // Since it's a bytewise compare, {0,0,0,...} < {0,0,1}.
- // Seek existing value within the allowed range.
- {
- numKeys: 300,
- step: 1,
- startKey: []byte{0x00, 0x00, 0x00},
- limitKey: []byte{0x00, 0x00, 0x01},
- expectedFirst: serializeUint32(0),
- expectedLast: serializeUint32(255),
- seekKey: serializeUint32(100),
- expectedSeek: serializeUint32(100),
- },
- }
-
-testLoop:
- for i, test := range tests {
- // Insert a bunch of keys.
- testTreap := NewMutable()
- for i := 0; i < test.numKeys; i += test.step {
- key := serializeUint32(uint32(i))
- testTreap.Put(key, key)
- }
-
- // Create new iterator limited by the test params.
- iter := testTreap.Iterator(test.startKey, test.limitKey)
-
- // Ensure the first item is accurate.
- hasFirst := iter.First()
- if !hasFirst && test.expectedFirst != nil {
- t.Errorf("First #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey := iter.Key()
- if !bytes.Equal(gotKey, test.expectedFirst) {
- t.Errorf("First.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedFirst)
- continue
- }
- gotVal := iter.Value()
- if !bytes.Equal(gotVal, test.expectedFirst) {
- t.Errorf("First.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedFirst)
- continue
- }
-
- // Ensure the iterator gives the expected items in order.
- curNum := binary.BigEndian.Uint32(test.expectedFirst)
- for iter.Next() {
- curNum += uint32(test.step)
-
- // Ensure key is as expected.
- gotKey := iter.Key()
- expectedKey := serializeUint32(curNum)
- if !bytes.Equal(gotKey, expectedKey) {
- t.Errorf("iter.Key #%d (%d): unexpected key - "+
- "got %x, want %x", i, curNum, gotKey,
- expectedKey)
- continue testLoop
- }
-
- // Ensure value is as expected.
- gotVal := iter.Value()
- if !bytes.Equal(gotVal, expectedKey) {
- t.Errorf("iter.Value #%d (%d): unexpected "+
- "value - got %x, want %x", i, curNum,
- gotVal, expectedKey)
- continue testLoop
- }
- }
-
- // Ensure iterator is exhausted.
- if iter.Valid() {
- t.Errorf("Valid #%d: iterator should be exhausted", i)
- continue
- }
-
- // Ensure the last item is accurate.
- hasLast := iter.Last()
- if !hasLast && test.expectedLast != nil {
- t.Errorf("Last #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedLast) {
- t.Errorf("Last.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedLast)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedLast) {
- t.Errorf("Last.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedLast)
- continue
- }
-
- // Ensure the iterator gives the expected items in reverse
- // order.
- curNum = binary.BigEndian.Uint32(test.expectedLast)
- for iter.Prev() {
- curNum -= uint32(test.step)
-
- // Ensure key is as expected.
- gotKey := iter.Key()
- expectedKey := serializeUint32(curNum)
- if !bytes.Equal(gotKey, expectedKey) {
- t.Errorf("iter.Key #%d (%d): unexpected key - "+
- "got %x, want %x", i, curNum, gotKey,
- expectedKey)
- continue testLoop
- }
-
- // Ensure value is as expected.
- gotVal := iter.Value()
- if !bytes.Equal(gotVal, expectedKey) {
- t.Errorf("iter.Value #%d (%d): unexpected "+
- "value - got %x, want %x", i, curNum,
- gotVal, expectedKey)
- continue testLoop
- }
- }
-
- // Ensure iterator is exhausted.
- if iter.Valid() {
- t.Errorf("Valid #%d: iterator should be exhausted", i)
- continue
- }
-
- // Seek to the provided key.
- seekValid := iter.Seek(test.seekKey)
- if !seekValid && test.expectedSeek != nil {
- t.Errorf("Seek #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedSeek) {
- t.Errorf("Seek.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedSeek)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedSeek) {
- t.Errorf("Seek.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedSeek)
- continue
- }
-
- // Recreate the iterator and ensure calling Next on it before it
- // has been positioned gives the first element.
- iter = testTreap.Iterator(test.startKey, test.limitKey)
- hasNext := iter.Next()
- if !hasNext && test.expectedFirst != nil {
- t.Errorf("Next #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedFirst) {
- t.Errorf("Next.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedFirst)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedFirst) {
- t.Errorf("Next.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedFirst)
- continue
- }
-
- // Recreate the iterator and ensure calling Prev on it before it
- // has been positioned gives the first element.
- iter = testTreap.Iterator(test.startKey, test.limitKey)
- hasPrev := iter.Prev()
- if !hasPrev && test.expectedLast != nil {
- t.Errorf("Prev #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedLast) {
- t.Errorf("Prev.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedLast)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedLast) {
- t.Errorf("Next.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedLast)
- continue
- }
- }
-}
-
-// TestMutableEmptyIterator ensures that the various functions behave as
-// expected when a mutable treap is empty.
-func TestMutableEmptyIterator(t *testing.T) {
- t.Parallel()
-
- // Create iterator against empty treap.
- testTreap := NewMutable()
- iter := testTreap.Iterator(nil, nil)
-
- // Ensure Valid on empty iterator reports it as exhausted.
- if iter.Valid() {
- t.Fatal("Valid: iterator should be exhausted")
- }
-
- // Ensure First and Last on empty iterator report it as exhausted.
- if iter.First() {
- t.Fatal("First: iterator should be exhausted")
- }
- if iter.Last() {
- t.Fatal("Last: iterator should be exhausted")
- }
-
- // Ensure Next and Prev on empty iterator report it as exhausted.
- if iter.Next() {
- t.Fatal("Next: iterator should be exhausted")
- }
- if iter.Prev() {
- t.Fatal("Prev: iterator should be exhausted")
- }
-
- // Ensure Key and Value on empty iterator are nil.
- if gotKey := iter.Key(); gotKey != nil {
- t.Fatalf("Key: should be nil - got %q", gotKey)
- }
- if gotVal := iter.Value(); gotVal != nil {
- t.Fatalf("Value: should be nil - got %q", gotVal)
- }
-
- // Ensure Next and Prev report exhausted after forcing a reseek on an
- // empty iterator.
- iter.ForceReseek()
- if iter.Next() {
- t.Fatal("Next: iterator should be exhausted")
- }
- iter.ForceReseek()
- if iter.Prev() {
- t.Fatal("Prev: iterator should be exhausted")
- }
-}
-
-// TestIteratorUpdates ensures that issuing a call to ForceReseek on an iterator
-// that had the underlying mutable treap updated works as expected.
-func TestIteratorUpdates(t *testing.T) {
- t.Parallel()
-
- // Create a new treap with various values inserted in no particular
- // order. The resulting keys are the set (2, 4, 7, 11, 18, 25).
- testTreap := NewMutable()
- testTreap.Put(serializeUint32(7), nil)
- testTreap.Put(serializeUint32(2), nil)
- testTreap.Put(serializeUint32(18), nil)
- testTreap.Put(serializeUint32(11), nil)
- testTreap.Put(serializeUint32(25), nil)
- testTreap.Put(serializeUint32(4), nil)
-
- // Create an iterator against the treap with a range that excludes the
- // lowest and highest entries. The limited set is then (4, 7, 11, 18)
- iter := testTreap.Iterator(serializeUint32(3), serializeUint32(25))
-
- // Delete a key from the middle of the range and notify the iterator to
- // force a reseek.
- testTreap.Delete(serializeUint32(11))
- iter.ForceReseek()
-
- // Ensure that calling Next on the iterator after the forced reseek
- // gives the expected key. The limited set of keys at this point is
- // (4, 7, 18) and the iterator has not yet been positioned.
- if !iter.Next() {
- t.Fatal("ForceReseek.Next: unexpected exhausted iterator")
- }
- wantKey := serializeUint32(4)
- gotKey := iter.Key()
- if !bytes.Equal(gotKey, wantKey) {
- t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x",
- gotKey, wantKey)
- }
-
- // Delete the key the iterator is currently position at and notify the
- // iterator to force a reseek.
- testTreap.Delete(serializeUint32(4))
- iter.ForceReseek()
-
- // Ensure that calling Next on the iterator after the forced reseek
- // gives the expected key. The limited set of keys at this point is
- // (7, 18) and the iterator is positioned at a deleted entry before 7.
- if !iter.Next() {
- t.Fatal("ForceReseek.Next: unexpected exhausted iterator")
- }
- wantKey = serializeUint32(7)
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, wantKey) {
- t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x",
- gotKey, wantKey)
- }
-
- // Add a key before the current key the iterator is position at and
- // notify the iterator to force a reseek.
- testTreap.Put(serializeUint32(4), nil)
- iter.ForceReseek()
-
- // Ensure that calling Prev on the iterator after the forced reseek
- // gives the expected key. The limited set of keys at this point is
- // (4, 7, 18) and the iterator is positioned at 7.
- if !iter.Prev() {
- t.Fatal("ForceReseek.Prev: unexpected exhausted iterator")
- }
- wantKey = serializeUint32(4)
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, wantKey) {
- t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x",
- gotKey, wantKey)
- }
-
- // Delete the next key the iterator would ordinarily move to then notify
- // the iterator to force a reseek.
- testTreap.Delete(serializeUint32(7))
- iter.ForceReseek()
-
- // Ensure that calling Next on the iterator after the forced reseek
- // gives the expected key. The limited set of keys at this point is
- // (4, 18) and the iterator is positioned at 4.
- if !iter.Next() {
- t.Fatal("ForceReseek.Next: unexpected exhausted iterator")
- }
- wantKey = serializeUint32(18)
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, wantKey) {
- t.Fatalf("ForceReseek.Key: unexpected key - got %x, want %x",
- gotKey, wantKey)
- }
-}
-
-// TestImmutableIterator ensures that the general behavior of immutable treap
-// iterators is as expected including tests for first, last, ordered and reverse
-// ordered iteration, limiting the range, seeking, and initially unpositioned.
-func TestImmutableIterator(t *testing.T) {
- t.Parallel()
-
- tests := []struct {
- numKeys int
- step int
- startKey []byte
- limitKey []byte
- expectedFirst []byte
- expectedLast []byte
- seekKey []byte
- expectedSeek []byte
- }{
- // No range limits. Values are the set (0, 1, 2, ..., 49).
- // Seek existing value.
- {
- numKeys: 50,
- step: 1,
- expectedFirst: serializeUint32(0),
- expectedLast: serializeUint32(49),
- seekKey: serializeUint32(12),
- expectedSeek: serializeUint32(12),
- },
-
- // Limited to range [24, end]. Values are the set
- // (0, 2, 4, ..., 48). Seek value that doesn't exist and is
- // greater than largest existing key.
- {
- numKeys: 50,
- step: 2,
- startKey: serializeUint32(24),
- expectedFirst: serializeUint32(24),
- expectedLast: serializeUint32(48),
- seekKey: serializeUint32(49),
- expectedSeek: nil,
- },
-
- // Limited to range [start, 25). Values are the set
- // (0, 3, 6, ..., 48). Seek value that doesn't exist but is
- // before an existing value within the range.
- {
- numKeys: 50,
- step: 3,
- limitKey: serializeUint32(25),
- expectedFirst: serializeUint32(0),
- expectedLast: serializeUint32(24),
- seekKey: serializeUint32(17),
- expectedSeek: serializeUint32(18),
- },
-
- // Limited to range [10, 21). Values are the set
- // (0, 4, ..., 48). Seek value that exists, but is before the
- // minimum allowed range.
- {
- numKeys: 50,
- step: 4,
- startKey: serializeUint32(10),
- limitKey: serializeUint32(21),
- expectedFirst: serializeUint32(12),
- expectedLast: serializeUint32(20),
- seekKey: serializeUint32(4),
- expectedSeek: nil,
- },
-
- // Limited by prefix {0,0,0}, range [{0,0,0}, {0,0,1}).
- // Since it's a bytewise compare, {0,0,0,...} < {0,0,1}.
- // Seek existing value within the allowed range.
- {
- numKeys: 300,
- step: 1,
- startKey: []byte{0x00, 0x00, 0x00},
- limitKey: []byte{0x00, 0x00, 0x01},
- expectedFirst: serializeUint32(0),
- expectedLast: serializeUint32(255),
- seekKey: serializeUint32(100),
- expectedSeek: serializeUint32(100),
- },
- }
-
-testLoop:
- for i, test := range tests {
- // Insert a bunch of keys.
- testTreap := NewImmutable()
- for i := 0; i < test.numKeys; i += test.step {
- key := serializeUint32(uint32(i))
- testTreap = testTreap.Put(key, key)
- }
-
- // Create new iterator limited by the test params.
- iter := testTreap.Iterator(test.startKey, test.limitKey)
-
- // Ensure the first item is accurate.
- hasFirst := iter.First()
- if !hasFirst && test.expectedFirst != nil {
- t.Errorf("First #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey := iter.Key()
- if !bytes.Equal(gotKey, test.expectedFirst) {
- t.Errorf("First.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedFirst)
- continue
- }
- gotVal := iter.Value()
- if !bytes.Equal(gotVal, test.expectedFirst) {
- t.Errorf("First.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedFirst)
- continue
- }
-
- // Ensure the iterator gives the expected items in order.
- curNum := binary.BigEndian.Uint32(test.expectedFirst)
- for iter.Next() {
- curNum += uint32(test.step)
-
- // Ensure key is as expected.
- gotKey := iter.Key()
- expectedKey := serializeUint32(curNum)
- if !bytes.Equal(gotKey, expectedKey) {
- t.Errorf("iter.Key #%d (%d): unexpected key - "+
- "got %x, want %x", i, curNum, gotKey,
- expectedKey)
- continue testLoop
- }
-
- // Ensure value is as expected.
- gotVal := iter.Value()
- if !bytes.Equal(gotVal, expectedKey) {
- t.Errorf("iter.Value #%d (%d): unexpected "+
- "value - got %x, want %x", i, curNum,
- gotVal, expectedKey)
- continue testLoop
- }
- }
-
- // Ensure iterator is exhausted.
- if iter.Valid() {
- t.Errorf("Valid #%d: iterator should be exhausted", i)
- continue
- }
-
- // Ensure the last item is accurate.
- hasLast := iter.Last()
- if !hasLast && test.expectedLast != nil {
- t.Errorf("Last #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedLast) {
- t.Errorf("Last.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedLast)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedLast) {
- t.Errorf("Last.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedLast)
- continue
- }
-
- // Ensure the iterator gives the expected items in reverse
- // order.
- curNum = binary.BigEndian.Uint32(test.expectedLast)
- for iter.Prev() {
- curNum -= uint32(test.step)
-
- // Ensure key is as expected.
- gotKey := iter.Key()
- expectedKey := serializeUint32(curNum)
- if !bytes.Equal(gotKey, expectedKey) {
- t.Errorf("iter.Key #%d (%d): unexpected key - "+
- "got %x, want %x", i, curNum, gotKey,
- expectedKey)
- continue testLoop
- }
-
- // Ensure value is as expected.
- gotVal := iter.Value()
- if !bytes.Equal(gotVal, expectedKey) {
- t.Errorf("iter.Value #%d (%d): unexpected "+
- "value - got %x, want %x", i, curNum,
- gotVal, expectedKey)
- continue testLoop
- }
- }
-
- // Ensure iterator is exhausted.
- if iter.Valid() {
- t.Errorf("Valid #%d: iterator should be exhausted", i)
- continue
- }
-
- // Seek to the provided key.
- seekValid := iter.Seek(test.seekKey)
- if !seekValid && test.expectedSeek != nil {
- t.Errorf("Seek #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedSeek) {
- t.Errorf("Seek.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedSeek)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedSeek) {
- t.Errorf("Seek.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedSeek)
- continue
- }
-
- // Recreate the iterator and ensure calling Next on it before it
- // has been positioned gives the first element.
- iter = testTreap.Iterator(test.startKey, test.limitKey)
- hasNext := iter.Next()
- if !hasNext && test.expectedFirst != nil {
- t.Errorf("Next #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedFirst) {
- t.Errorf("Next.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedFirst)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedFirst) {
- t.Errorf("Next.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedFirst)
- continue
- }
-
- // Recreate the iterator and ensure calling Prev on it before it
- // has been positioned gives the first element.
- iter = testTreap.Iterator(test.startKey, test.limitKey)
- hasPrev := iter.Prev()
- if !hasPrev && test.expectedLast != nil {
- t.Errorf("Prev #%d: unexpected exhausted iterator", i)
- continue
- }
- gotKey = iter.Key()
- if !bytes.Equal(gotKey, test.expectedLast) {
- t.Errorf("Prev.Key #%d: unexpected key - got %x, "+
- "want %x", i, gotKey, test.expectedLast)
- continue
- }
- gotVal = iter.Value()
- if !bytes.Equal(gotVal, test.expectedLast) {
- t.Errorf("Next.Value #%d: unexpected value - got %x, "+
- "want %x", i, gotVal, test.expectedLast)
- continue
- }
- }
-}
-
-// TestImmutableEmptyIterator ensures that the various functions behave as
-// expected when an immutable treap is empty.
-func TestImmutableEmptyIterator(t *testing.T) {
- t.Parallel()
-
- // Create iterator against empty treap.
- testTreap := NewImmutable()
- iter := testTreap.Iterator(nil, nil)
-
- // Ensure Valid on empty iterator reports it as exhausted.
- if iter.Valid() {
- t.Fatal("Valid: iterator should be exhausted")
- }
-
- // Ensure First and Last on empty iterator report it as exhausted.
- if iter.First() {
- t.Fatal("First: iterator should be exhausted")
- }
- if iter.Last() {
- t.Fatal("Last: iterator should be exhausted")
- }
-
- // Ensure Next and Prev on empty iterator report it as exhausted.
- if iter.Next() {
- t.Fatal("Next: iterator should be exhausted")
- }
- if iter.Prev() {
- t.Fatal("Prev: iterator should be exhausted")
- }
-
- // Ensure Key and Value on empty iterator are nil.
- if gotKey := iter.Key(); gotKey != nil {
- t.Fatalf("Key: should be nil - got %q", gotKey)
- }
- if gotVal := iter.Value(); gotVal != nil {
- t.Fatalf("Value: should be nil - got %q", gotVal)
- }
-
- // Ensure calling ForceReseek on an immutable treap iterator does not
- // cause any issues since it only applies to mutable treap iterators.
- iter.ForceReseek()
- if iter.Next() {
- t.Fatal("Next: iterator should be exhausted")
- }
- iter.ForceReseek()
- if iter.Prev() {
- t.Fatal("Prev: iterator should be exhausted")
- }
-}