use pattern_core::{Pattern, Symbol};
use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
fn hash_pattern<V: Hash>(p: &Pattern<V>) -> u64 {
let mut hasher = DefaultHasher::new();
p.hash(&mut hasher);
hasher.finish()
}
#[test]
fn test_hashset_dedup_string_patterns() {
let p1 = Pattern::point("hello".to_string());
let p2 = Pattern::point("world".to_string());
let p3 = Pattern::point("hello".to_string());
let mut set = HashSet::new();
set.insert(p1);
set.insert(p2);
set.insert(p3);
assert_eq!(set.len(), 2, "HashSet should deduplicate equal patterns");
}
#[test]
fn test_hashset_dedup_symbol_patterns() {
let p1 = Pattern::point(Symbol("a".to_string()));
let p2 = Pattern::point(Symbol("b".to_string()));
let p3 = Pattern::point(Symbol("a".to_string()));
let mut set = HashSet::new();
set.insert(p1);
set.insert(p2);
set.insert(p3);
assert_eq!(set.len(), 2);
}
#[test]
fn test_hashset_membership() {
let p1 = Pattern::point("test".to_string());
let p2 = Pattern::point("other".to_string());
let mut set = HashSet::new();
set.insert(p1.clone());
assert!(set.contains(&p1), "Set should contain inserted pattern");
assert!(
!set.contains(&p2),
"Set should not contain pattern that wasn't inserted"
);
}
#[test]
fn test_hashset_nested_patterns() {
let p1 = Pattern::pattern(
"root".to_string(),
vec![
Pattern::point("a".to_string()),
Pattern::point("b".to_string()),
],
);
let p2 = Pattern::pattern(
"root".to_string(),
vec![
Pattern::point("a".to_string()),
Pattern::point("b".to_string()),
],
);
let mut set = HashSet::new();
set.insert(p1);
set.insert(p2);
assert_eq!(set.len(), 1, "Nested patterns should be deduplicated");
}
#[test]
fn test_equal_patterns_hash_equal_atomic() {
let p1 = Pattern::point("test".to_string());
let p2 = Pattern::point("test".to_string());
assert_eq!(p1, p2, "Patterns should be equal");
assert_eq!(
hash_pattern(&p1),
hash_pattern(&p2),
"Equal patterns must hash to same value"
);
}
#[test]
fn test_equal_patterns_hash_equal_nested() {
let p1 = Pattern::pattern(
"root".to_string(),
vec![
Pattern::point("a".to_string()),
Pattern::pattern("b".to_string(), vec![Pattern::point("c".to_string())]),
],
);
let p2 = Pattern::pattern(
"root".to_string(),
vec![
Pattern::point("a".to_string()),
Pattern::pattern("b".to_string(), vec![Pattern::point("c".to_string())]),
],
);
assert_eq!(p1, p2);
assert_eq!(hash_pattern(&p1), hash_pattern(&p2));
}
#[test]
fn test_different_values_hash_correctly() {
let p1 = Pattern::point("test1".to_string());
let p2 = Pattern::point("test2".to_string());
assert_ne!(p1, p2);
let hash1 = hash_pattern(&p1);
let hash2 = hash_pattern(&p2);
let _ = (hash1, hash2); }
#[test]
fn test_structure_affects_pattern_equality() {
let atomic = Pattern::point("value".to_string());
let compound = Pattern::pattern(
"value".to_string(),
vec![Pattern::point("child".to_string())],
);
assert_ne!(atomic, compound);
let hash1 = hash_pattern(&atomic);
let hash2 = hash_pattern(&compound);
let _ = (hash1, hash2); }
#[test]
fn test_hashmap_insert_lookup() {
let mut map: HashMap<Pattern<String>, i32> = HashMap::new();
let p1 = Pattern::point("key1".to_string());
let p2 = Pattern::point("key2".to_string());
map.insert(p1.clone(), 42);
map.insert(p2.clone(), 100);
assert_eq!(map.get(&p1), Some(&42));
assert_eq!(map.get(&p2), Some(&100));
}
#[test]
fn test_hashmap_update_existing() {
let mut map: HashMap<Pattern<String>, i32> = HashMap::new();
let p1 = Pattern::point("key".to_string());
let p1_dup = Pattern::point("key".to_string());
map.insert(p1.clone(), 42);
map.insert(p1_dup, 100);
assert_eq!(map.len(), 1);
assert_eq!(map.get(&p1), Some(&100));
}
#[test]
fn test_hashmap_nested_pattern_keys() {
let mut map: HashMap<Pattern<String>, &str> = HashMap::new();
let p1 = Pattern::pattern(
"root".to_string(),
vec![Pattern::point("child".to_string())],
);
let p2 = Pattern::pattern(
"root".to_string(),
vec![Pattern::point("child".to_string())],
);
map.insert(p1.clone(), "value1");
assert_eq!(map.get(&p2), Some(&"value1"));
}
#[test]
fn test_hashmap_caching_pattern() {
let mut cache: HashMap<Pattern<String>, i32> = HashMap::new();
let pattern = Pattern::pattern(
"computation".to_string(),
vec![Pattern::point("input".to_string())],
);
if !cache.contains_key(&pattern) {
cache.insert(pattern.clone(), 42); }
assert_eq!(cache.get(&pattern), Some(&42));
}
#[test]
fn test_symbol_hashable() {
let s1 = Symbol("test".to_string());
let s2 = Symbol("test".to_string());
let mut hasher1 = DefaultHasher::new();
s1.hash(&mut hasher1);
let hash1 = hasher1.finish();
let mut hasher2 = DefaultHasher::new();
s2.hash(&mut hasher2);
let hash2 = hasher2.finish();
assert_eq!(s1, s2);
assert_eq!(hash1, hash2, "Equal symbols should hash equally");
}
#[test]
fn test_pattern_symbol_in_hashset() {
let p1 = Pattern::point(Symbol("a".to_string()));
let p2 = Pattern::point(Symbol("b".to_string()));
let mut set = HashSet::new();
set.insert(p1.clone());
set.insert(p2.clone());
assert!(set.contains(&p1));
assert!(set.contains(&p2));
assert_eq!(set.len(), 2);
}