use crate::test_support::TestSchema;
use crate::{ColumnLocator, ColumnTable, SchemaFacts};
use gnitz_wire::TypeCode;
type Case = (&'static [(TypeCode, bool)], &'static [u32]);
const CASES: &[Case] = &[
(
&[
(TypeCode::U64, false),
(TypeCode::U64, false),
(TypeCode::F64, true),
(TypeCode::String, false),
(TypeCode::U128, false),
],
&[0],
),
(
&[
(TypeCode::String, true),
(TypeCode::I64, false),
(TypeCode::U64, false),
(TypeCode::F32, true),
],
&[1],
),
(
&[
(TypeCode::I32, false),
(TypeCode::U16, false),
(TypeCode::F64, false),
(TypeCode::Blob, true),
],
&[0, 1],
),
(
&[
(TypeCode::U32, false),
(TypeCode::String, true),
(TypeCode::F64, false),
(TypeCode::I64, false),
],
&[3, 0],
),
(
&[
(TypeCode::I8, false),
(TypeCode::U16, false),
(TypeCode::I32, false),
(TypeCode::U64, false),
(TypeCode::I128, true),
(TypeCode::UUID, false),
],
&[0, 1, 2, 3],
),
(
&[
(TypeCode::U64, false),
(TypeCode::U8, true),
(TypeCode::I16, true),
(TypeCode::U32, true),
(TypeCode::I64, true),
(TypeCode::U128, true),
],
&[0],
),
(&[(TypeCode::U32, false)], &[0]),
];
#[test]
fn schema_facts_match_the_column_table() {
for &(cols, pk) in CASES {
let s = TestSchema::new(cols, pk);
let ctx = format!("cols {cols:?}, pk {pk:?}");
assert_eq!(s.pk_cols(), pk, "{ctx}: pk_cols()");
assert_eq!(s.num_columns(), cols.len(), "{ctx}: num_columns()");
assert_eq!(s.num_payload_cols(), cols.len() - pk.len(), "{ctx}: num_payload_cols()");
let want_stride: usize = pk.iter().map(|&p| cols[p as usize].0.wire_stride()).sum();
assert_eq!(s.pk_stride(), want_stride, "{ctx}: pk_stride()");
let mut pk_off = vec![0usize; cols.len()];
let mut running = 0usize;
for &p in pk {
pk_off[p as usize] = running;
running += cols[p as usize].0.wire_stride();
}
let (mut want_nullable, mut want_not_null) = (0u64, 0u64);
let mut next_slot = 0usize;
for (ci, &(want_tc, nullable)) in cols.iter().enumerate() {
let want_pk = pk.contains(&(ci as u32));
assert_eq!(s.is_pk_col(ci), want_pk, "{ctx}: is_pk_col({ci})");
let loc = s.locate(ci);
assert_eq!(loc.type_code(), want_tc, "{ctx}: locate({ci}).type_code()");
assert_eq!(loc.size(), want_tc.wire_stride(), "{ctx}: locate({ci}).size()");
match loc {
ColumnLocator::Pk { byte_off, .. } => {
assert!(want_pk, "{ctx}: locate({ci}) is Pk for a payload column");
assert_eq!(byte_off as usize, pk_off[ci], "{ctx}: locate({ci}) OPK byte offset");
assert_eq!(s.payload_slot(ci), None, "{ctx}: payload_slot({ci})");
}
ColumnLocator::Payload { slot, .. } => {
assert!(!want_pk, "{ctx}: locate({ci}) is Payload for a PK column");
assert_eq!(slot as usize, next_slot, "{ctx}: locate({ci}) payload slot");
assert_eq!(s.payload_slot(ci), Some(next_slot), "{ctx}: payload_slot({ci})");
assert_eq!(s.payload_col_idx(next_slot), ci, "{ctx}: payload_col_idx({next_slot})");
*if nullable {
&mut want_nullable
} else {
&mut want_not_null
} |= 1u64 << next_slot;
next_slot += 1;
}
}
}
assert_eq!(s.try_locate(s.num_columns()), None, "{ctx}: try_locate(num_columns())");
assert!(!s.is_pk_col(pk[0] as usize + (1 << 32)), "{ctx}: is_pk_col past u32");
assert_eq!(
s.payload_slot(s.num_columns()),
None,
"{ctx}: payload_slot(num_columns())"
);
assert_eq!(
s.nullable_payload_slots(),
want_nullable,
"{ctx}: nullable_payload_slots()"
);
assert_eq!(
s.not_null_payload_slots(),
want_not_null | !gnitz_wire::low_bits_mask(next_slot),
"{ctx}: not_null_payload_slots()"
);
}
}