Skip to main content

discovery/
fingerprint.rs

1use std::collections::HashSet;
2
3#[must_use]
4pub fn fingerprint(origin: &str, standard: &str, url: &str) -> String {
5    format!("{origin}\0{standard}\0{url}")
6}
7
8pub struct DedupSet {
9    seen: HashSet<String>,
10}
11
12impl DedupSet {
13    #[must_use]
14    pub fn new() -> Self {
15        Self {
16            seen: HashSet::new(),
17        }
18    }
19
20    pub fn is_new(&mut self, origin: &str, standard: &str, url: &str) -> bool {
21        self.seen.insert(fingerprint(origin, standard, url))
22    }
23}
24
25impl Default for DedupSet {
26    fn default() -> Self {
27        Self::new()
28    }
29}
30
31#[cfg(test)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn fingerprint_format() {
37        let fp = fingerprint("https://example.com", "ard", "https://example.com/.well-known/ard.json");
38        assert_eq!(fp, "https://example.com\0ard\0https://example.com/.well-known/ard.json");
39    }
40
41    #[test]
42    fn different_fields_differ() {
43        let a = fingerprint("https://a.com", "ard", "/x");
44        let b = fingerprint("https://b.com", "ard", "/x");
45        assert_ne!(a, b);
46    }
47
48    #[test]
49    fn dedup_first_is_new() {
50        let mut ds = DedupSet::new();
51        assert!(ds.is_new("https://example.com", "ard", "/x"));
52    }
53
54    #[test]
55    fn dedup_second_is_not_new() {
56        let mut ds = DedupSet::new();
57        ds.is_new("https://example.com", "ard", "/x");
58        assert!(!ds.is_new("https://example.com", "ard", "/x"));
59    }
60
61    #[test]
62    fn dedup_different_standard_is_new() {
63        let mut ds = DedupSet::new();
64        ds.is_new("https://example.com", "ard", "/x");
65        assert!(ds.is_new("https://example.com", "other", "/x"));
66    }
67}