#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_symbol_table_insertion_and_lookup() {
let table = SymbolTable::new();
let qname = QualifiedName::new(
vec!["std".to_string(), "collections".to_string()],
"HashMap".to_string(),
);
let location = Location::new(PathBuf::from("src/lib.rs"), 100, 200);
table.insert(qname.clone(), location.clone());
assert_eq!(table.get_location(&qname), Some(location));
assert_eq!(table.len(), 1);
}
#[test]
fn test_relative_location_resolution() {
let table = SymbolTable::new();
let file_path = PathBuf::from("src/lib.rs");
let rel_span = RelativeLocation::Span {
start: 100,
end: 200,
};
let resolved = table.resolve_relative(&rel_span, &file_path).unwrap();
assert_eq!(resolved.file_path, file_path);
assert_eq!(resolved.span.start.0, 100);
assert_eq!(resolved.span.end.0, 200);
}
#[test]
fn test_qualified_name_parsing() {
let qname = QualifiedName::from_string("std::collections::HashMap").unwrap();
assert_eq!(qname.module_path, vec!["std", "collections"]);
assert_eq!(qname.name, "HashMap");
assert_eq!(qname.to_string(), "std::collections::HashMap");
}
#[test]
fn test_symbol_table_builder() {
let builder = SymbolTableBuilder::new();
let qname = QualifiedName::new(vec!["test".to_string()], "function".to_string());
let location = Location::new(PathBuf::from("test.rs"), 0, 10);
builder.add_symbol(qname.clone(), location.clone());
let table = builder.build();
assert_eq!(table.get_location(&qname), Some(location));
}
#[test]
fn test_symbol_table_new() {
let table = SymbolTable::new();
assert!(table.is_empty());
assert_eq!(table.len(), 0);
}
#[test]
fn test_symbol_table_default() {
let table = SymbolTable::default();
assert!(table.is_empty());
}
#[test]
fn test_symbol_table_debug() {
let table = SymbolTable::new();
let debug = format!("{:?}", table);
assert!(debug.contains("SymbolTable"));
}
#[test]
fn test_symbol_table_insert_multiple() {
let table = SymbolTable::new();
for i in 0..10 {
let qname = QualifiedName::new(vec!["module".to_string()], format!("func{}", i));
let location = Location::new(PathBuf::from("src/lib.rs"), i * 10, (i + 1) * 10);
table.insert(qname, location);
}
assert_eq!(table.len(), 10);
}
#[test]
fn test_symbol_table_clear() {
let table = SymbolTable::new();
let qname = QualifiedName::new(vec!["test".to_string()], "func".to_string());
let location = Location::new(PathBuf::from("test.rs"), 0, 100);
table.insert(qname, location);
assert!(!table.is_empty());
table.clear();
assert!(table.is_empty());
}
#[test]
fn test_symbol_table_all_symbols() {
let table = SymbolTable::new();
let qname1 = QualifiedName::new(vec!["a".to_string()], "f1".to_string());
let qname2 = QualifiedName::new(vec!["b".to_string()], "f2".to_string());
let location1 = Location::new(PathBuf::from("a.rs"), 0, 10);
let location2 = Location::new(PathBuf::from("b.rs"), 0, 20);
table.insert(qname1.clone(), location1);
table.insert(qname2.clone(), location2);
let all = table.all_symbols();
assert_eq!(all.len(), 2);
}
#[test]
fn test_symbol_at_location_exact_match() {
let table = SymbolTable::new();
let file_path = PathBuf::from("src/lib.rs");
let qname = QualifiedName::new(vec!["module".to_string()], "my_func".to_string());
let location = Location::new(file_path.clone(), 100, 200);
table.insert(qname.clone(), location.clone());
let found = table.symbol_at_location(&location);
assert_eq!(found, Some(qname));
}
#[test]
fn test_symbol_at_location_closest_match() {
let table = SymbolTable::new();
let file_path = PathBuf::from("src/lib.rs");
let qname = QualifiedName::new(vec!["module".to_string()], "func".to_string());
let location = Location::new(file_path.clone(), 100, 200);
table.insert(qname.clone(), location);
let search_location = Location::new(file_path, 150, 160);
let found = table.symbol_at_location(&search_location);
assert_eq!(found, Some(qname));
}
#[test]
fn test_symbol_at_location_not_found() {
let table = SymbolTable::new();
let file_path = PathBuf::from("nonexistent.rs");
let location = Location::new(file_path, 0, 10);
let found = table.symbol_at_location(&location);
assert!(found.is_none());
}
#[test]
fn test_symbols_in_span_empty() {
let table = SymbolTable::new();
let file_path = PathBuf::from("test.rs");
let location = Location::new(file_path, 0, 1000);
let symbols = table.symbols_in_span(&location);
assert!(symbols.is_empty());
}
#[test]
fn test_symbols_in_span_with_symbols() {
let table = SymbolTable::new();
let file_path = PathBuf::from("src/lib.rs");
for i in 0..5 {
let qname = QualifiedName::new(vec!["mod".to_string()], format!("func{}", i));
let location = Location::new(file_path.clone(), i * 100, (i + 1) * 100 - 1);
table.insert(qname, location);
}
let search_location = Location::new(file_path, 0, 250);
let symbols = table.symbols_in_span(&search_location);
assert!(symbols.len() >= 2);
}
#[test]
fn test_symbols_in_span_boundary() {
let table = SymbolTable::new();
let file_path = PathBuf::from("test.rs");
let qname = QualifiedName::new(vec!["mod".to_string()], "func".to_string());
let location = Location::new(file_path.clone(), 100, 200);
table.insert(qname.clone(), location);
let search = Location::new(file_path, 100, 101);
let found = table.symbols_in_span(&search);
assert!(!found.is_empty());
}
#[test]
fn test_resolve_relative_function_with_module() {
let table = SymbolTable::new();
let file_path = PathBuf::from("src/utils/helpers.rs");
let qname = QualifiedName::new(
vec!["utils".to_string(), "helpers".to_string()],
"my_function".to_string(),
);
let location = Location::new(file_path.clone(), 50, 100);
table.insert(qname, location.clone());
let rel = RelativeLocation::Function {
name: "my_function".to_string(),
module: Some("utils::helpers".to_string()),
};
let resolved = table.resolve_relative(&rel, &file_path);
assert!(resolved.is_some());
}
#[test]
fn test_resolve_relative_function_without_module() {
let table = SymbolTable::new();
let file_path = PathBuf::from("src/lib.rs");
let rel = RelativeLocation::Function {
name: "test_func".to_string(),
module: None,
};
let resolved = table.resolve_relative(&rel, &file_path);
assert!(resolved.is_none() || resolved.is_some());
}
#[test]
fn test_resolve_relative_symbol() {
let table = SymbolTable::new();
let file_path = PathBuf::from("test.rs");
let qname = QualifiedName::new(vec!["pkg".to_string()], "Item".to_string());
let location = Location::new(PathBuf::from("pkg.rs"), 0, 50);
table.insert(qname, location.clone());
let rel = RelativeLocation::Symbol {
qualified_name: "pkg::Item".to_string(),
};
let resolved = table.resolve_relative(&rel, &file_path);
assert!(resolved.is_some());
assert_eq!(resolved.unwrap(), location);
}
#[test]
fn test_resolve_relative_symbol_not_found() {
let table = SymbolTable::new();
let file_path = PathBuf::from("test.rs");
let rel = RelativeLocation::Symbol {
qualified_name: "nonexistent::Symbol".to_string(),
};
let resolved = table.resolve_relative(&rel, &file_path);
assert!(resolved.is_none());
}
#[test]
fn test_resolve_relative_symbol_invalid_format() {
let table = SymbolTable::new();
let file_path = PathBuf::from("test.rs");
let rel = RelativeLocation::Symbol {
qualified_name: "".to_string(),
};
let resolved = table.resolve_relative(&rel, &file_path);
assert!(resolved.is_none());
}
#[test]
fn test_symbol_table_builder_new() {
let builder = SymbolTableBuilder::new();
let table = builder.build();
assert!(table.is_empty());
}
#[test]
fn test_symbol_table_builder_default() {
let builder = SymbolTableBuilder::default();
let table = builder.build();
assert!(table.is_empty());
}
#[test]
fn test_symbol_table_builder_add_multiple() {
let builder = SymbolTableBuilder::new();
for i in 0..5 {
let qname = QualifiedName::new(vec!["mod".to_string()], format!("fn{}", i));
let location = Location::new(PathBuf::from("test.rs"), i * 10, (i + 1) * 10);
builder.add_symbol(qname, location);
}
let table = builder.build();
assert_eq!(table.len(), 5);
}
#[test]
fn test_infer_module_from_file_path_simple() {
let table = SymbolTable::new();
let path = Path::new("src/utils.rs");
let module_path = table.infer_module_from_file_path(path);
assert!(module_path.contains(&"utils".to_string()));
}
#[test]
fn test_infer_module_from_file_path_mod_rs() {
let table = SymbolTable::new();
let path = Path::new("src/utils/mod.rs");
let module_path = table.infer_module_from_file_path(path);
assert!(!module_path.iter().any(|s| s == "mod"));
}
#[test]
fn test_infer_module_from_file_path_lib_rs() {
let table = SymbolTable::new();
let path = Path::new("src/lib.rs");
let module_path = table.infer_module_from_file_path(path);
assert!(!module_path.iter().any(|s| s == "lib"));
}
#[test]
fn test_infer_module_from_file_path_main_rs() {
let table = SymbolTable::new();
let path = Path::new("src/main.rs");
let module_path = table.infer_module_from_file_path(path);
assert!(!module_path.iter().any(|s| s == "main"));
}
#[test]
fn test_infer_module_from_file_path_nested() {
let table = SymbolTable::new();
let path = Path::new("src/services/cache/redis.rs");
let module_path = table.infer_module_from_file_path(path);
assert!(module_path.contains(&"redis".to_string()));
}
#[test]
fn test_parse_explicit_module() {
let table = SymbolTable::new();
let module_path = table.parse_explicit_module("std::collections::hash_map");
assert_eq!(module_path, vec!["std", "collections", "hash_map"]);
}
#[test]
fn test_parse_explicit_module_single() {
let table = SymbolTable::new();
let module_path = table.parse_explicit_module("single");
assert_eq!(module_path, vec!["single"]);
}
#[test]
fn test_extract_significant_file_stem() {
let table = SymbolTable::new();
let path = Path::new("src/utils.rs");
let stem = table.extract_significant_file_stem(path);
assert_eq!(stem, Some("utils".to_string()));
}
#[test]
fn test_extract_significant_file_stem_mod() {
let table = SymbolTable::new();
let path = Path::new("src/mod.rs");
let stem = table.extract_significant_file_stem(path);
assert!(stem.is_none());
}
#[test]
fn test_extract_directory_name() {
let table = SymbolTable::new();
let path = Path::new("src/services");
let name = table.extract_directory_name(path);
assert_eq!(name, Some("services".to_string()));
}
#[test]
fn test_get_location_not_found() {
let table = SymbolTable::new();
let qname = QualifiedName::new(vec!["nonexistent".to_string()], "func".to_string());
let location = table.get_location(&qname);
assert!(location.is_none());
}
#[test]
fn test_insert_overwrites_existing() {
let table = SymbolTable::new();
let qname = QualifiedName::new(vec!["mod".to_string()], "func".to_string());
let location1 = Location::new(PathBuf::from("a.rs"), 0, 10);
let location2 = Location::new(PathBuf::from("b.rs"), 20, 30);
table.insert(qname.clone(), location1);
table.insert(qname.clone(), location2.clone());
let found = table.get_location(&qname);
assert_eq!(found, Some(location2));
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}