use super::*;
use core::{mem::MaybeUninit, num::NonZeroU32, panic::AssertUnwindSafe};
extern crate std;
use std::panic::catch_unwind;
#[derive(super::super::WarpTableRow, super::super::CallerWarpTableColumns)]
struct Item {
value: u32,
}
#[test]
fn storage_dimensions_preserve_narrow_target_and_overflow_refusals() -> Result<(), &'static str> {
let outside = Capacity::new(NonZeroU32::new(65_536).ok_or("capacity")?);
assert_eq!(
represent_capacity::<u16>(outside),
Err(CallerStorageError::CapacityUnrepresentable { capacity: outside })
);
assert_eq!(represent_capacity::<u32>(outside), Ok(65_536));
assert_eq!(
primary_bucket_count(usize::MAX),
Err(CallerStorageError::PrimaryIndexCapacityOverflow {
maximum_rows: usize::MAX
})
);
for (rows, buckets) in [(1, 8), (4, 8), (5, 10), (100, 200)] {
let capacity = Capacity::new(NonZeroU32::new(rows).ok_or("capacity")?);
assert_eq!(capacity.primary_index_buckets(), Ok(buckets));
}
Ok(())
}
#[test]
fn backing_detects_broken_id_admission_and_removal_invariants() -> Result<(), &'static str> {
type Backing<'storage> = CallerStorage<'storage, Item, ItemCallerColumns<'storage>>;
let mut slots = [MaybeUninit::uninit(); 1];
let mut ids = ColumnLease::new(&mut slots);
let id = super::super::WarpId::<Item>::new(NonZeroU64::MIN);
<Backing<'_> as WarpTableBacking<Item>>::append_id(&mut ids, id);
assert!(
catch_unwind(AssertUnwindSafe(|| <Backing<'_> as WarpTableBacking<
Item,
>>::append_id(&mut ids, id)))
.is_err()
);
assert_eq!(ids.as_slice(), [id]);
assert!(
catch_unwind(AssertUnwindSafe(|| <Backing<'_> as WarpTableBacking<
Item,
>>::remove_id(&mut ids, 1)))
.is_err()
);
assert_eq!(ids.as_slice(), [id]);
<Backing<'_> as WarpTableBacking<Item>>::remove_id(&mut ids, 0);
assert!(ids.is_empty());
Ok(())
}
#[test]
fn populated_indexes_are_refused_before_capacity_checks() {
assert_eq!(
validate_caller_index("key", 4, 3, false),
Err(CallerStorageError::IndexNotEmpty { field: "key" })
);
}
#[cfg(feature = "secondary-indexes")]
mod indexed {
use super::*;
use crate::storage::warp_table::{stable_slots::*, *};
use crate::storage::{query_workspace::*, range_index::RangeIndex};
use alloc::boxed::Box;
#[derive(WarpTableRow, CallerWarpTableColumns)]
struct Ranked {
#[index(range)]
rank: u8,
}
type Table = CallerWarpTable<'static, Ranked, RankedCallerColumns<'static>>;
fn table() -> Result<Table, &'static str> {
let stable = StableSlots::from_storage(
1,
CallerStableSlots {
rows: ColumnLease::new(Box::leak(Box::new([MaybeUninit::uninit()]))),
locations: ColumnLease::new(Box::leak(Box::new([const { MaybeUninit::uninit() }]))),
},
)
.map_err(|_| "stable")?;
let range = RangeIndex::try_from_storage(1, &mut Box::leak(Box::new([0; 9]))[..])
.map_err(|_| "range")?;
Table::from_storage(
Capacity::new(NonZeroU32::MIN),
CallerStorage {
ids: ColumnLease::new(Box::leak(Box::new([MaybeUninit::uninit()]))),
columns: RankedCallerColumns::new(ColumnLease::new(Box::leak(Box::new([
MaybeUninit::uninit(),
])))),
indexes: RankedCallerIndexes::new(stable, range),
primary_buckets: Box::leak(Box::new([0; 8])),
},
)
.map_err(|_| "table")
}
#[test]
fn corrupted_row_locations_fail_loudly_in_selection_ranking_and_unique_lookup()
-> Result<(), &'static str> {
let mut table = table()?;
assert!(matches!(
table.insert(Ranked { rank: 1 }),
WarpTableInsertOutcome::Inserted { .. }
));
let _removed = table.ids.swap_remove(0);
table.len = 0;
let mut query = QueryWorkspace::new(1, alloc::vec![QueryChunk::EMPTY], QueryChunk::EMPTY)
.map_err(|_| "query")?;
let selected = table
.query_in(query.membership().map_err(|_| "query")?)
.find(|q| q.find_rank_in(..))
.map_err(|_| "find")?;
assert!(catch_unwind(AssertUnwindSafe(|| selected.rows().count())).is_err());
let mut empty = [];
assert!(selected.rows_in_dense_order(&mut empty).is_err());
let mut bytes = [MaybeUninit::uninit(); 256];
let ranked = selected
.rank_in(
StorageLease::new(&mut bytes),
core::num::NonZeroUsize::MIN,
|q| [q.smallest_rank_first()],
)
.map_err(|_| "rank")?;
assert!(catch_unwind(AssertUnwindSafe(|| ranked.leaders().count())).is_err());
assert!(
catch_unwind(AssertUnwindSafe(|| table.get_unique(|q| {
CallerUniqueLookup::new(
q,
Ok(UniqueIndexLookupOutcome::Present { key: 1_u8, row: 0 }),
)
})))
.is_err()
);
Ok(())
}
#[test]
fn mutable_snapshots_refuse_a_foreign_table_before_applying_updates() -> Result<(), &'static str>
{
let mut table = table()?;
let other = Box::leak(Box::new(self::table()?));
let mut query = QueryWorkspace::new(1, alloc::vec![QueryChunk::EMPTY], QueryChunk::EMPTY)
.map_err(|_| "query")?;
let outcome = table.update_selected_in(
query.membership().map_err(|_| "query")?,
|q| {
let membership = q.find(|q| q.find_rank_in(..))?.into_workspace();
other.query_in(membership).find(|q| q.find_rank_in(..))
},
|_row| {},
);
assert!(matches!(
outcome,
Err(CallerSelectionError::DifferentTables)
));
Ok(())
}
impl CallerWarpTableBulkUpdate<Ranked, fn(), ()> for RankedCallerColumns<'static> {
fn bulk_update(
&mut self,
_indexes: &mut Self::Indexes,
_selection: BulkSelection<'_>,
update: fn(),
) -> Result<(), BulkUpdateError> {
update();
Ok(())
}
}
#[test]
fn bulk_updates_refuse_a_foreign_snapshot_before_calling_the_adapter()
-> Result<(), &'static str> {
fn update() {}
let mut table = table()?;
let other = Box::leak(Box::new(self::table()?));
let query = QueryWorkspace::new(1, alloc::vec![QueryChunk::EMPTY], QueryChunk::EMPTY)
.map_err(|_| "query")?;
let mut workspace = BulkUpdateWorkspace::new(
query,
QueryChunk::EMPTY,
QueryChunk::EMPTY,
alloc::vec![0_u16],
);
let outcome = table.bulk_update_in(
&mut workspace,
|q| {
let membership = q.find(|q| q.find_rank_in(..))?.into_workspace();
other.query_in(membership).find(|q| q.find_rank_in(..))
},
update as fn(),
);
assert!(matches!(
outcome,
Err(CallerBulkUpdateError::DifferentTables)
));
Ok(())
}
}