use std::fs::File;
use std::io::Write;
use tempfile::TempDir;
use obj::Db;
#[cfg(not(feature = "encryption"))]
use obj::Error;
const PAGE_SIZE: usize = 4096;
const HEADER_CRC_OFFSET: usize = PAGE_SIZE - 4;
fn synth_encryption_capable_header() -> [u8; PAGE_SIZE] {
let mut buf = [0u8; PAGE_SIZE];
buf[0..4].copy_from_slice(b"OBJF");
buf[4..6].copy_from_slice(&0u16.to_le_bytes());
buf[6..8].copy_from_slice(&2u16.to_le_bytes());
buf[8..10].copy_from_slice(
&u16::try_from(PAGE_SIZE)
.expect("PAGE_SIZE fits in u16")
.to_le_bytes(),
);
buf[10..14].copy_from_slice(&0b10u32.to_le_bytes());
buf[16..24].copy_from_slice(&1u64.to_le_bytes());
for (i, b) in buf[72..104].iter_mut().enumerate() {
*b = u8::try_from(i & 0xFF).expect("masked");
}
let crc = obj_core::pager::checksum::crc32c(&buf[..HEADER_CRC_OFFSET]);
buf[HEADER_CRC_OFFSET..HEADER_CRC_OFFSET + 4].copy_from_slice(&crc.to_le_bytes());
buf
}
#[cfg(not(feature = "encryption"))]
#[test]
fn open_refuses_format_minor_two_without_encryption_feature() {
let dir = TempDir::new().expect("tmp");
let path = dir.path().join("encryption_capable.obj");
let header = synth_encryption_capable_header();
{
let mut f = File::create(&path).expect("create");
f.write_all(&header).expect("write header");
f.sync_all().expect("sync");
}
let err = Db::open(&path).expect_err("default build must refuse");
match err {
Error::FormatFeatureUnsupported { feature } => {
assert_eq!(feature, "encryption");
}
other => panic!(
"expected Error::FormatFeatureUnsupported {{ feature: \"encryption\" }}; \
got {other:?}",
),
}
}
#[cfg(feature = "encryption")]
#[test]
fn format_feature_unsupported_variant_exists_under_encryption() {
let err = obj::Error::FormatFeatureUnsupported {
feature: "encryption",
};
assert!(matches!(
err,
obj::Error::FormatFeatureUnsupported { feature } if feature == "encryption"
));
let dir = TempDir::new().expect("tmp");
let path = dir.path().join("e.obj");
let header = synth_encryption_capable_header();
{
let mut f = File::create(&path).expect("create");
f.write_all(&header).expect("write header");
f.sync_all().expect("sync");
}
let err = Db::open(&path).expect_err("missing key must fail");
assert!(matches!(err, obj::Error::EncryptionKeyRequired));
}