tests
This commit is contained in:
parent
8dc0709730
commit
6da9247ab0
3 changed files with 292 additions and 1 deletions
285
src/btree.rs
285
src/btree.rs
|
|
@ -194,3 +194,288 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::record::Record;
|
||||||
|
use crate::storage::InMemoryStorage;
|
||||||
|
|
||||||
|
// Helper function to generate a large number of keys and values
|
||||||
|
fn generate_large_dataset(size: usize) -> (Vec<i32>, Vec<Record>) {
|
||||||
|
let keys: Vec<i32> = (1..=size as i32).collect();
|
||||||
|
let values: Vec<Record> = keys.iter().map(|&k| [k; 6]).collect();
|
||||||
|
(keys, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to generate random keys and values
|
||||||
|
fn generate_random_dataset(size: usize) -> (Vec<i32>, Vec<Record>) {
|
||||||
|
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; 6]).collect();
|
||||||
|
(keys, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_initialization() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let tree = BPlusTree::open(storage);
|
||||||
|
assert_eq!(tree.root_loc, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_insert_and_find() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let key = 1;
|
||||||
|
let value = [1, 2, 3, 4, 5, 6]; // Example Record as [i32; 6]
|
||||||
|
tree.insert(key, value);
|
||||||
|
assert_eq!(tree.find(key), Some(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multiple_inserts_and_finds() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let keys = [1, 2, 3, 4, 5];
|
||||||
|
let values = [
|
||||||
|
[1, 2, 3, 4, 5, 6],
|
||||||
|
[7, 8, 9, 10, 11, 12],
|
||||||
|
[13, 14, 15, 16, 17, 18],
|
||||||
|
[19, 20, 21, 22, 23, 24],
|
||||||
|
[25, 26, 27, 28, 29, 30],
|
||||||
|
];
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_leaf_split() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let keys = [1, 2, 3, 4, 5]; // Assuming MAX_KEYS is 4, this will trigger a split
|
||||||
|
let values = [
|
||||||
|
[1, 2, 3, 4, 5, 6],
|
||||||
|
[7, 8, 9, 10, 11, 12],
|
||||||
|
[13, 14, 15, 16, 17, 18],
|
||||||
|
[19, 20, 21, 22, 23, 24],
|
||||||
|
[25, 26, 27, 28, 29, 30],
|
||||||
|
];
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
// Verify that all keys can still be found after splits
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_internal_split() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
// Insert enough keys to trigger internal splits
|
||||||
|
let keys = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
let values = [
|
||||||
|
[1, 2, 3, 4, 5, 6],
|
||||||
|
[7, 8, 9, 10, 11, 12],
|
||||||
|
[13, 14, 15, 16, 17, 18],
|
||||||
|
[19, 20, 21, 22, 23, 24],
|
||||||
|
[25, 26, 27, 28, 29, 30],
|
||||||
|
[31, 32, 33, 34, 35, 36],
|
||||||
|
[37, 38, 39, 40, 41, 42],
|
||||||
|
[43, 44, 45, 46, 47, 48],
|
||||||
|
[49, 50, 51, 52, 53, 54],
|
||||||
|
[55, 56, 57, 58, 59, 60],
|
||||||
|
[61, 62, 63, 64, 65, 66],
|
||||||
|
];
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
// Verify that all keys can still be found after splits
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let key = 1;
|
||||||
|
let initial_value = [1, 2, 3, 4, 5, 6];
|
||||||
|
let updated_value = [7, 8, 9, 10, 11, 12];
|
||||||
|
tree.insert(key, initial_value);
|
||||||
|
assert_eq!(tree.find(key), Some(initial_value));
|
||||||
|
tree.insert(key, updated_value);
|
||||||
|
assert_eq!(tree.find(key), Some(updated_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_non_existent_key() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let 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 keys = [5, 3, 1, 4, 2];
|
||||||
|
let values = [
|
||||||
|
[1, 2, 3, 4, 5, 6],
|
||||||
|
[7, 8, 9, 10, 11, 12],
|
||||||
|
[13, 14, 15, 16, 17, 18],
|
||||||
|
[19, 20, 21, 22, 23, 24],
|
||||||
|
[25, 26, 27, 28, 29, 30],
|
||||||
|
];
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
// Verify that all keys can be found
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_large_number_of_inserts() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let num_keys = 100;
|
||||||
|
let keys: Vec<i32> = (1..=num_keys).collect();
|
||||||
|
let values: Vec<Record> = (1..=num_keys)
|
||||||
|
.map(|i| [i, i + 1, i + 2, i + 3, i + 4, i + 5])
|
||||||
|
.collect();
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
// Verify that all keys can be found
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_keys() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let key = 1;
|
||||||
|
let initial_value = [1, 2, 3, 4, 5, 6];
|
||||||
|
let updated_value = [7, 8, 9, 10, 11, 12];
|
||||||
|
tree.insert(key, initial_value);
|
||||||
|
assert_eq!(tree.find(key), Some(initial_value));
|
||||||
|
tree.insert(key, updated_value);
|
||||||
|
assert_eq!(tree.find(key), Some(updated_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_recursive_splitting_up_to_root() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
|
||||||
|
// Insert enough keys to cause multiple splits, including root split
|
||||||
|
let keys = (1..=20).collect::<Vec<i32>>();
|
||||||
|
let values: Vec<Record> = keys.iter().map(|&k| [k; 6]).collect();
|
||||||
|
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all keys are present
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_large_dataset() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let (keys, values) = generate_large_dataset(10000);
|
||||||
|
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all keys are present
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_boundary_values() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
|
||||||
|
// Test with minimum and maximum i32 values
|
||||||
|
let min_key = i32::MIN;
|
||||||
|
let max_key = i32::MAX;
|
||||||
|
let min_value = [i32::MIN; 6];
|
||||||
|
let max_value = [i32::MAX; 6];
|
||||||
|
|
||||||
|
tree.insert(min_key, min_value);
|
||||||
|
tree.insert(max_key, max_value);
|
||||||
|
|
||||||
|
assert_eq!(tree.find(min_key), Some(min_value));
|
||||||
|
assert_eq!(tree.find(max_key), Some(max_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sequential_insertions() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let (keys, values) = generate_large_dataset(100);
|
||||||
|
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all keys are present
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_random_insertions() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
let (keys, values) = generate_random_dataset(100);
|
||||||
|
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all keys are present
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_node_splitting_and_balance() {
|
||||||
|
let storage = InMemoryStorage::new();
|
||||||
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
|
||||||
|
// Insert keys that will cause multiple splits
|
||||||
|
let keys = (1..=50).collect::<Vec<i32>>();
|
||||||
|
let values: Vec<Record> = keys.iter().map(|&k| [k; 6]).collect();
|
||||||
|
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
tree.insert(*key, values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all keys are present and tree is balanced
|
||||||
|
for (i, key) in keys.iter().enumerate() {
|
||||||
|
assert_eq!(tree.find(*key), Some(values[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::btree::BPlusTree;
|
||||||
use crate::storage::InMemoryStorage;
|
use crate::storage::InMemoryStorage;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let storage = InMemoryStorage { nodes: Vec::new() };
|
let storage = InMemoryStorage::new();
|
||||||
let mut tree = BPlusTree::open(storage);
|
let mut tree = BPlusTree::open(storage);
|
||||||
|
|
||||||
// Insert some key-value pairs
|
// Insert some key-value pairs
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,12 @@ pub struct InMemoryStorage {
|
||||||
pub nodes: Vec<Option<Node>>,
|
pub nodes: Vec<Option<Node>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InMemoryStorage {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { nodes: Vec::new() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Storage for InMemoryStorage {
|
impl Storage for InMemoryStorage {
|
||||||
fn read_node(&self, loc: usize) -> Option<Node> {
|
fn read_node(&self, loc: usize) -> Option<Node> {
|
||||||
self.nodes.get(loc)?.clone()
|
self.nodes.get(loc)?.clone()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue