use diffguard_types::Finding;
use sha2::{Digest, Sha256};
pub fn compute_fingerprint(f: &Finding) -> String {
let input = format!("{}:{}:{}:{}", f.rule_id, f.path, f.line, f.match_text);
compute_fingerprint_raw(&input)
}
pub fn compute_fingerprint_raw(input: &str) -> String {
let hash = Sha256::digest(input.as_bytes());
hex::encode(hash)
}
#[cfg(test)]
mod tests {
use super::*;
use diffguard_types::Severity;
fn test_finding() -> Finding {
Finding {
rule_id: "rust.no_unwrap".to_string(),
severity: Severity::Error,
message: "Avoid unwrap".to_string(),
path: "src/lib.rs".to_string(),
line: 42,
column: Some(10),
match_text: ".unwrap()".to_string(),
snippet: "let x = foo.unwrap();".to_string(),
}
}
#[test]
fn fingerprint_is_64_hex_chars() {
let f = test_finding();
let fp = compute_fingerprint(&f);
assert_eq!(fp.len(), 64);
assert!(fp.chars().all(|c| c.is_ascii_hexdigit()));
}
#[test]
fn fingerprint_is_stable() {
let f = test_finding();
let fp1 = compute_fingerprint(&f);
let fp2 = compute_fingerprint(&f);
assert_eq!(fp1, fp2);
}
#[test]
fn fingerprint_differs_for_different_rule_id() {
let f1 = test_finding();
let mut f2 = test_finding();
f2.rule_id = "rust.no_dbg".to_string();
assert_ne!(compute_fingerprint(&f1), compute_fingerprint(&f2));
}
#[test]
fn fingerprint_differs_for_different_path() {
let f1 = test_finding();
let mut f2 = test_finding();
f2.path = "src/main.rs".to_string();
assert_ne!(compute_fingerprint(&f1), compute_fingerprint(&f2));
}
#[test]
fn fingerprint_differs_for_different_line() {
let f1 = test_finding();
let mut f2 = test_finding();
f2.line = 100;
assert_ne!(compute_fingerprint(&f1), compute_fingerprint(&f2));
}
#[test]
fn fingerprint_differs_for_different_match_text() {
let f1 = test_finding();
let mut f2 = test_finding();
f2.match_text = ".expect()".to_string();
assert_ne!(compute_fingerprint(&f1), compute_fingerprint(&f2));
}
#[test]
fn fingerprint_ignores_severity() {
let f1 = test_finding();
let mut f2 = test_finding();
f2.severity = Severity::Warn;
assert_eq!(compute_fingerprint(&f1), compute_fingerprint(&f2));
}
#[test]
fn fingerprint_ignores_message() {
let f1 = test_finding();
let mut f2 = test_finding();
f2.message = "Different message".to_string();
assert_eq!(compute_fingerprint(&f1), compute_fingerprint(&f2));
}
#[test]
fn snapshot_fingerprint_value() {
let f = test_finding();
let fp = compute_fingerprint(&f);
insta::assert_snapshot!(fp, @"d559ee3767f8ccda27b477039711c881d44c366e3bd8ea119649746bdff1a0b8");
}
#[test]
fn compute_fingerprint_raw_produces_64_hex() {
let fp = super::compute_fingerprint_raw("test:input");
assert_eq!(fp.len(), 64);
assert!(fp.chars().all(|c| c.is_ascii_hexdigit()));
}
}