use super::*;
#[test]
fn every_descriptor_shape_roundtrips() {
let two_indexes = vec![
RelIndex {
cols: PkColList::from_slice(&[1]),
is_unique: true,
},
RelIndex {
cols: PkColList::from_slice(&[2, 0, 1]),
is_unique: false,
},
];
for &class in RelClass::ALL {
for (pk_repeats, serial) in [(false, false), (true, false), (false, true), (true, true)] {
for indexes in [vec![], two_indexes.clone()] {
let d = RelDescriptorBlob { class, pk_repeats, serial, indexes };
assert_eq!(RelDescriptorBlob::decode(&d.encode()), Ok(d.clone()), "{d:?}");
}
}
}
}
#[test]
fn each_decode_guard_rejects_its_own_forgery() {
let base = RelDescriptorBlob {
indexes: vec![RelIndex {
cols: PkColList::from_slice(&[0]),
is_unique: false,
}],
..Default::default()
}
.encode();
let ix = RelDescriptorBlob::default().encode().len();
let forge = |f: &dyn Fn(&mut Vec<u8>)| {
let mut b = base.clone();
f(&mut b);
b
};
let cases: &[(&str, Vec<u8>, &str)] = &[
("unknown class", forge(&|b| b[0] = 5), "unknown RelClass 5"),
("pk_repeats byte 2", forge(&|b| b[1] = 2), "neither 0 nor 1"),
("serial byte 2", forge(&|b| b[2] = 2), "neither 0 nor 1"),
("trailing byte", forge(&|b| b.push(0)), "trailing"),
(
"index column count",
forge(&|b| crate::write_u64_le(b, ix, crate::PK_LIST_PACKED_FLAG | 0xF)),
"out of range",
),
(
"untagged index list",
forge(&|b| crate::write_u64_le(b, ix, 0)),
"no packed-list flag",
),
(
"index repeats a column",
forge(&|b| crate::write_u64_le(b, ix, crate::PK_LIST_PACKED_FLAG | 2 | 1 << 4 | 1 << 11)),
"names column 1 twice",
),
("is_unique byte 2", forge(&|b| b[ix + 8] = 2), "neither 0 nor 1"),
];
for (what, bytes, want) in cases {
let err = RelDescriptorBlob::decode(bytes).expect_err(what);
assert!(err.contains(want), "{what}: {err:?} does not name {want:?}");
}
for cut in 0..base.len() {
let err = RelDescriptorBlob::decode(&base[..cut]).unwrap_err();
assert!(err.starts_with("rel descriptor:"), "a {cut}-byte prefix: {err}");
}
}