#![cfg(all(feature = "compression", feature = "checksum", feature = "messagepack"))]
use std::collections::{BTreeSet, HashMap, HashSet};
use std::mem::discriminant;
use cachekit_core::byte_storage::ByteStorageError;
use cachekit_core::{ByteStorage, StorageEnvelope};
use sha2::{Digest, Sha256};
const FIXTURE: &str = include_str!("vectors/wire-format.json");
const FIXTURE_SHA256: &str = "5d72ca1ff27202ab46aa501f54abf77e535f275d2ea4443966ad464f3c020cd7";
#[derive(serde::Deserialize)]
struct WireFormatFixture {
limits: Limits,
vectors: Vec<Vector>,
#[serde(default)]
reject_vectors: Vec<RejectVector>,
version: String,
}
#[derive(serde::Deserialize)]
struct Limits {
max_compressed_size: usize,
max_compression_ratio: u64,
max_uncompressed_size: usize,
}
#[derive(serde::Deserialize)]
struct Vector {
name: String,
format: String,
input_hex: String,
input_size: usize,
envelope_hex: String,
envelope_size: usize,
envelope_encoding: Option<String>,
derived_from: Option<String>,
}
#[derive(serde::Deserialize)]
struct RejectVector {
name: String,
envelope_hex: String,
envelope_size: usize,
}
impl Vector {
fn is_legacy(&self) -> bool {
self.envelope_encoding.is_none()
}
}
fn load_fixture() -> WireFormatFixture {
serde_json::from_str(FIXTURE).expect("wire-format.json fixture must parse")
}
#[test]
fn fixture_integrity_pinned_sha256() {
let digest = hex::encode(Sha256::digest(FIXTURE.as_bytes()));
assert_eq!(
digest, FIXTURE_SHA256,
"vendored wire-format.json drifted from its pinned sha256 — \
re-vendor from the protocol repo and update FIXTURE_SHA256 deliberately"
);
}
#[test]
fn fixture_is_current_version_with_vectors() {
let fixture = load_fixture();
assert_eq!(fixture.version, "1.3.0");
let legacy: HashSet<&str> = fixture
.vectors
.iter()
.filter(|v| v.is_legacy())
.map(|v| v.name.as_str())
.collect();
let bin = fixture.vectors.len() - legacy.len();
assert!(
legacy.len() >= 6,
"legacy vectors are retained forever as legacy-read proof; expected at least the original 6, got {}",
legacy.len()
);
assert!(
bin >= 6,
"protocol 1.1 pins a *_bin twin per legacy vector; expected at least 6, got {bin}"
);
let mut twins: HashMap<&str, usize> = HashMap::new();
for vector in fixture.vectors.iter().filter(|v| !v.is_legacy()) {
let parent = vector.derived_from.as_deref().unwrap_or_else(|| {
panic!(
"[{}] bin vector must name its legacy parent in derived_from",
vector.name
)
});
assert!(
legacy.contains(parent),
"[{}] derived_from {parent:?} names no legacy vector",
vector.name
);
*twins.entry(parent).or_insert(0) += 1;
}
for name in &legacy {
assert_eq!(
twins.get(name).copied().unwrap_or(0),
1,
"legacy vector {name:?} must have exactly one *_bin twin"
);
}
for required in ["width_boundary_bin16", "width_boundary_bin16_bin"] {
assert!(
fixture.vectors.iter().any(|v| v.name == required),
"fixture must retain the {required:?} vector"
);
}
}
#[test]
fn fixture_limits_match_implementation() {
let fixture = load_fixture();
let storage = ByteStorage::new(None);
assert_eq!(
fixture.limits.max_uncompressed_size,
storage.max_uncompressed_size()
);
assert_eq!(
fixture.limits.max_compressed_size,
storage.max_compressed_size()
);
assert_eq!(
fixture.limits.max_compression_ratio,
storage.max_compression_ratio()
);
}
#[test]
fn vectors_decode_to_expected_payload() {
let storage = ByteStorage::new(None);
for vector in load_fixture().vectors {
let input = hex::decode(&vector.input_hex).expect("input_hex must decode");
let envelope = hex::decode(&vector.envelope_hex).expect("envelope_hex must decode");
assert_eq!(
input.len(),
vector.input_size,
"[{}] input_size mismatch",
vector.name
);
assert_eq!(
envelope.len(),
vector.envelope_size,
"[{}] envelope_size mismatch",
vector.name
);
let (payload, format) = storage
.retrieve(&envelope)
.unwrap_or_else(|e| panic!("[{}] retrieve failed: {e:?}", vector.name));
assert_eq!(
payload, input,
"[{}] decoded payload differs from input",
vector.name
);
assert_eq!(format, vector.format, "[{}] format mismatch", vector.name);
assert!(
storage.validate(&envelope),
"[{}] validate() rejected canonical envelope",
vector.name
);
}
}
#[test]
fn vectors_reencode_byte_identical() {
let storage = ByteStorage::new(None);
for vector in load_fixture()
.vectors
.into_iter()
.filter(|v| !v.is_legacy())
{
let input = hex::decode(&vector.input_hex).expect("input_hex must decode");
let expected = hex::decode(&vector.envelope_hex).expect("envelope_hex must decode");
let encoded = storage
.store(&input, Some(vector.format.clone()))
.unwrap_or_else(|e| panic!("[{}] store failed: {e:?}", vector.name));
assert_eq!(
hex::encode(&encoded),
hex::encode(&expected),
"[{}] re-encoded envelope is not byte-identical to the canonical vector",
vector.name
);
}
}
#[test]
fn envelope_codec_roundtrip_byte_identical() {
for vector in load_fixture()
.vectors
.into_iter()
.filter(|v| !v.is_legacy())
{
let canonical = hex::decode(&vector.envelope_hex).expect("envelope_hex must decode");
let envelope: StorageEnvelope = rmp_serde::from_slice(&canonical)
.unwrap_or_else(|e| panic!("[{}] envelope must deserialize: {e}", vector.name));
let reserialized = rmp_serde::to_vec(&envelope)
.unwrap_or_else(|e| panic!("[{}] envelope must reserialize: {e}", vector.name));
assert_eq!(
hex::encode(&reserialized),
hex::encode(&canonical),
"[{}] MessagePack envelope layout is not byte-stable",
vector.name
);
}
}
#[test]
fn bin_twins_are_bin_encoded_and_field_identical_to_legacy() {
let fixture = load_fixture();
let twins: Vec<&Vector> = fixture.vectors.iter().filter(|v| !v.is_legacy()).collect();
assert!(
!twins.is_empty(),
"protocol 1.1 fixture must carry *_bin twins"
);
for twin in twins {
assert_eq!(
twin.envelope_encoding.as_deref(),
Some("bin"),
"[{}] unknown envelope_encoding",
twin.name
);
let parent_name = twin
.derived_from
.as_deref()
.unwrap_or_else(|| panic!("[{}] *_bin twin missing derived_from", twin.name));
let parent = fixture
.vectors
.iter()
.find(|v| v.name == parent_name)
.unwrap_or_else(|| {
panic!(
"[{}] derived_from '{parent_name}' not in fixture",
twin.name
)
});
let twin_bytes = hex::decode(&twin.envelope_hex).expect("envelope_hex must decode");
let twin_env: StorageEnvelope = rmp_serde::from_slice(&twin_bytes)
.unwrap_or_else(|e| panic!("[{}] twin must deserialize: {e}", twin.name));
assert_eq!(
twin_bytes[0], 0x94,
"[{}] outer fixarray(4) marker",
twin.name
);
assert_eq!(
twin_bytes[1],
match twin_env.compressed_data.len() {
0..=255 => 0xc4,
256..=65_535 => 0xc5,
_ => 0xc6,
},
"[{}] compressed_data does not use the shortest bin marker: 0x{:02x}",
twin.name,
twin_bytes[1]
);
let parent_bytes = hex::decode(&parent.envelope_hex).expect("envelope_hex must decode");
let parent_env: StorageEnvelope = rmp_serde::from_slice(&parent_bytes)
.unwrap_or_else(|e| panic!("[{parent_name}] parent must deserialize: {e}"));
assert_eq!(
twin_env.compressed_data, parent_env.compressed_data,
"[{}]",
twin.name
);
assert_eq!(twin_env.checksum, parent_env.checksum, "[{}]", twin.name);
assert_eq!(
twin_env.original_size, parent_env.original_size,
"[{}]",
twin.name
);
assert_eq!(twin_env.format, parent_env.format, "[{}]", twin.name);
}
}
const REJECT_EXPECTATIONS: [(&str, ByteStorageError); 6] = [
(
"reject_original_size_over_cap",
ByteStorageError::InputTooLarge,
),
(
"reject_original_size_wraps_u32",
ByteStorageError::DeserializationFailed(String::new()),
),
(
"reject_zero_length_compressed_data",
ByteStorageError::DecompressionBomb,
),
("reject_ratio_bomb", ByteStorageError::DecompressionBomb),
(
"reject_decompressed_length_mismatch",
ByteStorageError::SizeValidationFailed,
),
(
"reject_checksum_mismatch",
ByteStorageError::ChecksumMismatch,
),
];
#[test]
fn reject_vectors_fail_with_the_spec_error() {
let fixture = load_fixture();
let names: BTreeSet<&str> = fixture
.reject_vectors
.iter()
.map(|v| v.name.as_str())
.collect();
let expected: BTreeSet<&str> = REJECT_EXPECTATIONS.iter().map(|(n, _)| *n).collect();
assert_eq!(
names, expected,
"wire-format.json reject_vectors must be exactly the six pinned names"
);
assert_eq!(
fixture.reject_vectors.len(),
expected.len(),
"duplicate reject vector name"
);
let storage = ByteStorage::new(None);
for (name, expected) in REJECT_EXPECTATIONS {
let vector = fixture
.reject_vectors
.iter()
.find(|v| v.name == name)
.expect("checked above");
let envelope = hex::decode(&vector.envelope_hex).expect("envelope_hex must decode");
assert_eq!(
envelope.len(),
vector.envelope_size,
"[{name}] envelope_size mismatch"
);
match storage.retrieve(&envelope) {
Ok(_) => panic!("[{name}] retrieve accepted a reject vector"),
Err(e) => assert_eq!(
discriminant(&e),
discriminant(&expected),
"[{name}] rejected with {e:?}, expected {expected:?}"
),
}
assert!(
!storage.validate(&envelope),
"[{name}] validate() accepted a reject vector"
);
}
}