use probe_code::ranking::{
tokenize, get_stemmer, compute_tf_df,
compute_avgdl, rank_documents, RankingParams,
QueryTokenMap
};
use probe_code::search::tokenization::is_stop_word;
fn rank_documents(documents: &[&str], query: &str) -> Vec<(usize, f64, f64, f64, f64)> {
let params = RankingParams {
documents,
query,
file_unique_terms: None,
file_total_matches: None,
file_match_rank: None,
block_unique_terms: None,
block_total_matches: None,
node_type: None,
};
let results = crate::ranking::rank_documents(¶ms);
results.into_iter()
.map(|(idx, bm25_score)| (idx, bm25_score, 0.0, bm25_score, bm25_score))
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_stop_words() {
assert!(is_stop_word("the"));
assert!(is_stop_word("and"));
assert!(is_stop_word("of"));
assert!(is_stop_word("function"));
assert!(is_stop_word("class"));
assert!(is_stop_word("return"));
}
#[test]
fn test_tokenize_basic() {
let text = "The quick brown fox jumps over the lazy dog";
let tokens = tokenize(text);
assert!(!tokens.contains(&"the".to_string()));
assert!(!tokens.contains(&"over".to_string()));
assert!(tokens.contains(&"quick".to_string()));
assert!(tokens.contains(&"brown".to_string()));
assert!(tokens.contains(&"fox".to_string()));
assert!(tokens.contains(&"jump".to_string())); assert!(tokens.contains(&"lazi".to_string())); assert!(tokens.contains(&"dog".to_string()));
}
#[test]
fn test_tokenize_code() {
let code = "function calculateTotal(items) { return items.reduce((sum, item) => sum + item.price, 0); }";
let tokens = tokenize(code);
assert!(!tokens.contains(&"function".to_string()));
assert!(!tokens.contains(&"return".to_string()));
assert!(tokens.contains(&"calculatetot".to_string())); assert!(tokens.contains(&"item".to_string()));
assert!(tokens.contains(&"reduc".to_string())); assert!(tokens.contains(&"sum".to_string()));
assert!(tokens.contains(&"price".to_string()));
}
#[test]
fn test_tokenize_with_punctuation() {
let text = "This, is a test. With multiple punctuation marks! And some numbers: 123, 456.";
let tokens = tokenize(text);
assert!(!tokens.contains(&"a".to_string()));
assert!(!tokens.contains(&"is".to_string()));
assert!(!tokens.contains(&"and".to_string()));
assert!(!tokens.contains(&"some".to_string()));
assert!(!tokens.contains(&"with".to_string()));
assert!(tokens.contains(&"test".to_string()));
assert!(tokens.contains(&"multipl".to_string())); assert!(tokens.contains(&"punctuat".to_string())); assert!(tokens.contains(&"mark".to_string())); assert!(tokens.contains(&"number".to_string()));
assert!(tokens.contains(&"123".to_string()));
assert!(tokens.contains(&"456".to_string()));
}
#[test]
fn test_stemming_consistency() {
let stemmer = get_stemmer();
let pairs = vec![
("run", "running"),
("code", "coding"),
("search", "searching"),
("function", "functions"),
("calculate", "calculation"),
];
for (word1, word2) in pairs {
let stem1 = stemmer.stem(word1).to_string();
let stem2 = stemmer.stem(word2).to_string();
assert_eq!(stem1, stem2, "{} and {} should stem to the same token", word1, word2);
}
}
#[test]
fn test_compute_tf_df() {
let documents = vec![
"the quick brown fox",
"the quick brown",
"the fox jumps",
];
let (tfs, dfs, lengths) = compute_tf_df(&documents);
assert_eq!(lengths[0], 3); assert_eq!(lengths[1], 2); assert_eq!(lengths[2], 2);
assert_eq!(tfs[0].get("fox"), Some(&1));
assert_eq!(tfs[0].get("quick"), Some(&1));
assert_eq!(tfs[0].get("brown"), Some(&1));
assert_eq!(dfs.get("fox"), Some(&2)); assert_eq!(dfs.get("quick"), Some(&2)); assert_eq!(dfs.get("brown"), Some(&2)); assert_eq!(dfs.get("jump"), Some(&1)); }
#[test]
fn test_compute_avgdl() {
let lengths = vec![5, 10, 15];
let avgdl = compute_avgdl(&lengths);
assert_eq!(avgdl, 10.0);
let empty_lengths: Vec<usize> = vec![];
let avgdl_empty = compute_avgdl(&empty_lengths);
assert_eq!(avgdl_empty, 0.0);
}
#[test]
fn test_rank_documents() {
let documents = vec![
"the quick brown fox", "the quick brown", "the fox jumps", "fox fox fox", ];
let ranked_docs = rank_documents(&documents, "fox");
assert_eq!(ranked_docs[0].0, 3);
let doc_indices: Vec<usize> = ranked_docs.iter().map(|(idx, _, _, _, _)| *idx).collect();
assert!(doc_indices.contains(&0));
assert!(doc_indices.contains(&2));
assert!(ranked_docs.last().unwrap().0 == 1 || !doc_indices.contains(&1));
}
#[test]
fn test_rank_documents_multi_term() {
let documents = vec![
"search function implementation", "search algorithm", "function declaration", "unrelated document", ];
let ranked_docs = rank_documents(&documents, "search function");
assert_eq!(ranked_docs[0].0, 0);
let doc_indices: Vec<usize> = ranked_docs.iter().map(|(idx, _, _, _, _)| *idx).collect();
assert!(doc_indices.contains(&1));
assert!(doc_indices.contains(&2));
assert_eq!(ranked_docs.last().unwrap().0, 3);
}
#[test]
fn test_rank_documents_stemming() {
let documents = vec![
"searching functions", "search implementation", "functional programming", ];
let ranked_docs = rank_documents(&documents, "search function");
let top_docs: Vec<usize> = ranked_docs.iter()
.take(2)
.map(|(idx, _, _, _, _)| *idx)
.collect();
assert!(top_docs.contains(&0)); assert!(top_docs.contains(&2)); }
}