prx 0.5.9

Praxis — agent-native Unix tools. Single binary replacing grep, cat, find, sed, diff for AI coding agents.
use std::path::Path;
use xxhash_rust::xxh3::xxh3_128;

pub fn hash_bytes(data: &[u8]) -> String {
    format!("{:032x}", xxh3_128(data))
}

pub fn hash_file(path: &Path) -> Result<String, std::io::Error> {
    let data = std::fs::read(path)?;
    Ok(hash_bytes(&data))
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::Write;

    #[test]
    fn deterministic() {
        let a = hash_bytes(b"hello world");
        let b = hash_bytes(b"hello world");
        assert_eq!(a, b);
    }

    #[test]
    fn different_inputs_different_hashes() {
        let a = hash_bytes(b"hello");
        let b = hash_bytes(b"world");
        assert_ne!(a, b);
    }

    #[test]
    fn hex_length_is_32() {
        let h = hash_bytes(b"test");
        assert_eq!(h.len(), 32);
    }

    #[test]
    fn empty_input() {
        let h = hash_bytes(b"");
        assert_eq!(h.len(), 32);
    }

    #[test]
    fn hash_file_works() {
        let mut tmp = tempfile::NamedTempFile::new().unwrap();
        tmp.write_all(b"file content").unwrap();
        let h = hash_file(tmp.path()).unwrap();
        assert_eq!(h.len(), 32);
        assert_eq!(h, hash_bytes(b"file content"));
    }

    #[test]
    fn hash_file_not_found() {
        let result = hash_file(Path::new("/nonexistent/file.txt"));
        assert!(result.is_err());
    }
}