mod test_helpers;
use reflex::{Language, QueryFilter, SymbolKind};
use test_helpers::*;
#[test]
fn test_rust_function_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Function),
file_pattern: Some("rust/functions.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("function", filter);
assert_result_count_at_least(&results, 10);
assert_symbol_found(&results, "public_function", SymbolKind::Function);
assert_symbol_found(&results, "async_function", SymbolKind::Function);
assert_symbol_found(&results, "generic_function", SymbolKind::Function);
}
#[test]
fn test_rust_struct_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Struct),
file_pattern: Some("rust/structs.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("oin", filter);
assert_result_count_at_least(&results, 1);
assert_symbol_found(&results, "Point", SymbolKind::Struct);
}
#[test]
fn test_rust_enum_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Enum),
file_pattern: Some("rust/enums.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("tat", filter);
assert_result_count_at_least(&results, 1);
assert_symbol_found(&results, "Status", SymbolKind::Enum);
}
#[test]
fn test_rust_trait_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Trait),
file_pattern: Some("rust/traits.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("able", filter);
assert_result_count_at_least(&results, 2);
assert_symbol_found(&results, "Drawable", SymbolKind::Trait);
assert_symbol_found(&results, "Serializable", SymbolKind::Trait);
}
#[test]
fn test_rust_method_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Function), file_pattern: Some("rust/impls.rs".to_string()),
..Default::default()
};
let results = query_corpus("new", filter);
assert_result_count_at_least(&results, 2);
}
#[test]
fn test_rust_module_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Module),
file_pattern: Some("rust/modules.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("mod", filter);
assert_result_count_at_least(&results, 3);
}
#[test]
fn test_typescript_class_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Class),
language: Some(Language::TypeScript),
file_pattern: Some("typescript/classes.ts".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("erson", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_typescript_interface_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Interface),
file_pattern: Some("typescript/interfaces.ts".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("ser", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_typescript_type_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Type),
file_pattern: Some("typescript/types.ts".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("oint", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_typescript_enum_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Enum),
file_pattern: Some("typescript/enums.ts".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("olor", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_javascript_function_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Function),
language: Some(Language::JavaScript),
file_pattern: Some("javascript/functions.js".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("function", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_javascript_class_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Class),
file_pattern: Some("javascript/classes.js".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("erson", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_php_class_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Class),
language: Some(Language::PHP),
file_pattern: Some("php/classes.php".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("erson", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_php_function_detection() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Function),
file_pattern: Some("php/functions.php".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("Function", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_fulltext_search_across_all_files() {
setup_corpus();
let filter = QueryFilter::default();
let results = query_corpus("function", filter);
assert_result_count_at_least(&results, 50);
let files = unique_files(&results);
assert!(files.len() > 10, "Should find matches in many files");
}
#[test]
fn test_fulltext_unicode_search() {
setup_corpus();
let filter = QueryFilter {
force: true, ..Default::default()
};
let results = query_corpus("ä½ å¥½", filter);
assert_result_count_at_least(&results, 1);
assert_file_match(&results, "unicode");
}
#[test]
fn test_fulltext_emoji_search() {
setup_corpus();
let filter = QueryFilter {
force: true, ..Default::default()
};
let results = query_corpus("🚀", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_fulltext_operator_search() {
setup_corpus();
let filter = QueryFilter::default();
let results = query_corpus("true && false", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_fulltext_special_chars() {
setup_corpus();
let filter = QueryFilter::default();
let results = query_corpus("std::", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_regex_digit_pattern() {
setup_corpus();
let filter = QueryFilter {
use_regex: true,
file_pattern: Some("rust/many_symbols.rs".to_string()),
..Default::default()
};
let results = query_corpus(r"func_\d{3}", filter);
assert_result_count_at_least(&results, 90);
}
#[test]
fn test_regex_alternation() {
setup_corpus();
let filter = QueryFilter {
use_regex: true,
..Default::default()
};
let results = query_corpus(r"(async|await)", filter);
assert_result_count_at_least(&results, 10);
}
#[test]
fn test_regex_character_class() {
setup_corpus();
let filter = QueryFilter {
use_regex: true,
file_pattern: Some("rust/single_char.rs".to_string()),
..Default::default()
};
let results = query_corpus(r"fn [a-z]\(\)", filter);
assert_result_count_at_least(&results, 7);
}
#[test]
fn test_regex_start_anchor() {
setup_corpus();
let filter = QueryFilter {
use_regex: true,
..Default::default()
};
let results = query_corpus(r"^pub fn", filter);
assert_result_count_at_least(&results, 20);
}
#[test]
fn test_regex_word_boundary() {
setup_corpus();
let filter = QueryFilter {
use_regex: true,
..Default::default()
};
let results = query_corpus(r"\btest\b", filter);
assert_result_count_at_least(&results, 5);
}
#[test]
fn test_filter_language_and_kind() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
language: Some(Language::Rust),
kind: Some(SymbolKind::Function),
use_contains: true, ..Default::default()
};
let results = query_corpus("async", filter);
assert_result_count_at_least(&results, 3);
assert_all_language(&results, Language::Rust);
assert_all_kind(&results, SymbolKind::Function);
}
#[test]
fn test_filter_language_kind_and_file() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
language: Some(Language::TypeScript),
kind: Some(SymbolKind::Class),
file_pattern: Some("typescript/classes.ts".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("erson", filter);
assert_result_count_at_least(&results, 1);
assert_all_language(&results, Language::TypeScript);
}
#[test]
fn test_filter_exact_match() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
exact: true,
file_pattern: Some("rust/functions.rs".to_string()),
..Default::default()
};
let results = query_corpus("public_function", filter);
assert_eq!(results.len(), 1);
assert_eq!(results[0].symbol.as_deref(), Some("public_function"));
}
#[test]
fn test_filter_with_limit() {
setup_corpus();
let filter = QueryFilter {
limit: Some(5),
..Default::default()
};
let results = query_corpus("function", filter);
assert_eq!(results.len(), 5);
}
#[test]
fn test_filter_symbols_mode_vs_fulltext() {
setup_corpus();
let fulltext_filter = QueryFilter {
use_contains: true, ..Default::default()
};
let fulltext_results = query_corpus("calculate", fulltext_filter);
let symbol_filter = QueryFilter {
symbols_mode: true,
use_contains: true, ..Default::default()
};
let symbol_results = query_corpus("calculate", symbol_filter);
assert!(fulltext_results.len() > symbol_results.len());
}
#[test]
fn test_filter_regex_with_symbols() {
setup_corpus();
let filter = QueryFilter {
use_regex: true,
symbols_mode: true,
kind: Some(SymbolKind::Function),
..Default::default()
};
let results = query_corpus(r"test\w+", filter);
assert_result_count_at_least(&results, 2);
}
#[test]
fn test_empty_file() {
setup_corpus();
let filter = QueryFilter {
file_pattern: Some("edge_cases/empty_file.txt".to_string()),
..Default::default()
};
let results = query_corpus("anything", filter);
assert_eq!(results.len(), 0);
}
#[test]
fn test_very_long_line() {
setup_corpus();
let filter = QueryFilter {
file_pattern: Some("rust/long_lines.rs".to_string()),
..Default::default()
};
let results = query_corpus("extremely", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_unicode_identifiers() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
file_pattern: Some("rust/unicode_identifiers.rs".to_string()),
..Default::default()
};
let results = query_corpus("café", filter);
assert_result_count_at_least(&results, 1);
assert_symbol_found(&results, "café", SymbolKind::Function);
}
#[test]
fn test_raw_identifiers() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
file_pattern: Some("rust/raw_identifiers.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("r#type", filter);
assert_result_count_at_least(&results, 1);
}
#[test]
fn test_whitespace_handling() {
setup_corpus();
let filter = QueryFilter {
file_pattern: Some("rust/weird_spacing.rs".to_string()),
..Default::default()
};
let results = query_corpus("pub fn", filter);
assert_result_count_at_least(&results, 4);
}
#[test]
fn test_many_symbols_performance() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
file_pattern: Some("rust/many_symbols.rs".to_string()),
use_contains: true, ..Default::default()
};
let start = std::time::Instant::now();
let results = query_corpus("func", filter);
let elapsed = start.elapsed();
assert_result_count_at_least(&results, 90);
assert!(elapsed.as_secs() < 5, "Query took too long: {:?}", elapsed);
}
#[test]
fn test_deterministic_results() {
setup_corpus();
let filter = QueryFilter::default();
let results1 = query_corpus("function", filter.clone());
let results2 = query_corpus("function", filter.clone());
let results3 = query_corpus("function", filter);
assert_eq!(results1.len(), results2.len());
assert_eq!(results1.len(), results3.len());
assert_sorted(&results1);
for i in 0..results1.len() {
assert_eq!(results1[i].path, results2[i].path);
assert_eq!(results1[i].span.start_line, results2[i].span.start_line);
}
}
#[test]
fn test_no_duplicate_results() {
setup_corpus();
let filter = QueryFilter::default();
let results = query_corpus("test", filter);
assert_no_duplicates(&results);
}
#[test]
fn test_find_async_functions() {
setup_corpus();
let filter = QueryFilter {
symbols_mode: true,
kind: Some(SymbolKind::Function),
use_contains: true, ..Default::default()
};
let results = query_corpus("async", filter);
assert_result_count_at_least(&results, 10);
}
#[test]
fn test_find_error_handling() {
setup_corpus();
let filter = QueryFilter {
file_pattern: Some("rust/error_handling.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("unwrap", filter);
assert_result_count_at_least(&results, 3);
}
#[test]
fn test_find_generic_functions() {
setup_corpus();
let filter = QueryFilter {
file_pattern: Some("rust/generics_complex.rs".to_string()),
use_contains: true, ..Default::default()
};
let results = query_corpus("<T>", filter);
assert_result_count_at_least(&results, 2);
}
#[test]
fn test_cross_language_search() {
setup_corpus();
let filter = QueryFilter::default();
let results = query_corpus("Point", filter);
let files = unique_files(&results);
assert!(files.iter().any(|f| f.contains("rust")));
assert!(files.iter().any(|f| f.contains("typescript")));
assert!(files.iter().any(|f| f.contains("javascript")));
}
#[test]
fn test_glob_filter_source_files_only() {
setup_corpus();
let filter = QueryFilter {
glob_patterns: vec!["**/filtered/src/**".to_string()],
..Default::default()
};
let results = query_corpus("extract_pattern", filter);
assert_result_count_at_least(&results, 3);
assert!(results.iter().all(|r| r.path.contains("filtered/src/")));
assert!(!results.iter().any(|r| r.path.contains("filtered/tests/")));
assert!(
!results
.iter()
.any(|r| r.path.contains("filtered/examples/"))
);
assert!(!results.iter().any(|r| r.path.contains("filtered/build/")));
}
#[test]
fn test_glob_filter_multiple_directories() {
setup_corpus();
let filter = QueryFilter {
glob_patterns: vec![
"**/filtered/src/**".to_string(),
"**/filtered/examples/**".to_string(),
],
..Default::default()
};
let results = query_corpus("extract_pattern", filter);
assert_result_count_at_least(&results, 4);
assert!(results.iter().any(|r| r.path.contains("filtered/src/")));
assert!(
results
.iter()
.any(|r| r.path.contains("filtered/examples/"))
);
assert!(!results.iter().any(|r| r.path.contains("filtered/tests/")));
assert!(!results.iter().any(|r| r.path.contains("filtered/build/")));
}
#[test]
fn test_glob_filter_specific_extension() {
setup_corpus();
let filter = QueryFilter {
glob_patterns: vec!["**/filtered/**/*.rs".to_string()],
use_contains: true, ..Default::default()
};
let results = query_corpus("extract", filter);
assert_result_count_at_least(&results, 5);
assert!(results.iter().all(|r| r.path.ends_with(".rs")));
assert!(!results.iter().any(|r| r.path.ends_with(".sh")));
}
#[test]
fn test_glob_with_todo_comments() {
setup_corpus();
let filter = QueryFilter {
glob_patterns: vec!["**/filtered/src/**".to_string()],
..Default::default()
};
let results = query_corpus("TODO", filter);
assert_result_count_at_least(&results, 3);
assert!(results.iter().all(|r| r.path.contains("filtered/src/")));
}
#[test]
fn test_exclude_generated_files() {
setup_corpus();
let filter = QueryFilter {
exclude_patterns: vec!["**/filtered/build/**".to_string()],
..Default::default()
};
let results = query_corpus("extract_pattern", filter);
assert!(!results.iter().any(|r| r.path.contains("filtered/build/")));
assert!(results.iter().any(|r| r.path.contains("filtered/src/")));
}
#[test]
fn test_exclude_test_files() {
setup_corpus();
let filter = QueryFilter {
exclude_patterns: vec!["**/filtered/tests/**".to_string()],
..Default::default()
};
let results = query_corpus("test_extract", filter);
assert!(!results.iter().any(|r| r.path.contains("filtered/tests/")));
}
#[test]
fn test_exclude_multiple_directories() {
setup_corpus();
let filter = QueryFilter {
exclude_patterns: vec![
"**/filtered/build/**".to_string(),
"**/filtered/tests/**".to_string(),
],
use_contains: true, ..Default::default()
};
let results = query_corpus("extract", filter);
assert!(!results.iter().any(|r| r.path.contains("filtered/build/")));
assert!(!results.iter().any(|r| r.path.contains("filtered/tests/")));
assert!(results.iter().any(|r| r.path.contains("filtered/src/")));
}
#[test]
fn test_exclude_scripts() {
setup_corpus();
let filter = QueryFilter {
exclude_patterns: vec!["**/filtered/scripts/**".to_string()],
..Default::default()
};
let results = query_corpus("extract_pattern", filter);
assert!(!results.iter().any(|r| r.path.contains("filtered/scripts/")));
}
#[test]
fn test_paths_only_deduplication_corpus() {
setup_corpus();
let filter = QueryFilter {
paths_only: true,
..Default::default()
};
let results = query_corpus("TODO", filter);
let files = unique_files(&results);
assert_eq!(results.len(), files.len(), "All paths should be unique");
assert!(results.len() >= 5);
}
#[test]
fn test_paths_only_with_glob() {
setup_corpus();
let filter = QueryFilter {
paths_only: true,
glob_patterns: vec!["**/filtered/src/**".to_string()],
..Default::default()
};
let results = query_corpus("extract", filter);
let files = unique_files(&results);
assert_eq!(results.len(), files.len());
assert!(results.iter().all(|r| r.path.contains("filtered/src/")));
}
#[test]
fn test_paths_only_with_exclude() {
setup_corpus();
let filter = QueryFilter {
paths_only: true,
exclude_patterns: vec!["**/filtered/build/**".to_string()],
..Default::default()
};
let results = query_corpus("TODO", filter);
let files = unique_files(&results);
assert_eq!(results.len(), files.len());
assert!(!results.iter().any(|r| r.path.contains("filtered/build/")));
}
#[test]
fn test_paths_only_listing_files_with_pattern() {
setup_corpus();
let filter = QueryFilter {
paths_only: true,
glob_patterns: vec!["**/filtered/**/*.rs".to_string()],
..Default::default()
};
let results = query_corpus("TODO", filter);
let files = unique_files(&results);
assert_eq!(results.len(), files.len());
assert!(results.iter().all(|r| r.path.ends_with(".rs")));
assert_result_count_at_least(&results, 3);
}
#[test]
fn test_glob_and_exclude_together_corpus() {
setup_corpus();
let filter = QueryFilter {
glob_patterns: vec!["**/filtered/**/*.rs".to_string()],
exclude_patterns: vec!["**/filtered/build/**".to_string()],
..Default::default()
};
let results = query_corpus("TODO", filter);
assert!(results.iter().all(|r| r.path.ends_with(".rs")));
assert!(!results.iter().any(|r| r.path.contains("filtered/build/")));
assert!(results.iter().any(|r| r.path.contains("filtered/src/")));
}
#[test]
fn test_glob_exclude_and_paths_together() {
setup_corpus();
let filter = QueryFilter {
glob_patterns: vec!["**/filtered/src/**".to_string()],
exclude_patterns: vec!["**/generated.rs".to_string()],
paths_only: true,
..Default::default()
};
let results = query_corpus("extract", filter);
let files = unique_files(&results);
assert_eq!(results.len(), files.len());
assert!(results.iter().all(|r| r.path.contains("filtered/src/")));
assert!(!results.iter().any(|r| r.path.contains("generated")));
}
#[test]
fn test_real_world_find_todos_in_source_only() {
setup_corpus();
let filter = QueryFilter {
glob_patterns: vec!["**/filtered/src/**".to_string()],
exclude_patterns: vec![
"**/filtered/tests/**".to_string(),
"**/filtered/examples/**".to_string(),
"**/filtered/build/**".to_string(),
],
paths_only: true,
..Default::default()
};
let results = query_corpus("TODO", filter);
let files = unique_files(&results);
assert_eq!(results.len(), files.len());
assert!(results.iter().all(|r| r.path.contains("filtered/src/")));
assert_result_count_at_least(&results, 3);
}
#[test]
fn test_real_world_exclude_generated_code() {
setup_corpus();
let filter = QueryFilter {
exclude_patterns: vec!["**/build/**".to_string(), "**/generated.rs".to_string()],
..Default::default()
};
let results = query_corpus("extract_pattern", filter);
assert!(!results.iter().any(|r| r.path.contains("/build/")));
assert!(!results.iter().any(|r| r.path.contains("generated.rs")));
}
#[test]
fn test_real_world_list_files_with_pattern() {
setup_corpus();
let filter = QueryFilter {
paths_only: true,
..Default::default()
};
let results = query_corpus("extract_pattern", filter);
let files = unique_files(&results);
assert_eq!(results.len(), files.len());
assert_result_count_at_least(&results, 5);
}