use probe_code::search::tokenization::tokenize_and_stem;
fn process_ast_terms(expr: Expr) -> Expr {
match expr {
Expr::Term { keywords, field, required, excluded, exact } => {
let processed_keywords = if exact || excluded {
keywords
} else {
let mut processed = Vec::new();
for keyword in keywords {
let stemmed = tokenize_and_stem(&keyword);
processed.extend(stemmed);
}
processed
};
Expr::Term {
keywords: processed_keywords,
field,
required,
excluded,
exact,
}
},
Expr::And(left, right) => {
Expr::And(
Box::new(process_ast_terms(*left)),
Box::new(process_ast_terms(*right))
)
},
Expr::Or(left, right) => {
Expr::Or(
Box::new(process_ast_terms(*left)),
Box::new(process_ast_terms(*right))
)
},
}
}
#[test]
fn test_tokenize_and_stem() {
let result = tokenize_and_stem("running");
assert_eq!(result, vec!["run"]);
let result = tokenize_and_stem("enableIpWhiteListing");
assert!(result.contains(&"enabl".to_string()));
assert!(result.contains(&"ip".to_string()));
assert!(result.contains(&"white".to_string()));
assert!(result.contains(&"list".to_string()));
let result = tokenize_and_stem("whitelist");
assert!(result.contains(&"whitelist".to_string()));
let result = tokenize_and_stem("function");
assert!(result.len() == 1);
let result = tokenize_and_stem("firewall");
assert!(result.len() == 1);
assert!(result[0] == "firewall" || result[0] == "firewal");
}
#[test]
fn test_process_ast_terms() {
let expr = Expr::Term {
keywords: vec!["running".to_string()],
field: None,
required: false,
excluded: false,
exact: false,
};
let processed = process_ast_terms(expr);
if let Expr::Term { keywords, field, required, excluded, exact } = processed {
assert_eq!(keywords, vec!["run"]);
assert_eq!(field, None);
assert!(!required);
assert!(!excluded);
assert!(!exact);
} else {
panic!("Expected Term expression");
}
let expr = Expr::Term {
keywords: vec!["enableIpWhiteListing".to_string()],
field: None,
required: true,
excluded: false,
exact: false,
};
let processed = process_ast_terms(expr);
if let Expr::Term { keywords, field, required, excluded, exact } = processed {
assert!(keywords.contains(&"enabl".to_string()));
assert!(keywords.contains(&"ip".to_string()));
assert!(keywords.contains(&"white".to_string()));
assert!(keywords.contains(&"list".to_string()));
assert_eq!(field, None);
assert!(required);
assert!(!excluded);
assert!(!exact);
} else {
panic!("Expected Term expression");
}
let expr = Expr::And(
Box::new(Expr::Term {
keywords: vec!["running".to_string()],
field: None,
required: false,
excluded: false,
exact: false,
}),
Box::new(Expr::Term {
keywords: vec!["whitelist".to_string()],
field: None,
required: false,
excluded: false,
exact: false,
})
);
let processed = process_ast_terms(expr);
if let Expr::And(left, right) = processed {
if let Expr::Term { keywords, .. } = *left {
assert_eq!(keywords, vec!["run"]);
} else {
panic!("Expected Term expression for left side");
}
if let Expr::Term { keywords, .. } = *right {
assert!(keywords.contains(&"whitelist".to_string()));
} else {
panic!("Expected Term expression for right side");
}
} else {
panic!("Expected And expression");
}
}
#[test]
fn test_parse_query_with_tokenization() {
let result = parse_query_test("running").unwrap();
if let Expr::Term { keywords, .. } = result {
assert_eq!(keywords, vec!["run"]);
} else {
panic!("Expected Term expression");
}
let result = parse_query_test("enableIpWhiteListing").unwrap();
if let Expr::Term { keywords, .. } = result {
assert!(keywords.contains(&"enabl".to_string()));
assert!(keywords.contains(&"ip".to_string()));
assert!(keywords.contains(&"white".to_string()));
assert!(keywords.contains(&"list".to_string()));
} else {
panic!("Expected Term expression");
}
let result = parse_query_test("running AND whitelist").unwrap();
if let Expr::And(left, right) = result {
if let Expr::Term { keywords, .. } = *left {
assert_eq!(keywords, vec!["run"]);
} else {
panic!("Expected Term expression for left side");
}
if let Expr::Term { keywords, .. } = *right {
assert!(keywords.contains(&"whitelist".to_string()));
} else {
panic!("Expected Term expression for right side");
}
} else {
panic!("Expected And expression");
}
}
#[test]
fn test_query_evaluation_with_tokenization() {
let mut term_indices = HashMap::new();
term_indices.insert("run".to_string(), 0);
term_indices.insert("whitelist".to_string(), 1);
let expr = parse_query_test("running").unwrap();
let matched_terms = HashSet::from([0]); assert!(expr.evaluate(&matched_terms, &term_indices, false));
let matched_terms = HashSet::from([1]); assert!(!expr.evaluate(&matched_terms, &term_indices, false));
let expr = parse_query_test("running AND whitelist").unwrap();
let matched_terms = HashSet::from([0, 1]); assert!(expr.evaluate(&matched_terms, &term_indices, false));
let matched_terms = HashSet::from([0]); assert!(!expr.evaluate(&matched_terms, &term_indices, false));
}
#[test]
fn test_tokenize_quoted_strings() {
let tokens = tokenize("\"hello world\"").unwrap();
assert_eq!(tokens.len(), 1);
assert_eq!(tokens[0], Token::QuotedString("hello world".to_string()));
let tokens = tokenize("\"hello \\\"world\\\"\"").unwrap();
assert_eq!(tokens.len(), 1);
assert_eq!(tokens[0], Token::QuotedString("hello \"world\"".to_string()));
let tokens = tokenize("foo \"bar baz\" qux").unwrap();
assert_eq!(tokens.len(), 3);
assert_eq!(tokens[0], Token::Ident("foo".to_string()));
assert_eq!(tokens[1], Token::QuotedString("bar baz".to_string()));
assert_eq!(tokens[2], Token::Ident("qux".to_string()));
let tokens = tokenize("+\"required term\"").unwrap();
assert_eq!(tokens.len(), 2);
assert_eq!(tokens[0], Token::Plus);
assert_eq!(tokens[1], Token::QuotedString("required term".to_string()));
let tokens = tokenize("-\"excluded term\"").unwrap();
assert_eq!(tokens.len(), 2);
assert_eq!(tokens[0], Token::Minus);
assert_eq!(tokens[1], Token::QuotedString("excluded term".to_string()));
}
#[test]
fn test_parse_quoted_strings() {
let result = parse_query_test("\"hello world\"").unwrap();
if let Expr::Term { keywords, exact, .. } = result {
assert_eq!(keywords, vec!["hello world"]);
assert!(exact);
} else {
panic!("Expected Term expression");
}
let result = parse_query_test("+\"required term\"").unwrap();
if let Expr::Term { keywords, required, exact, .. } = result {
assert_eq!(keywords, vec!["required term"]);
assert!(required);
assert!(exact);
} else {
panic!("Expected Term expression");
}
let result = parse_query_test("-\"excluded term\"").unwrap();
if let Expr::Term { keywords, excluded, exact, .. } = result {
assert_eq!(keywords, vec!["excluded term"]);
assert!(excluded);
assert!(exact);
} else {
panic!("Expected Term expression");
}
let result = parse_query_test("\"exact term\" AND foo").unwrap();
if let Expr::And(left, right) = result {
if let Expr::Term { keywords, exact, .. } = *left {
assert_eq!(keywords, vec!["exact term"]);
assert!(exact);
} else {
panic!("Expected Term expression for left side");
}
if let Expr::Term { keywords, exact, .. } = *right {
assert!(keywords.contains(&"foo".to_string()));
assert!(!exact);
} else {
panic!("Expected Term expression for right side");
}
} else {
panic!("Expected And expression");
}
}
#[test]
fn test_process_ast_terms_with_exact_flag() {
let expr = Expr::Term {
keywords: vec!["running".to_string()],
field: None,
required: false,
excluded: false,
exact: true,
};
let processed = process_ast_terms(expr);
if let Expr::Term { keywords, field, required, excluded, exact } = processed {
assert_eq!(keywords, vec!["running"]);
assert_eq!(field, None);
assert!(!required);
assert!(!excluded);
assert!(exact);
} else {
panic!("Expected Term expression");
}
let expr = Expr::And(
Box::new(Expr::Term {
keywords: vec!["running".to_string()],
field: None,
required: false,
excluded: false,
exact: false,
}),
Box::new(Expr::Term {
keywords: vec!["whitelist".to_string()],
field: None,
required: false,
excluded: false,
exact: true,
})
);
let processed = process_ast_terms(expr);
if let Expr::And(left, right) = processed {
if let Expr::Term { keywords, exact, .. } = *left {
assert_eq!(keywords, vec!["run"]);
assert!(!exact);
} else {
panic!("Expected Term expression for left side");
}
if let Expr::Term { keywords, exact, .. } = *right {
assert_eq!(keywords, vec!["whitelist"]);
assert!(exact);
} else {
panic!("Expected Term expression for right side");
}
} else {
panic!("Expected And expression");
}
}
#[test]
fn test_evaluate_exact_terms_tokenization() {
let mut term_indices = HashMap::new();
term_indices.insert("running".to_string(), 0);
term_indices.insert("run".to_string(), 1);
term_indices.insert("whitelist".to_string(), 2);
term_indices.insert("white".to_string(), 3);
term_indices.insert("list".to_string(), 4);
let expr = Expr::Term {
keywords: vec!["running".to_string()],
field: None,
required: false,
excluded: false,
exact: true,
};
let matched_terms = HashSet::from([0]); assert!(expr.evaluate(&matched_terms, &term_indices, false));
let matched_terms = HashSet::from([1]); assert!(!expr.evaluate(&matched_terms, &term_indices, false));
let expr = Expr::Term {
keywords: vec!["run".to_string()], field: None,
required: false,
excluded: false,
exact: false,
};
let mut term_indices_updated = HashMap::new();
term_indices_updated.insert("run".to_string(), 1); term_indices_updated.insert("running".to_string(), 0); term_indices_updated.insert("whitelist".to_string(), 2);
term_indices_updated.insert("white".to_string(), 3);
term_indices_updated.insert("list".to_string(), 4);
let matched_terms = HashSet::from([0, 1]); assert!(expr.evaluate(&matched_terms, &term_indices_updated, false));
let matched_terms = HashSet::from([1]); assert!(expr.evaluate(&matched_terms, &term_indices, false));
let expr = Expr::And(
Box::new(Expr::Term {
keywords: vec!["run".to_string()], field: None,
required: false,
excluded: false,
exact: false,
}),
Box::new(Expr::Term {
keywords: vec!["whitelist".to_string()],
field: None,
required: false,
excluded: false,
exact: true,
})
);
let matched_terms = HashSet::from([1, 2]); assert!(expr.evaluate(&matched_terms, &term_indices, false));
let matched_terms = HashSet::from([0, 3, 4]); assert!(!expr.evaluate(&matched_terms, &term_indices, false));
}