gobby_code/index/
hasher.rs1use std::path::Path;
5
6pub fn file_content_hash(path: &Path) -> anyhow::Result<String> {
8 Ok(gobby_core::indexing::file_content_hash(path)?)
9}
10
11pub fn content_hash(source: &[u8]) -> String {
13 gobby_core::indexing::content_hash(source)
14}
15
16pub fn symbol_content_hash(source: &[u8], start: usize, end: usize) -> anyhow::Result<String> {
18 let slice = source.get(start..end).ok_or_else(|| {
19 anyhow::anyhow!(
20 "invalid byte range {}..{} for source len {}",
21 start,
22 end,
23 source.len()
24 )
25 })?;
26 Ok(gobby_core::indexing::content_hash(slice))
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32 use proptest::prelude::*;
33
34 #[test]
35 fn file_content_hash_delegates_to_gobby_core() {
36 let tmp = tempfile::NamedTempFile::new().expect("tempfile");
37 std::fs::write(tmp.path(), b"hash me\n").expect("write file");
38
39 let actual = file_content_hash(tmp.path()).expect("hash via wrapper");
40 let expected =
41 gobby_core::indexing::file_content_hash(tmp.path()).expect("hash via gobby-core");
42 assert_eq!(actual, expected);
43
44 let source = include_str!("hasher.rs");
45 let delegate = ["gobby_core", "::indexing::file_content_hash"].concat();
46 let local_buffer = format!("let mut buf = [0u8; {}]", 64 * 1024);
47 assert!(source.contains(&delegate));
48 assert!(!source.contains(&local_buffer));
49 }
50
51 #[test]
52 fn content_hash_delegates_to_gobby_core() {
53 let source = b"hash me from memory\n";
54
55 assert_eq!(
56 content_hash(source),
57 gobby_core::indexing::content_hash(source)
58 );
59 }
60
61 proptest! {
62 #[test]
63 fn content_hash_matches_gobby_core_for_arbitrary_bytes(
64 source in proptest::collection::vec(any::<u8>(), 0..4096),
65 ) {
66 prop_assert_eq!(
67 content_hash(&source),
68 gobby_core::indexing::content_hash(&source)
69 );
70 }
71
72 #[test]
73 fn symbol_content_hash_matches_gobby_core_for_valid_slices(
74 source in proptest::collection::vec(any::<u8>(), 0..4096),
75 raw_start in 0usize..4096,
76 raw_len in 0usize..4096,
77 ) {
78 let start = raw_start.min(source.len());
79 let end = (start + raw_len).min(source.len());
80 let actual = symbol_content_hash(&source, start, end).expect("valid slice hashes");
81 let expected = gobby_core::indexing::content_hash(&source[start..end]);
82
83 prop_assert_eq!(actual, expected);
84 }
85 }
86}