1pub fn normalize(text: &str) -> String {
5 text.replace("\r\n", "\n").replace('\r', "\n")
6}
7
8pub fn content_hash(text: &str) -> String {
10 use sha2::Digest;
11 let normalized = normalize(text);
12 let mut hasher = sha2::Sha256::new();
13 hasher.update(normalized.as_bytes());
14 let digest = hasher.finalize();
15 format!("sha256:{}", hex::encode(digest))
16}
17
18#[cfg(test)]
19mod tests {
20 use super::*;
21
22 #[test]
24 fn crlf_と_lf_は同じハッシュになる() {
25 let lf = "line one\nline two\n";
26 let crlf = "line one\r\nline two\r\n";
27 assert_eq!(content_hash(lf), content_hash(crlf));
28 }
29
30 #[test]
32 fn content_hash_はsha256プレフィックス付きの小文字hexを返す() {
33 let hash = content_hash("hello");
34 assert!(hash.starts_with("sha256:"), "unexpected hash: {hash}");
35 let hex = hash.strip_prefix("sha256:").unwrap();
36 assert_eq!(hex.len(), 64);
37 assert!(hex
38 .chars()
39 .all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase()));
40 assert_ne!(content_hash("hello"), content_hash("hello "));
42 }
43
44 #[test]
46 fn 単独crもlfと同じハッシュになる() {
47 let lf = "a\nb";
48 let cr = "a\rb";
49 assert_eq!(content_hash(lf), content_hash(cr));
50 }
51}