use sha2::{Digest, Sha256};
pub fn compute_blob_sha(content: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(b"blob ");
hasher.update(content.len().to_string().as_bytes());
hasher.update(b"\0");
hasher.update(content.as_bytes());
format!("{:x}", hasher.finalize())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_blob_sha_deterministic() {
let content = "function foo() { return 1; }";
let sha1 = compute_blob_sha(content);
let sha2 = compute_blob_sha(content);
assert_eq!(sha1, sha2);
assert_eq!(sha1.len(), 64); }
#[test]
fn test_blob_sha_different_content() {
let content1 = "function foo() { return 1; }";
let content2 = "function bar() { return 2; }";
let sha1 = compute_blob_sha(content1);
let sha2 = compute_blob_sha(content2);
assert_ne!(sha1, sha2);
}
#[test]
fn test_blob_sha_whitespace_sensitive() {
let content1 = "function foo() { return 1; }";
let content2 = "function foo() { return 1; }"; let sha1 = compute_blob_sha(content1);
let sha2 = compute_blob_sha(content2);
assert_ne!(sha1, sha2);
}
#[test]
fn test_blob_sha_empty_content() {
let content = "";
let sha = compute_blob_sha(content);
assert_eq!(sha.len(), 64);
let sha2 = compute_blob_sha(content);
assert_eq!(sha, sha2);
}
#[test]
fn test_blob_sha_unicode() {
let content = "函数 foo() { return 'привет'; } // こんにちは";
let sha1 = compute_blob_sha(content);
let sha2 = compute_blob_sha(content);
assert_eq!(sha1, sha2);
assert_eq!(sha1.len(), 64);
let different = "函数 bar() { return 'привет'; } // こんにちは";
assert_ne!(sha1, compute_blob_sha(different));
}
#[test]
fn test_blob_sha_git_compatibility() {
let content = "test";
let sha = compute_blob_sha(content);
assert_eq!(sha.len(), 64);
assert!(sha.chars().all(|c| c.is_ascii_hexdigit()));
assert_eq!(sha, compute_blob_sha(content));
let expected = "aa19560d465e7d43915547490a1f6b73eb55702e3d12cb82fb577df60bad4928";
assert_eq!(sha, expected);
let empty = "";
let empty_sha = compute_blob_sha(empty);
let expected_empty = "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813";
assert_eq!(empty_sha, expected_empty);
}
#[test]
fn test_blob_sha_large_content() {
let large_content = "x".repeat(100_000);
let sha1 = compute_blob_sha(&large_content);
let sha2 = compute_blob_sha(&large_content);
assert_eq!(sha1, sha2);
assert_eq!(sha1.len(), 64);
}
#[test]
fn test_blob_sha_newlines() {
let content1 = "line1\nline2\nline3";
let content2 = "line1line2line3";
assert_ne!(compute_blob_sha(content1), compute_blob_sha(content2));
let content_lf = "line1\nline2";
let content_crlf = "line1\r\nline2";
assert_ne!(compute_blob_sha(content_lf), compute_blob_sha(content_crlf));
}
}