mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-08-05 15:13:06 -07:00
593 lines
13 KiB
Rust
593 lines
13 KiB
Rust
//! Generic basic operations tests for all vec types.
|
|
//!
|
|
//! These tests run against any type implementing `StoredVec`, ensuring
|
|
//! consistent behavior across BytesVec, ZeroCopyVec, PcoVec, LZ4Vec, ZstdVec, and EagerVec.
|
|
|
|
use rawdb::Database;
|
|
use tempfile::TempDir;
|
|
use vecdb::{Result, Stamp, StoredVec, Version};
|
|
|
|
// ============================================================================
|
|
// Test Setup
|
|
// ============================================================================
|
|
|
|
fn setup_db() -> Result<(Database, TempDir)> {
|
|
let temp = TempDir::new()?;
|
|
let db = Database::open(temp.path())?;
|
|
Ok((db, temp))
|
|
}
|
|
|
|
// ============================================================================
|
|
// Generic Basic Operations Tests
|
|
// ============================================================================
|
|
|
|
fn run_push_write_read<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
// Push values
|
|
for i in 0..21_u32 {
|
|
vec.push(i);
|
|
}
|
|
|
|
// Read via get before write
|
|
assert_eq!(vec.collect_range(0, 1), vec![0]);
|
|
assert_eq!(vec.collect_range(1, 2), vec![1]);
|
|
assert_eq!(vec.collect_range(2, 3), vec![2]);
|
|
assert_eq!(vec.collect_range(20, 21), vec![20]);
|
|
assert!(vec.collect_range(21, 22).is_empty());
|
|
|
|
// Write to storage
|
|
vec.write()?;
|
|
|
|
// Verify stamp
|
|
assert_eq!(vec.header().stamp(), Stamp::new(0));
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_stamp_management<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
for i in 0..21_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
|
|
// Reimport and update stamp
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
vec.mut_header().update_stamp(Stamp::new(100));
|
|
|
|
assert_eq!(vec.header().stamp(), Stamp::new(100));
|
|
|
|
// Verify data still readable
|
|
assert_eq!(vec.collect_range(0, 1), vec![0]);
|
|
assert_eq!(vec.collect_range(1, 2), vec![1]);
|
|
assert_eq!(vec.collect_range(20, 21), vec![20]);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_length_tracking<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
// Push and write
|
|
for i in 0..21_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
|
|
// Reimport and verify
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
assert_eq!(vec.stored_len(), 21);
|
|
assert_eq!(vec.pushed_len(), 0);
|
|
assert_eq!(vec.len(), 21);
|
|
|
|
// Push more
|
|
vec.push(21);
|
|
vec.push(22);
|
|
|
|
assert_eq!(vec.stored_len(), 21);
|
|
assert_eq!(vec.pushed_len(), 2);
|
|
assert_eq!(vec.len(), 23);
|
|
|
|
// Read across stored/pushed boundary
|
|
assert_eq!(vec.collect_range(20, 21), vec![20]);
|
|
assert_eq!(vec.collect_range(21, 22), vec![21]);
|
|
assert_eq!(vec.collect_range(22, 23), vec![22]);
|
|
assert!(vec.collect_range(23, 24).is_empty());
|
|
|
|
// Write and verify persistence
|
|
vec.write()?;
|
|
|
|
let vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
assert_eq!(vec.stored_len(), 23);
|
|
assert_eq!(vec.pushed_len(), 0);
|
|
assert_eq!(vec.len(), 23);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_truncate<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
// Push and write
|
|
for i in 0..23_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
|
|
// Reimport and truncate
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
vec.truncate_if_needed(14)?;
|
|
|
|
assert_eq!(vec.stored_len(), 14);
|
|
assert_eq!(vec.pushed_len(), 0);
|
|
assert_eq!(vec.len(), 14);
|
|
|
|
// Verify truncated data
|
|
assert_eq!(vec.collect_range(0, 1), vec![0]);
|
|
assert_eq!(vec.collect_range(5, 6), vec![5]);
|
|
assert_eq!(vec.collect_range(13, 14), vec![13]);
|
|
assert!(vec.collect_range(14, 15).is_empty());
|
|
assert!(vec.collect_range(20, 21).is_empty());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_collect_signed_range<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
for i in 0..15_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
|
|
// Test negative range (last 5 elements)
|
|
assert_eq!(
|
|
vec.collect_signed_range(Some(-5), None),
|
|
vec![10, 11, 12, 13, 14]
|
|
);
|
|
|
|
// Test positive range
|
|
assert_eq!(
|
|
vec.collect_signed_range(Some(5), Some(10)),
|
|
vec![5, 6, 7, 8, 9]
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_iter_last<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
for i in 0..15_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
|
|
// Push one more without writing
|
|
vec.push(15);
|
|
|
|
let last = vec.collect_range(vec.len() - 1, vec.len());
|
|
assert_eq!(last[0], 15);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_reset<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
for i in 0..15_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
|
|
// Reset
|
|
vec.reset()?;
|
|
|
|
assert_eq!(vec.pushed_len(), 0);
|
|
assert_eq!(vec.stored_len(), 0);
|
|
assert_eq!(vec.len(), 0);
|
|
|
|
// Push new data after reset
|
|
for i in 0..21_u32 {
|
|
vec.push(i);
|
|
}
|
|
|
|
assert_eq!(vec.pushed_len(), 21);
|
|
assert_eq!(vec.stored_len(), 0);
|
|
assert_eq!(vec.len(), 21);
|
|
|
|
// Verify new data
|
|
assert_eq!(vec.collect_range(0, 1), vec![0]);
|
|
assert_eq!(vec.collect_range(20, 21), vec![20]);
|
|
assert!(vec.collect_range(21, 22).is_empty());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_collect<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
|
|
for i in 0..10_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
|
|
assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn run_persistence_across_reopen<V>() -> Result<()>
|
|
where
|
|
V: StoredVec<I = usize, T = u32>,
|
|
{
|
|
let (db, _temp) = setup_db()?;
|
|
|
|
// Write data
|
|
{
|
|
let mut vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
for i in 0..100_u32 {
|
|
vec.push(i);
|
|
}
|
|
vec.write()?;
|
|
}
|
|
|
|
// Reopen and verify
|
|
{
|
|
let vec = V::forced_import(&db, "test", Version::ONE)?;
|
|
assert_eq!(vec.len(), 100);
|
|
assert_eq!(vec.collect().len(), 100);
|
|
|
|
assert_eq!(vec.collect_range(0, 1), vec![0]);
|
|
assert_eq!(vec.collect_range(50, 51), vec![50]);
|
|
assert_eq!(vec.collect_range(99, 100), vec![99]);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// ============================================================================
|
|
// Test instantiation for each vec type
|
|
// ============================================================================
|
|
|
|
mod bytes {
|
|
use super::*;
|
|
use vecdb::BytesVec;
|
|
type V = BytesVec<usize, u32>;
|
|
|
|
#[test]
|
|
fn push_write_read() -> Result<()> {
|
|
run_push_write_read::<V>()
|
|
}
|
|
#[test]
|
|
fn stamp_management() -> Result<()> {
|
|
run_stamp_management::<V>()
|
|
}
|
|
#[test]
|
|
fn length_tracking() -> Result<()> {
|
|
run_length_tracking::<V>()
|
|
}
|
|
#[test]
|
|
fn truncate() -> Result<()> {
|
|
run_truncate::<V>()
|
|
}
|
|
#[test]
|
|
fn collect_signed_range() -> Result<()> {
|
|
run_collect_signed_range::<V>()
|
|
}
|
|
#[test]
|
|
fn iter_last() -> Result<()> {
|
|
run_iter_last::<V>()
|
|
}
|
|
#[test]
|
|
fn reset() -> Result<()> {
|
|
run_reset::<V>()
|
|
}
|
|
#[test]
|
|
fn collect() -> Result<()> {
|
|
run_collect::<V>()
|
|
}
|
|
#[test]
|
|
fn persistence_across_reopen() -> Result<()> {
|
|
run_persistence_across_reopen::<V>()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "zerocopy")]
|
|
mod zerocopy {
|
|
use super::*;
|
|
use vecdb::ZeroCopyVec;
|
|
type V = ZeroCopyVec<usize, u32>;
|
|
|
|
#[test]
|
|
fn push_write_read() -> Result<()> {
|
|
run_push_write_read::<V>()
|
|
}
|
|
#[test]
|
|
fn stamp_management() -> Result<()> {
|
|
run_stamp_management::<V>()
|
|
}
|
|
#[test]
|
|
fn length_tracking() -> Result<()> {
|
|
run_length_tracking::<V>()
|
|
}
|
|
#[test]
|
|
fn truncate() -> Result<()> {
|
|
run_truncate::<V>()
|
|
}
|
|
#[test]
|
|
fn collect_signed_range() -> Result<()> {
|
|
run_collect_signed_range::<V>()
|
|
}
|
|
#[test]
|
|
fn iter_last() -> Result<()> {
|
|
run_iter_last::<V>()
|
|
}
|
|
#[test]
|
|
fn reset() -> Result<()> {
|
|
run_reset::<V>()
|
|
}
|
|
#[test]
|
|
fn collect() -> Result<()> {
|
|
run_collect::<V>()
|
|
}
|
|
#[test]
|
|
fn persistence_across_reopen() -> Result<()> {
|
|
run_persistence_across_reopen::<V>()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "pco")]
|
|
mod pco {
|
|
use super::*;
|
|
use vecdb::PcoVec;
|
|
type V = PcoVec<usize, u32>;
|
|
|
|
#[test]
|
|
fn push_write_read() -> Result<()> {
|
|
run_push_write_read::<V>()
|
|
}
|
|
#[test]
|
|
fn stamp_management() -> Result<()> {
|
|
run_stamp_management::<V>()
|
|
}
|
|
#[test]
|
|
fn length_tracking() -> Result<()> {
|
|
run_length_tracking::<V>()
|
|
}
|
|
#[test]
|
|
fn truncate() -> Result<()> {
|
|
run_truncate::<V>()
|
|
}
|
|
#[test]
|
|
fn collect_signed_range() -> Result<()> {
|
|
run_collect_signed_range::<V>()
|
|
}
|
|
#[test]
|
|
fn iter_last() -> Result<()> {
|
|
run_iter_last::<V>()
|
|
}
|
|
#[test]
|
|
fn reset() -> Result<()> {
|
|
run_reset::<V>()
|
|
}
|
|
#[test]
|
|
fn collect() -> Result<()> {
|
|
run_collect::<V>()
|
|
}
|
|
#[test]
|
|
fn persistence_across_reopen() -> Result<()> {
|
|
run_persistence_across_reopen::<V>()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "lz4")]
|
|
mod lz4 {
|
|
use super::*;
|
|
use vecdb::LZ4Vec;
|
|
type V = LZ4Vec<usize, u32>;
|
|
|
|
#[test]
|
|
fn push_write_read() -> Result<()> {
|
|
run_push_write_read::<V>()
|
|
}
|
|
#[test]
|
|
fn stamp_management() -> Result<()> {
|
|
run_stamp_management::<V>()
|
|
}
|
|
#[test]
|
|
fn length_tracking() -> Result<()> {
|
|
run_length_tracking::<V>()
|
|
}
|
|
#[test]
|
|
fn truncate() -> Result<()> {
|
|
run_truncate::<V>()
|
|
}
|
|
#[test]
|
|
fn collect_signed_range() -> Result<()> {
|
|
run_collect_signed_range::<V>()
|
|
}
|
|
#[test]
|
|
fn iter_last() -> Result<()> {
|
|
run_iter_last::<V>()
|
|
}
|
|
#[test]
|
|
fn reset() -> Result<()> {
|
|
run_reset::<V>()
|
|
}
|
|
#[test]
|
|
fn collect() -> Result<()> {
|
|
run_collect::<V>()
|
|
}
|
|
#[test]
|
|
fn persistence_across_reopen() -> Result<()> {
|
|
run_persistence_across_reopen::<V>()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "zstd")]
|
|
mod zstd {
|
|
use super::*;
|
|
use vecdb::ZstdVec;
|
|
type V = ZstdVec<usize, u32>;
|
|
|
|
#[test]
|
|
fn push_write_read() -> Result<()> {
|
|
run_push_write_read::<V>()
|
|
}
|
|
#[test]
|
|
fn stamp_management() -> Result<()> {
|
|
run_stamp_management::<V>()
|
|
}
|
|
#[test]
|
|
fn length_tracking() -> Result<()> {
|
|
run_length_tracking::<V>()
|
|
}
|
|
#[test]
|
|
fn truncate() -> Result<()> {
|
|
run_truncate::<V>()
|
|
}
|
|
#[test]
|
|
fn collect_signed_range() -> Result<()> {
|
|
run_collect_signed_range::<V>()
|
|
}
|
|
#[test]
|
|
fn iter_last() -> Result<()> {
|
|
run_iter_last::<V>()
|
|
}
|
|
#[test]
|
|
fn reset() -> Result<()> {
|
|
run_reset::<V>()
|
|
}
|
|
#[test]
|
|
fn collect() -> Result<()> {
|
|
run_collect::<V>()
|
|
}
|
|
#[test]
|
|
fn persistence_across_reopen() -> Result<()> {
|
|
run_persistence_across_reopen::<V>()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "zerocopy")]
|
|
mod eager_zerocopy {
|
|
use super::*;
|
|
use vecdb::{EagerVec, ZeroCopyVec};
|
|
type V = EagerVec<ZeroCopyVec<usize, u32>>;
|
|
|
|
#[test]
|
|
fn push_write_read() -> Result<()> {
|
|
run_push_write_read::<V>()
|
|
}
|
|
#[test]
|
|
fn stamp_management() -> Result<()> {
|
|
run_stamp_management::<V>()
|
|
}
|
|
#[test]
|
|
fn length_tracking() -> Result<()> {
|
|
run_length_tracking::<V>()
|
|
}
|
|
#[test]
|
|
fn truncate() -> Result<()> {
|
|
run_truncate::<V>()
|
|
}
|
|
#[test]
|
|
fn collect_signed_range() -> Result<()> {
|
|
run_collect_signed_range::<V>()
|
|
}
|
|
#[test]
|
|
fn iter_last() -> Result<()> {
|
|
run_iter_last::<V>()
|
|
}
|
|
#[test]
|
|
fn reset() -> Result<()> {
|
|
run_reset::<V>()
|
|
}
|
|
#[test]
|
|
fn collect() -> Result<()> {
|
|
run_collect::<V>()
|
|
}
|
|
#[test]
|
|
fn persistence_across_reopen() -> Result<()> {
|
|
run_persistence_across_reopen::<V>()
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "pco")]
|
|
mod eager_pco {
|
|
use super::*;
|
|
use vecdb::{EagerVec, PcoVec};
|
|
type V = EagerVec<PcoVec<usize, u32>>;
|
|
|
|
#[test]
|
|
fn push_write_read() -> Result<()> {
|
|
run_push_write_read::<V>()
|
|
}
|
|
#[test]
|
|
fn stamp_management() -> Result<()> {
|
|
run_stamp_management::<V>()
|
|
}
|
|
#[test]
|
|
fn length_tracking() -> Result<()> {
|
|
run_length_tracking::<V>()
|
|
}
|
|
#[test]
|
|
fn truncate() -> Result<()> {
|
|
run_truncate::<V>()
|
|
}
|
|
#[test]
|
|
fn collect_signed_range() -> Result<()> {
|
|
run_collect_signed_range::<V>()
|
|
}
|
|
#[test]
|
|
fn iter_last() -> Result<()> {
|
|
run_iter_last::<V>()
|
|
}
|
|
#[test]
|
|
fn reset() -> Result<()> {
|
|
run_reset::<V>()
|
|
}
|
|
#[test]
|
|
fn collect() -> Result<()> {
|
|
run_collect::<V>()
|
|
}
|
|
#[test]
|
|
fn persistence_across_reopen() -> Result<()> {
|
|
run_persistence_across_reopen::<V>()
|
|
}
|
|
}
|