extern crate std;
use super::*;
use crate::storage::query_workspace::{QueryChunk, QueryWorkspace};
use crate::storage::warp_table::secondary_index::StableSlots;
use crate::storage::warp_table::{Capacity, WarpTableInsertWithIdOutcome};
use core::num::NonZeroU32;
use core::panic::AssertUnwindSafe;
use std::panic::catch_unwind;
#[derive(WarpTableRow)]
#[index(primary = u32)]
struct Unit {
#[index(secondary)]
group: u8,
}
fn table() -> Result<WarpTable<Unit>, &'static str> {
let mut table = WarpTable::try_new(Capacity::new(NonZeroU32::MIN)).map_err(|_| "table")?;
if !matches!(
table.insert_with_id(7, Unit { group: 1 }),
WarpTableInsertWithIdOutcome::Inserted { .. }
) {
return Err("insert");
}
Ok(table)
}
#[test]
fn invalid_stable_memberships_cannot_project_or_update_a_row() -> Result<(), &'static str> {
let mut table = table()?;
table.indexes.__pipecircuit_stable_slots = StableSlots::try_new(1).map_err(|_| "slots")?;
let mut chunks = [QueryChunk::EMPTY];
let mut scratch = QueryChunk::EMPTY;
let mut workspace =
QueryWorkspace::new(1, &mut chunks, &mut scratch).map_err(|_| "workspace")?;
let selected = table
.query_memberships()
.find_group(1)
.in_workspace(workspace.membership().map_err(|_| "members")?)
.map_err(|_| "select")?;
assert!(catch_unwind(AssertUnwindSafe(|| selected.ids().next())).is_err());
assert!(
catch_unwind(AssertUnwindSafe(|| table.update_memberships(
workspace
.membership()
.map_err(WorkspaceSelectionError::from)?,
|table, members| table
.query_memberships()
.find_group(1)
.in_workspace(members),
|_| {}
)))
.is_err()
);
Ok(())
}
#[test]
fn a_missing_primary_identity_is_an_invariant_failure() -> Result<(), &'static str> {
let mut table = table()?;
table.ids.clear();
let mut chunks = [QueryChunk::EMPTY];
let mut scratch = QueryChunk::EMPTY;
let mut workspace =
QueryWorkspace::new(1, &mut chunks, &mut scratch).map_err(|_| "workspace")?;
let selected = table
.query_memberships()
.find_group(1)
.in_workspace(workspace.membership().map_err(|_| "members")?)
.map_err(|_| "select")?;
assert!(catch_unwind(AssertUnwindSafe(|| selected.ids().next())).is_err());
Ok(())
}
#[test]
fn an_update_cannot_accept_a_selection_bound_to_another_table() -> Result<(), &'static str> {
static FOREIGN: std::sync::OnceLock<WarpTable<Unit>> = std::sync::OnceLock::new();
FOREIGN
.set(table()?)
.map_err(|_| "foreign initialized twice")?;
let foreign = FOREIGN.get().ok_or("foreign missing")?;
let mut table = table()?;
let mut chunks = [QueryChunk::EMPTY];
let mut scratch = QueryChunk::EMPTY;
let mut workspace =
QueryWorkspace::new(1, &mut chunks, &mut scratch).map_err(|_| "workspace")?;
let mut called = false;
let result = table.update_memberships(
workspace.membership().map_err(|_| "members")?,
|_, members| {
foreign
.query_memberships()
.find_group(1)
.in_workspace(members)
},
|_| called = true,
);
assert_eq!(result, Err(WorkspaceSelectionError::DifferentTables));
assert!(!called);
assert_eq!(table.query_memberships().find_group(1).len(), 1);
let mut storage = [99];
let result = table.update_memberships_in_dense_order(
workspace.membership().map_err(|_| "members")?,
&mut storage,
|_, members| foreign.query().find_group(1).in_workspace(members),
|_| called = true,
);
assert_eq!(result, Err(WorkspaceSelectionError::DifferentTables));
assert!(!called);
assert_eq!(storage, [99]);
Ok(())
}