use proptest::prelude::*;
use sui_spec::hash;
const ALGOS: &[&str] = &["sha256", "sha512"];
const SIZE_BY_ALG: &[(&str, usize)] = &[
("sha256", 32),
("sha512", 64),
];
fn digest_size_for(alg: &str) -> usize {
SIZE_BY_ALG.iter().find(|(a, _)| *a == alg).map(|(_, n)| *n).unwrap_or(32)
}
proptest! {
#[test]
fn base16_roundtrip_bytes(
bytes in proptest::collection::vec(any::<u8>(), 32..=32),
) {
let encoded = hash::encode_hash("sha256", "base16", &bytes).unwrap();
let (_, decoded) = hash::decode_hash(&encoded).unwrap();
prop_assert_eq!(decoded, bytes);
}
#[test]
fn sri_roundtrip(
bytes in proptest::collection::vec(any::<u8>(), 32..=32),
) {
let encoded = hash::encode_hash("sha256", "sri", &bytes).unwrap();
let (decoded_alg, decoded) = hash::decode_hash(&encoded).unwrap();
prop_assert_eq!(decoded_alg, "sha256");
prop_assert_eq!(decoded, bytes);
}
#[test]
fn nix_base32_roundtrip(
bytes in proptest::collection::vec(any::<u8>(), 32..=32),
) {
let encoded = hash::encode_hash("sha256", "nix-base32", &bytes).unwrap();
let (decoded_alg, decoded) = hash::decode_hash(&encoded).unwrap();
prop_assert_eq!(decoded_alg, "sha256");
prop_assert_eq!(decoded, bytes);
}
#[test]
fn cross_encoding_equivalence_bytes(
bytes in proptest::collection::vec(any::<u8>(), 32..=32),
) {
let as_sri = hash::encode_hash("sha256", "sri", &bytes).unwrap();
let as_b32 = hash::encode_hash("sha256", "nix-base32", &bytes).unwrap();
let (_, d_sri) = hash::decode_hash(&as_sri).unwrap();
let (_, d_b32) = hash::decode_hash(&as_b32).unwrap();
prop_assert_eq!(d_sri.clone(), bytes.clone());
prop_assert_eq!(d_b32, bytes);
}
#[test]
fn apply_conversion_preserves_bytes(
bytes in proptest::collection::vec(any::<u8>(), 32..=32),
target in prop::sample::select(&["sri", "nix-base32"][..]),
) {
let target = target.to_string();
let sri_input = hash::encode_hash("sha256", "sri", &bytes).unwrap();
let converted = hash::apply_conversion("auto", &target, &sri_input).unwrap();
let (_, redecoded) = hash::decode_hash(&converted).unwrap();
prop_assert_eq!(redecoded, bytes);
}
#[test]
fn different_bytes_yield_different_encodings(
a in proptest::collection::vec(any::<u8>(), 32..=32),
b in proptest::collection::vec(any::<u8>(), 32..=32),
) {
prop_assume!(a != b);
for enc in ["base16", "sri", "nix-base32"] {
let ea = hash::encode_hash("sha256", enc, &a).unwrap();
let eb = hash::encode_hash("sha256", enc, &b).unwrap();
prop_assert_ne!(&ea, &eb,
"{}: same encoding for different bytes", enc);
}
}
}
#[test]
fn empty_string_sha256_is_canonical() {
let empty_sha256: Vec<u8> = vec![
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
];
let sri = hash::encode_hash("sha256", "sri", &empty_sha256).unwrap();
assert_eq!(sri, "sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=");
let b32 = hash::encode_hash("sha256", "nix-base32", &empty_sha256).unwrap();
assert!(b32.starts_with("sha256:"));
assert_eq!(b32.strip_prefix("sha256:").unwrap().len(), 52);
}