use std::fmt::Write as _;
use dig_blockstore::BlockStoreError;
use rocksdb::{Options, DB};
#[test]
fn test_rocksdb_error_converts_with_into() {
let inner = sample_rocksdb_error();
let original_msg = inner.to_string();
let err: BlockStoreError = inner.into();
assert!(
matches!(err, BlockStoreError::RocksDb(_)),
"ERR-002 requires RocksDb variant after .into()"
);
let mut s = String::new();
write!(&mut s, "{err}").unwrap();
assert!(
s.contains(original_msg.trim()),
"Display should surface RocksDB message: {s}"
);
}
#[test]
fn test_bincode_error_maps_to_serialization_with_nonempty_message() {
let bc_err = bincode::deserialize::<u64>(&[0xFF, 0xFF]).unwrap_err();
let original = bc_err.to_string();
assert!(
!original.is_empty(),
"sanity: bincode should explain failure"
);
let err = BlockStoreError::from(bc_err);
match err {
BlockStoreError::Serialization(msg) => {
assert!(
!msg.is_empty(),
"ERR-002: Serialization payload must carry bincode context"
);
assert!(
msg.contains(original.trim()),
"ERR-002 acceptance §5: preserve bincode text (got {msg}, expected fragment of {original})"
);
}
other => panic!("expected Serialization, got {other:?}"),
}
}
#[test]
fn test_zstd_io_error_maps_to_compression() {
let io_err = zstd::decode_all([0xFFu8, 0xFE, 0xFD].as_slice()).unwrap_err();
let original = io_err.to_string();
let err = BlockStoreError::compression_from_io(io_err);
match err {
BlockStoreError::Compression(msg) => {
assert!(
!msg.is_empty(),
"ERR-002: Compression payload must carry zstd/io context"
);
assert!(
msg.contains(original.trim()),
"ERR-002 acceptance §5: preserve io error text (got {msg})"
);
}
other => panic!("expected Compression, got {other:?}"),
}
}
mod question_mark_smoke {
use dig_blockstore::BlockStoreError;
use rocksdb::{Options, DB};
pub(super) fn bincode_propagates() -> Result<u64, BlockStoreError> {
Ok(bincode::deserialize(&[0x01u8])?)
}
pub(super) fn zstd_propagates() -> Result<Vec<u8>, BlockStoreError> {
zstd::decode_all(&[0xAA, 0xBB][..]).map_err(BlockStoreError::compression_from_io)
}
pub(super) fn rocksdb_propagates() -> Result<(), BlockStoreError> {
let tmp = tempfile::tempdir().map_err(|e| {
BlockStoreError::Serialization(format!("tempdir for rocksdb smoke: {e}"))
})?;
let blocker = tmp.path().join("not_a_db_dir");
std::fs::write(&blocker, b"x")
.map_err(|e| BlockStoreError::Serialization(format!("setup rocksdb smoke: {e}")))?;
DB::open(&Options::default(), &blocker)?;
Ok(())
}
}
#[test]
fn test_question_mark_propagates_each_source() {
assert!(matches!(
question_mark_smoke::bincode_propagates(),
Err(BlockStoreError::Serialization(_))
));
assert!(matches!(
question_mark_smoke::zstd_propagates(),
Err(BlockStoreError::Compression(_))
));
assert!(matches!(
question_mark_smoke::rocksdb_propagates(),
Err(BlockStoreError::RocksDb(_))
));
}
fn sample_rocksdb_error() -> rocksdb::Error {
let tmp = tempfile::tempdir().expect("tempdir");
let not_a_dir = tmp.path().join("not_a_directory");
std::fs::write(¬_a_dir, b"x").expect("write file");
DB::open(&Options::default(), ¬_a_dir).expect_err("expected RocksDB open failure")
}