use probe_code::search::query::{preprocess_query, regex_escape, create_term_patterns};
#[cfg(test)]
use std::collections::HashSet;
#[test]
fn test_preprocess_query() {
let exact_result = preprocess_query("findAPI inCode", true);
assert_eq!(
exact_result,
vec![
("findapi".to_string(), "findapi".to_string()),
("incode".to_string(), "incode".to_string()),
]
);
let non_exact_result = preprocess_query("findAPIInCode typeIgnore", false);
println!("Actual result: {non_exact_result:?}");
assert_eq!(
non_exact_result,
vec![
("find".to_string(), "find".to_string()),
("api".to_string(), "api".to_string()),
("code".to_string(), "code".to_string()),
("type".to_string(), "type".to_string()),
("ignore".to_string(), "ignor".to_string()),
]
);
}
#[test]
fn test_preprocess_query_with_stemming() {
let query = "searching functions";
let terms = preprocess_query(query, false);
assert_eq!(terms.len(), 2);
let search_term = terms.iter().find(|(orig, _)| orig == "searching");
assert!(search_term.is_some());
let (orig, stemmed) = search_term.unwrap();
assert_eq!(orig, "searching");
assert_eq!(stemmed, "search"); }
#[test]
fn test_preprocess_query_empty() {
let query = "";
let terms = preprocess_query(query, false);
assert_eq!(terms.len(), 0);
}
#[test]
fn test_preprocess_query_only_stop_words() {
let query = "the and of";
let terms = preprocess_query(query, false);
assert_eq!(terms.len(), 0);
}
#[test]
fn test_preprocess_query_exact_mode() {
let query = "ip whitelist";
let exact_terms = preprocess_query(query, true);
assert_eq!(exact_terms.len(), 2);
let has_ip = exact_terms.iter().any(|(orig, stemmed)| orig == "ip" && stemmed == "ip");
let has_whitelist = exact_terms.iter().any(|(orig, stemmed)| orig == "whitelist" && stemmed == "whitelist");
assert!(has_ip);
assert!(has_whitelist);
let query_with_stop = "the ip whitelist for security";
let exact_with_stop = preprocess_query(query_with_stop, true);
assert_eq!(exact_with_stop.len(), 5);
let has_the = exact_with_stop.iter().any(|(orig, _)| orig == "the");
let has_for = exact_with_stop.iter().any(|(orig, _)| orig == "for");
assert!(has_the);
assert!(has_for);
}
#[test]
fn test_regex_escape() {
let special_chars = ".*+?()[]{}|^$\\";
let escaped = regex_escape(special_chars);
assert_eq!(escaped, "\\.\\*\\+\\?\\(\\)\\[\\]\\{\\}\\|\\^\\$\\\\");
let normal_text = "normal text";
let escaped_normal = regex_escape(normal_text);
assert_eq!(escaped_normal, normal_text);
}
#[test]
fn test_create_term_patterns() {
let term_pairs = vec![
("search".to_string(), "search".to_string()),
("function".to_string(), "function".to_string()),
("running".to_string(), "run".to_string()),
];
let patterns = create_term_patterns(&term_pairs);
let search_pattern = patterns.iter().find(|(p, indices)|
indices.len() == 1 && indices.contains(&0) && p.contains("search")
);
let function_pattern = patterns.iter().find(|(p, indices)|
indices.len() == 1 && indices.contains(&1) && p.contains("function")
);
let running_pattern = patterns.iter().find(|(p, indices)|
indices.len() == 1 && indices.contains(&2) && p.contains("running|run")
);
assert!(search_pattern.is_some(), "No pattern found for 'search'");
assert!(function_pattern.is_some(), "No pattern found for 'function'");
assert!(running_pattern.is_some(), "No pattern found for 'running|run'");
assert_eq!(search_pattern.unwrap().1, HashSet::from([0]));
assert_eq!(function_pattern.unwrap().1, HashSet::from([1]));
assert_eq!(running_pattern.unwrap().1, HashSet::from([2]));
assert!(search_pattern.unwrap().0.contains("\\b"));
assert!(function_pattern.unwrap().0.contains("\\b"));
assert!(running_pattern.unwrap().0.contains("\\b"));
let search_function_pattern = patterns.iter().find(|(_, indices)|
indices.len() == 2 && indices.contains(&0) && indices.contains(&1)
);
let search_running_pattern = patterns.iter().find(|(_, indices)|
indices.len() == 2 && indices.contains(&0) && indices.contains(&2)
);
let function_running_pattern = patterns.iter().find(|(_, indices)|
indices.len() == 2 && indices.contains(&1) && indices.contains(&2)
);
assert!(search_function_pattern.is_some(), "No pattern found for 'search' + 'function'");
assert!(search_running_pattern.is_some(), "No pattern found for 'search' + 'running'");
assert!(function_running_pattern.is_some(), "No pattern found for 'function' + 'running'");
}
#[test]
fn test_create_term_patterns_with_regex_chars() {
let terms = vec![
("search.term".to_string(), "search.term".to_string()),
("function(x)".to_string(), "function(x)".to_string()),
];
let patterns = create_term_patterns(&terms);
let search_term_pattern = patterns.iter().find(|(p, indices)|
indices.len() == 1 && indices.contains(&0) && p.contains("search\\.term")
);
let function_x_pattern = patterns.iter().find(|(p, indices)|
indices.len() == 1 && indices.contains(&1) && p.contains("function\\(x\\)")
);
assert!(search_term_pattern.is_some(), "No pattern found for 'search.term'");
assert!(function_x_pattern.is_some(), "No pattern found for 'function(x)'");
assert_eq!(search_term_pattern.unwrap().1, HashSet::from([0]));
assert_eq!(function_x_pattern.unwrap().1, HashSet::from([1]));
let concatenated = patterns.iter().find(|(p, indices)|
indices.len() == 2 && indices.contains(&0) && indices.contains(&1) &&
(p.contains("search\\.term") && p.contains("function\\(x\\)"))
);
assert!(concatenated.is_some(), "No concatenated pattern found");
}
#[test]
fn test_create_term_patterns_with_flexible_boundaries() {
let term_pairs = vec![
("ip".to_string(), "ip".to_string()),
("address".to_string(), "address".to_string()),
];
let patterns = create_term_patterns(&term_pairs);
let ip_pattern = patterns.iter().find(|(p, indices)|
indices.len() == 1 && indices.contains(&0) && p.contains("ip")
);
let address_pattern = patterns.iter().find(|(p, indices)|
indices.len() == 1 && indices.contains(&1) && p.contains("address")
);
assert!(ip_pattern.is_some(), "No pattern found for 'ip'");
assert!(address_pattern.is_some(), "No pattern found for 'address'");
assert_eq!(ip_pattern.unwrap().1, HashSet::from([0]));
assert_eq!(address_pattern.unwrap().1, HashSet::from([1]));
assert!(ip_pattern.unwrap().0.contains("\\b"));
assert!(address_pattern.unwrap().0.contains("\\b"));
let ip_address_pattern = patterns.iter().find(|(_, indices)|
indices.len() == 2 && indices.contains(&0) && indices.contains(&1)
);
assert!(ip_address_pattern.is_some(), "No pattern found for 'ip' + 'address'");
let pattern_str = ip_address_pattern.unwrap().0.clone();
assert!(pattern_str.contains("ip") && pattern_str.contains("address"),
"Concatenated pattern doesn't contain both terms: {}", pattern_str);
}
#[test]
fn test_preprocess_query_with_compound_words() {
let query = "whitelist";
let terms = preprocess_query(query, false);
println!("Processed terms for 'whitelist': {terms:?}");
let has_white = terms.iter().any(|(_, stemmed)| stemmed == "white");
let has_list = terms.iter().any(|(_, stemmed)| stemmed == "list");
assert!(
has_white && has_list,
"Expected 'whitelist' to be split into 'white' and 'list', but got: {:?}",
terms
);
}
#[test]
fn test_preprocess_query_english_stop_words() {
let query = "ENGLISH_STOP_WORDS";
let terms = preprocess_query(query, false);
println!("Preprocessed terms for 'ENGLISH_STOP_WORDS': {terms:?}");
let has_english = terms.iter().any(|(_, stemmed)| stemmed == "english");
let has_stop = terms.iter().any(|(_, stemmed)| stemmed == "stop");
let has_word = terms.iter().any(|(_, stemmed)| stemmed == "word");
assert!(has_english, "Expected 'english' in the stemmed terms");
assert!(has_stop, "Expected 'stop' in the stemmed terms");
assert!(has_word, "Expected 'word' in the stemmed terms");
}
#[test]
fn test_preprocess_query_with_negated_terms() {
let query = "foo AND -bar";
let terms = preprocess_query(query, false);
println!("Preprocessed terms for 'foo AND -bar': {terms:?}");
let has_foo = terms.iter().any(|(orig, _)| orig == "foo");
assert!(has_foo, "Expected 'foo' in the terms");
let has_bar = terms.iter().any(|(orig, _)| orig == "bar");
assert!(!has_bar, "Did not expect 'bar' in the terms as it was negated");
let query = "search -test -ignore";
let terms = preprocess_query(query, false);
println!("Preprocessed terms for 'search -test -ignore': {terms:?}");
let has_search = terms.iter().any(|(orig, _)| orig == "search");
assert!(has_search, "Expected 'search' in the terms");
let has_test = terms.iter().any(|(orig, _)| orig == "test");
let has_ignore = terms.iter().any(|(orig, _)| orig == "ignore");
assert!(!has_test, "Did not expect 'test' in the terms as it was negated");
assert!(!has_ignore, "Did not expect 'ignore' in the terms as it was negated");
}