#![allow(clippy::unwrap_used, clippy::expect_used)]
use sqlite_core::Value;
use sqlite_forensic::interpret::{interpret_values, BlobContext, BlobInterpreter, Interpretation};
struct ByteLen;
impl BlobInterpreter for ByteLen {
fn interpret(&self, bytes: &[u8], _ctx: &BlobContext<'_>) -> Option<Interpretation> {
Some(Interpretation {
text: format!("{} bytes", bytes.len()),
kind: "bytelen".to_string(),
lossy: false,
confidence: 1.0,
})
}
}
fn sample_values() -> Vec<Value> {
vec![
Value::Integer(7),
Value::Text("hello".to_string()),
Value::Blob(vec![0xDE, 0xAD, 0xBE, 0xEF]),
]
}
#[test]
fn interpreter_reaches_only_the_blob_value() {
let values = sample_values();
let ctx = BlobContext {
table: Some("moz_places"),
column: None,
};
let out = interpret_values(&values, &ctx, Some(&ByteLen));
assert_eq!(out.len(), 1, "only the BLOB value is interpreted: {out:?}");
let (idx, interp) = &out[0];
assert_eq!(*idx, 2, "the BLOB is at column index 2");
assert_eq!(interp.text, "4 bytes");
assert_eq!(interp.kind, "bytelen");
assert!(!interp.lossy);
}
#[test]
fn none_interpreter_is_passthrough_no_interpretations() {
let values = sample_values();
let ctx = BlobContext {
table: None,
column: None,
};
let out = interpret_values(&values, &ctx, None);
assert!(
out.is_empty(),
"with no interpreter, behaviour is unchanged (no interpretations): {out:?}"
);
}
#[test]
fn no_blobs_yields_no_interpretations_even_with_an_interpreter() {
let values = vec![Value::Integer(1), Value::Text("x".to_string()), Value::Null];
let ctx = BlobContext {
table: None,
column: None,
};
let out = interpret_values(&values, &ctx, Some(&ByteLen));
assert!(out.is_empty(), "no BLOB → nothing to interpret: {out:?}");
}