use sha2::{Digest, Sha256};
pub const FIXTURE_SIZE_BYTES: usize = 1024 * 1024;
pub const FIXTURE_SHA256_HEX: &str =
"38c34d93ad6a2080be2f49dfed60acd747278a0a1cf4b81dedda07c512fd1fe6";
const LINE_CONTENT: &[u8] = b"HL-A13-0123456789ABCDEF0123456789ABCDEF0123456789ABCDEFXXXXXXXX";
pub fn build_a13_fixture() -> Vec<u8> {
assert_eq!(
LINE_CONTENT.len(),
63,
"fixture line content must stay 63 bytes so each LF record is 64 bytes"
);
let mut buf = Vec::with_capacity(FIXTURE_SIZE_BYTES);
let line_len = LINE_CONTENT.len() + 1;
while buf.len() + line_len <= FIXTURE_SIZE_BYTES {
buf.extend_from_slice(LINE_CONTENT);
buf.push(b'\n');
}
let remaining = FIXTURE_SIZE_BYTES - buf.len();
if remaining > 0 {
buf.extend(std::iter::repeat(b'P').take(remaining));
}
debug_assert_eq!(buf.len(), FIXTURE_SIZE_BYTES);
buf
}
pub fn build_a13_fixture_crlf() -> Vec<u8> {
assert_eq!(LINE_CONTENT.len(), 63);
let lf = build_a13_fixture();
let mut out = Vec::with_capacity(lf.len() + lf.iter().filter(|&&b| b == b'\n').count());
let mut index = 0usize;
while index < lf.len() {
if lf[index] == b'\n' {
out.push(b'\r');
out.push(b'\n');
index += 1;
continue;
}
if !lf[index..].contains(&b'\n') {
out.extend_from_slice(&lf[index..]);
break;
}
out.push(lf[index]);
index += 1;
}
out
}
pub fn sha256_hex(bytes: &[u8]) -> String {
let digest = Sha256::digest(bytes);
let mut hex = String::with_capacity(digest.len() * 2);
for byte in digest {
use std::fmt::Write as _;
let _ = write!(hex, "{byte:02x}");
}
hex
}
pub fn normalize_agent_path_spelling(path: &str) -> String {
path.replace('\\', "/")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fixture_is_exactly_one_mib_with_pinned_checksum() {
let bytes = build_a13_fixture();
assert_eq!(bytes.len(), FIXTURE_SIZE_BYTES);
assert_eq!(sha256_hex(&bytes), FIXTURE_SHA256_HEX);
}
#[test]
fn crlf_twin_preserves_logical_line_contents() {
let lf = build_a13_fixture();
let crlf = build_a13_fixture_crlf();
assert!(crlf.len() > lf.len(), "CRLF twin must be larger");
assert!(
crlf.windows(2).any(|pair| pair == b"\r\n"),
"CRLF twin must contain CRLF terminators"
);
let lf_has_padding_tail = !lf.ends_with(b"\n");
if lf_has_padding_tail {
assert!(!crlf.ends_with(b"\n"));
assert!(!crlf.ends_with(b"\r\n"));
} else {
assert!(crlf.ends_with(b"\r\n"));
}
}
#[test]
fn agent_path_spelling_normalizes_windows_separators() {
assert_eq!(
normalize_agent_path_spelling(r"src\hashline\release\mod.rs"),
"src/hashline/release/mod.rs"
);
assert_eq!(
normalize_agent_path_spelling("src/hashline/release/mod.rs"),
"src/hashline/release/mod.rs"
);
}
}