use std::{fs, path::PathBuf};
use io_pimdir::{PimdirBlobs, hash::PimdirHashAlgo};
use io_replica::object::ReplicaHash;
use serde_json::Value;
fn spec_dir() -> Option<PathBuf> {
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()?
.join("pimdir");
dir.join("vectors/objects.json").is_file().then_some(dir)
}
fn vectors() -> Option<Value> {
let spec = spec_dir()?;
let text = fs::read_to_string(spec.join("vectors/objects.json")).unwrap();
Some(serde_json::from_str(&text).unwrap())
}
fn body(case: &Value) -> Vec<u8> {
let len = case["body_len"].as_u64().unwrap() as usize;
match case["body_hex"].as_str() {
Some(hex) => {
let bytes: Vec<u8> = (0..hex.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap())
.collect();
assert_eq!(
bytes.len(),
len,
"case {} declares a length its bytes do not match",
case["label"]
);
bytes
}
None => {
assert!(
case["body_pattern"].is_string(),
"case {} carries neither bytes nor a pattern",
case["label"]
);
(0..len).map(|i| (i % 251) as u8).collect()
}
}
}
#[test]
fn every_body_names_what_the_format_says() {
let Some(vectors) = vectors() else {
eprintln!("skipped: no pimdir spec checkout beside this one");
return;
};
let cases = vectors["objects"].as_array().unwrap();
assert!(!cases.is_empty(), "the vectors carry no object");
for case in cases {
let label = case["label"].as_str().unwrap();
let body = body(case);
for (algo, spelling) in [
(PimdirHashAlgo::Blake3, "blake3"),
(PimdirHashAlgo::Sha256_128, "sha256-128"),
] {
let expected = &case[spelling];
let name = algo.hash(&body);
assert_eq!(
name.0,
expected["name"].as_str().unwrap(),
"{label} under {spelling}",
);
let blobs = PimdirBlobs::open("", algo);
assert_eq!(
blobs.path(&ReplicaHash(name.0.clone())),
PathBuf::from(expected["path"].as_str().unwrap()),
"{label} under {spelling} lands elsewhere",
);
}
}
}
#[test]
fn a_streamed_body_names_what_a_whole_one_names() {
let Some(vectors) = vectors() else {
eprintln!("skipped: no pimdir spec checkout beside this one");
return;
};
for case in vectors["objects"].as_array().unwrap() {
let label = case["label"].as_str().unwrap();
let body = body(case);
for (algo, spelling) in [
(PimdirHashAlgo::Blake3, "blake3"),
(PimdirHashAlgo::Sha256_128, "sha256-128"),
] {
let mut hasher = algo.hasher();
for chunk in body.chunks(7) {
hasher.update(chunk);
}
assert_eq!(
hasher.finish().0,
case[spelling]["name"].as_str().unwrap(),
"{label} under {spelling}, streamed in 7-byte pieces",
);
}
}
}