// Ensure that a C cursor can seek over branches and leafs. func TestCursor_Seek_Deep(t *testing.T) { withDB(func(db *bolt.DB) { pgsz := db.Info().PageSize / 10 assert.True(t, pgsz > 100) db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucket([]byte("widgets")) for i := 1; i < 1000; i++ { kv := []byte(fmt.Sprintf("%0*d", pgsz, i*10)) b.Put(kv, kv) } return nil }) db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) s := b.Stats() assert.True(t, s.Depth > 3) c := NewCursor(b) // Exact match should go to the key. seek := fmt.Sprintf("%0*d", pgsz, 5000) k, v, _ := c.Seek([]byte(seek)) assert.Equal(t, seek, string(k)) assert.Equal(t, seek, string(v)) // Inexact match should go to the next key. seek = fmt.Sprintf("%0*d", pgsz, 7495) found := fmt.Sprintf("%0*d", pgsz, 7500) k, v, _ = c.Seek([]byte(seek)) assert.Equal(t, found, string(k)) assert.Equal(t, found, string(v)) // Low key should go to the first key. seek = fmt.Sprintf("%0*d", pgsz, 0) found = fmt.Sprintf("%0*d", pgsz, 10) k, v, _ = c.Seek([]byte(seek)) assert.Equal(t, found, string(k)) assert.Equal(t, found, string(v)) // High key should return no key. seek = fmt.Sprintf("%0*d", pgsz, 40000) k, v, _ = c.Seek([]byte(seek)) assert.Equal(t, "", string(k)) assert.Equal(t, "", string(v)) // Exact match in the middle of a branch page. seek = fmt.Sprintf("%0*d", pgsz, 4170) k, v, _ = c.Seek([]byte(seek)) assert.Equal(t, seek, string(k)) assert.Equal(t, seek, string(v)) return nil }) }) }
// Ensure that a C cursor can seek over branches and leafs. func TestCursor_Seek_Large(t *testing.T) { withDB(func(db *bolt.DB) { db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucket([]byte("widgets")) for i := 1; i < 1000; i++ { b.Put([]byte(fmt.Sprintf("%05d\000", i*10)), []byte(fmt.Sprintf("%020d", i*10))) } return nil }) db.View(func(tx *bolt.Tx) error { c := NewCursor(tx.Bucket([]byte("widgets"))) // Exact match should go to the key. k, v, _ := c.Seek([]byte("05000\000")) assert.Equal(t, "05000\000", string(k)) assert.Equal(t, fmt.Sprintf("%020d", 5000), string(v)) // Inexact match should go to the next key. k, v, _ = c.Seek([]byte("07495\000")) assert.Equal(t, "07500\000", string(k)) assert.Equal(t, fmt.Sprintf("%020d", 7500), string(v)) // Low key should go to the first key. k, v, _ = c.Seek([]byte("00000\000")) assert.Equal(t, "00010\000", string(k)) assert.Equal(t, fmt.Sprintf("%020d", 10), string(v)) // High key should return no key. k, v, _ = c.Seek([]byte("40000\000")) assert.Equal(t, "", string(k)) assert.Equal(t, "", string(v)) return nil }) }) }
// Ensure that a C cursor handles empty bucket properly func TestCursor_Empty(t *testing.T) { withDB(func(db *bolt.DB) { db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) return nil }) db.View(func(tx *bolt.Tx) error { c := NewCursor(tx.Bucket([]byte("widgets"))) key, value := c.First() assert.Nil(t, key) assert.Nil(t, value) key, value = c.Next() assert.Nil(t, key) assert.Nil(t, value) key, value, flags := c.Seek([]byte("bar")) assert.Nil(t, key) assert.Nil(t, value) assert.Equal(t, 0, flags) return nil }) }) }
// Ensure that a C cursor can seek to the appropriate keys. func TestCursor_Seek(t *testing.T) { withDB(func(db *bolt.DB) { db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) assert.NoError(t, b.Put([]byte("foo"), []byte("0001"))) assert.NoError(t, b.Put([]byte("bar"), []byte("0002"))) assert.NoError(t, b.Put([]byte("baz"), []byte("0003"))) _, err = b.CreateBucket([]byte("bkt")) assert.NoError(t, err) return nil }) db.View(func(tx *bolt.Tx) error { c := NewCursor(tx.Bucket([]byte("widgets"))) // Exact match should go to the key. k, v, flags := c.Seek([]byte("bar")) assert.Equal(t, "bar", string(k)) assert.Equal(t, "0002", string(v)) assert.Equal(t, 0, flags) // Inexact match should go to the next key. k, v, flags = c.Seek([]byte("bas")) assert.Equal(t, "baz", string(k)) assert.Equal(t, "0003", string(v)) assert.Equal(t, 0, flags) // Inexact match with smaller db key should go to the next key. k, v, flags = c.Seek([]byte("barrrr")) assert.Equal(t, "baz", string(k)) assert.Equal(t, "0003", string(v)) assert.Equal(t, 0, flags) // Inexact match with smaller seek key should go to the next key. k, v, flags = c.Seek([]byte("ba")) assert.Equal(t, "bar", string(k)) assert.Equal(t, "0002", string(v)) assert.Equal(t, 0, flags) // Low key should go to the first key. k, v, flags = c.Seek([]byte("")) assert.Equal(t, "bar", string(k)) assert.Equal(t, "0002", string(v)) assert.Equal(t, 0, flags) // High key should return no key. k, v, flags = c.Seek([]byte("zzz")) assert.Equal(t, "", string(k)) assert.Equal(t, "", string(v)) assert.Equal(t, 0, flags) // Buckets should return their key but no value. k, v, flags = c.Seek([]byte("bkt")) assert.Equal(t, []byte("bkt"), k) assert.True(t, len(v) > 0) assert.Equal(t, 1, flags) // bucketLeafFlag return nil }) }) }