tests
This commit is contained in:
parent
0d0bdcbe45
commit
1b3399a16f
1 changed files with 81 additions and 134 deletions
215
src/btree.rs
215
src/btree.rs
|
|
@ -191,164 +191,111 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::record::Record;
|
|
||||||
use crate::storage::InMemoryStorage;
|
use crate::storage::InMemoryStorage;
|
||||||
|
|
||||||
// Helper function to generate a large number of keys and values
|
use proptest::prelude::*;
|
||||||
fn generate_large_dataset(size: usize) -> Vec<Record> {
|
use proptest::proptest;
|
||||||
let keys: Vec<i32> = (1..=size as i32).collect();
|
|
||||||
let values: Vec<Record> = keys.iter().map(|&k| [k; 7]).collect();
|
use std::collections::BTreeMap;
|
||||||
values
|
|
||||||
|
fn arb_record() -> impl Strategy<Value = Record> {
|
||||||
|
prop::array::uniform7(any::<i32>())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to generate random keys and values
|
fn arb_key() -> impl Strategy<Value = i32> {
|
||||||
fn generate_random_dataset(size: usize) -> Vec<Record> {
|
any::<i32>()
|
||||||
use rand::Rng;
|
|
||||||
let mut rng = rand::rng();
|
|
||||||
let keys: Vec<i32> = (0..size).map(|_| rng.random_range(1..10000)).collect();
|
|
||||||
let values: Vec<Record> = keys.iter().map(|&k| [k; 7]).collect();
|
|
||||||
values
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[derive(Debug, Clone)]
|
||||||
fn test_initialization() {
|
enum Op {
|
||||||
let storage = InMemoryStorage::new();
|
Insert(Record),
|
||||||
let tree = BPlusTree::open(storage);
|
Find(i32),
|
||||||
assert_eq!(tree.root_loc, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn arb_op() -> impl Strategy<Value = Op> {
|
||||||
fn test_insert_and_find() {
|
prop_oneof![
|
||||||
let storage = InMemoryStorage::new();
|
arb_record().prop_map(Op::Insert),
|
||||||
let mut tree = BPlusTree::open(storage);
|
arb_key().prop_map(Op::Find),
|
||||||
let value = [1, 1, 2, 3, 4, 5, 6]; // Example Record as [i32; 6]
|
]
|
||||||
tree.insert(value);
|
|
||||||
assert_eq!(tree.find(value[0]), Some(value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn arb_ops() -> impl Strategy<Value = Vec<Op>> {
|
||||||
fn test_multiple_inserts_and_finds() {
|
// Long enough to trigger many splits, but still fast
|
||||||
let storage = InMemoryStorage::new();
|
prop::collection::vec(arb_op(), 1..500)
|
||||||
let mut tree = BPlusTree::open(storage);
|
}
|
||||||
let values = [
|
|
||||||
[1, 1, 2, 3, 4, 5, 6],
|
proptest! {
|
||||||
[2, 7, 8, 9, 10, 11, 12],
|
#![proptest_config(ProptestConfig {
|
||||||
[3, 13, 14, 15, 16, 17, 18],
|
cases: 200,
|
||||||
[4, 19, 20, 21, 22, 23, 24],
|
.. ProptestConfig::default()
|
||||||
[5, 25, 26, 27, 28, 29, 30],
|
})]
|
||||||
];
|
|
||||||
for rec in values {
|
#[test]
|
||||||
tree.insert(rec);
|
fn prop_bplustree_matches_btreemap(ops in arb_ops()) {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
|
||||||
|
let mut model = BTreeMap::<i32, Record>::new();
|
||||||
|
|
||||||
|
for op in ops {
|
||||||
|
match op {
|
||||||
|
Op::Insert(record) => {
|
||||||
|
let key = record[0];
|
||||||
|
tree.insert(record);
|
||||||
|
model.insert(key, record);
|
||||||
|
}
|
||||||
|
|
||||||
|
Op::Find(key) => {
|
||||||
|
let tree_res = tree.find(key);
|
||||||
|
let model_res = model.get(&key).copied();
|
||||||
|
prop_assert_eq!(tree_res, model_res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for rec in values {
|
}
|
||||||
assert_eq!(tree.find(rec[0]), Some(rec));
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn prop_all_inserted_keys_are_findable(records in prop::collection::vec(arb_record(), 0..1000)) {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let mut model = BTreeMap::<i32, Record>::new();
|
||||||
|
|
||||||
|
for rec in records {
|
||||||
|
tree.insert(rec);
|
||||||
|
model.insert(rec[0], rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (key, value) in model {
|
||||||
|
prop_assert_eq!(tree.find(key), Some(value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_internal_split() {
|
fn sanity_single_insert() {
|
||||||
let storage = InMemoryStorage::new();
|
|
||||||
let mut tree = BPlusTree::open(storage);
|
|
||||||
let values = [
|
|
||||||
[1, 1, 2, 3, 4, 5, 6],
|
|
||||||
[2, 7, 8, 9, 10, 11, 12],
|
|
||||||
[3, 13, 14, 15, 16, 17, 18],
|
|
||||||
[4, 19, 20, 21, 22, 23, 24],
|
|
||||||
[5, 25, 26, 27, 28, 29, 30],
|
|
||||||
[6, 31, 32, 33, 34, 35, 36],
|
|
||||||
[7, 37, 38, 39, 40, 41, 42],
|
|
||||||
[8, 43, 44, 45, 46, 47, 48],
|
|
||||||
[9, 49, 50, 51, 52, 53, 54],
|
|
||||||
[10, 55, 56, 57, 58, 59, 60],
|
|
||||||
[11, 61, 62, 63, 64, 65, 66],
|
|
||||||
];
|
|
||||||
for rec in values {
|
|
||||||
tree.insert(rec);
|
|
||||||
}
|
|
||||||
for rec in values {
|
|
||||||
assert_eq!(tree.find(rec[0]), Some(rec));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_update() {
|
|
||||||
let storage = InMemoryStorage::new();
|
|
||||||
let mut tree = BPlusTree::open(storage);
|
|
||||||
let key = 1;
|
|
||||||
let initial_value = [key, 1, 2, 3, 4, 5, 6];
|
|
||||||
let updated_value = [key, 7, 8, 9, 10, 11, 12];
|
|
||||||
tree.insert(initial_value);
|
|
||||||
assert_eq!(tree.find(key), Some(initial_value));
|
|
||||||
tree.insert(updated_value);
|
|
||||||
assert_eq!(tree.find(key), Some(updated_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_non_existent_key() {
|
|
||||||
let storage = InMemoryStorage::new();
|
|
||||||
let mut tree = BPlusTree::open(storage);
|
|
||||||
assert_eq!(tree.find(999), None); // Assuming 999 is not in the tree
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_out_of_order_inserts() {
|
|
||||||
let storage = InMemoryStorage::new();
|
|
||||||
let mut tree = BPlusTree::open(storage);
|
|
||||||
let values = [
|
|
||||||
[5, 1, 2, 3, 4, 5, 6],
|
|
||||||
[3, 7, 8, 9, 10, 11, 12],
|
|
||||||
[1, 13, 14, 15, 16, 17, 18],
|
|
||||||
[4, 19, 20, 21, 22, 23, 24],
|
|
||||||
[2, 25, 26, 27, 28, 29, 30],
|
|
||||||
];
|
|
||||||
for rec in values {
|
|
||||||
tree.insert(rec);
|
|
||||||
}
|
|
||||||
for rec in values {
|
|
||||||
assert_eq!(tree.find(rec[0]), Some(rec));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_large_number_of_inserts() {
|
|
||||||
let storage = InMemoryStorage::new();
|
|
||||||
let mut tree = BPlusTree::open(storage);
|
|
||||||
let num_keys = 100000;
|
|
||||||
let values = generate_large_dataset(num_keys);
|
|
||||||
for rec in &values {
|
|
||||||
tree.insert(*rec);
|
|
||||||
}
|
|
||||||
for rec in &values {
|
|
||||||
assert_eq!(tree.find(rec[0]), Some(*rec));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_boundary_values() {
|
|
||||||
let storage = InMemoryStorage::new();
|
let storage = InMemoryStorage::new();
|
||||||
let mut tree = BPlusTree::open(storage);
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
|
||||||
let min_value = [i32::MIN; 7];
|
let rec = [42, 1, 2, 3, 4, 5, 6];
|
||||||
let max_value = [i32::MAX; 7];
|
tree.insert(rec);
|
||||||
|
|
||||||
tree.insert(min_value);
|
assert_eq!(tree.find(42), Some(rec));
|
||||||
tree.insert(max_value);
|
assert_eq!(tree.find(7), None);
|
||||||
|
|
||||||
assert_eq!(tree.find(min_value[0]), Some(min_value));
|
|
||||||
assert_eq!(tree.find(max_value[0]), Some(max_value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_random_insertions() {
|
fn sanity_update_overwrites_value() {
|
||||||
let storage = InMemoryStorage::new();
|
let storage = InMemoryStorage::new();
|
||||||
let mut tree = BPlusTree::open(storage);
|
let mut tree = BPlusTree::open(storage);
|
||||||
let values = generate_random_dataset(10000);
|
|
||||||
|
|
||||||
for rec in &values {
|
let r1 = [1, 1, 1, 1, 1, 1, 1];
|
||||||
tree.insert(*rec);
|
let r2 = [1, 9, 9, 9, 9, 9, 9];
|
||||||
}
|
|
||||||
for rec in &values {
|
tree.insert(r1);
|
||||||
assert_eq!(tree.find(rec[0]), Some(*rec));
|
tree.insert(r2);
|
||||||
}
|
|
||||||
|
assert_eq!(tree.find(1), Some(r2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue