use cqs::parser::{ChunkType, Language, Parser};
fn fixtures_path() -> std::path::PathBuf {
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures")
}
#[test]
fn test_rust_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.rs");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 5,
"Expected at least 5 chunks, got {}",
chunks.len()
);
let add_fn = chunks
.iter()
.find(|c| c.name == "add" && c.chunk_type == ChunkType::Function);
assert!(add_fn.is_some(), "Should find 'add' function");
let add_fn = add_fn.unwrap();
assert_eq!(add_fn.language, Language::Rust);
assert!(add_fn.content.contains("a + b"));
}
#[test]
fn test_rust_method_detection() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.rs");
let chunks = parser.parse_file(&path).unwrap();
let methods: Vec<_> = chunks
.iter()
.filter(|c| c.chunk_type == ChunkType::Method)
.collect();
assert!(!methods.is_empty(), "Should find methods in impl block");
let new_ctor = chunks
.iter()
.find(|c| c.name == "new" && c.chunk_type == ChunkType::Constructor);
assert!(
new_ctor.is_some(),
"Calculator::new should be a constructor"
);
}
#[test]
fn test_python_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.py");
let chunks = parser.parse_file(&path).unwrap();
assert!(!chunks.is_empty(), "Should find chunks in Python file");
let greet_fn = chunks.iter().find(|c| c.name == "greet");
assert!(greet_fn.is_some(), "Should find 'greet' function");
let greet_fn = greet_fn.unwrap();
assert_eq!(greet_fn.language, Language::Python);
}
#[test]
fn test_python_method_detection() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.py");
let chunks = parser.parse_file(&path).unwrap();
let methods: Vec<_> = chunks
.iter()
.filter(|c| c.chunk_type == ChunkType::Method)
.collect();
assert!(!methods.is_empty(), "Should find methods in Python class");
let increment = chunks.iter().find(|c| c.name == "increment");
assert!(increment.is_some(), "Should find 'increment' method");
assert_eq!(increment.unwrap().chunk_type, ChunkType::Method);
}
#[test]
fn test_typescript_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.ts");
let chunks = parser.parse_file(&path).unwrap();
assert!(!chunks.is_empty(), "Should find chunks in TypeScript file");
let format_fn = chunks.iter().find(|c| c.name == "formatName");
assert!(format_fn.is_some(), "Should find 'formatName' function");
let format_fn = format_fn.unwrap();
assert_eq!(format_fn.language, Language::TypeScript);
}
#[test]
fn test_typescript_arrow_function() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.ts");
let chunks = parser.parse_file(&path).unwrap();
let double_fn = chunks.iter().find(|c| c.name == "double");
assert!(double_fn.is_some(), "Should find 'double' arrow function");
}
#[test]
fn test_javascript_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.js");
let chunks = parser.parse_file(&path).unwrap();
assert!(!chunks.is_empty(), "Should find chunks in JavaScript file");
let validate_fn = chunks.iter().find(|c| c.name == "validateEmail");
assert!(
validate_fn.is_some(),
"Should find 'validateEmail' function"
);
let validate_fn = validate_fn.unwrap();
assert_eq!(validate_fn.language, Language::JavaScript);
}
#[test]
fn test_go_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.go");
let chunks = parser.parse_file(&path).unwrap();
assert!(!chunks.is_empty(), "Should find chunks in Go file");
let greet_fn = chunks.iter().find(|c| c.name == "Greet");
assert!(greet_fn.is_some(), "Should find 'Greet' function");
let greet_fn = greet_fn.unwrap();
assert_eq!(greet_fn.language, Language::Go);
assert_eq!(greet_fn.chunk_type, ChunkType::Function);
}
#[test]
fn test_go_method_detection() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.go");
let chunks = parser.parse_file(&path).unwrap();
let push = chunks.iter().find(|c| c.name == "Push");
assert!(push.is_some(), "Should find 'Push' method");
assert_eq!(push.unwrap().chunk_type, ChunkType::Method);
}
#[test]
fn test_signature_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.rs");
let chunks = parser.parse_file(&path).unwrap();
let add_fn = chunks
.iter()
.find(|c| c.name == "add" && c.chunk_type == ChunkType::Function)
.unwrap();
assert!(
add_fn.signature.contains("pub fn add"),
"Signature should contain function declaration"
);
assert!(
!add_fn.signature.contains('{'),
"Signature should not contain body"
);
}
#[test]
fn test_doc_comment_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.rs");
let chunks = parser.parse_file(&path).unwrap();
let add_fn = chunks
.iter()
.find(|c| c.name == "add" && c.chunk_type == ChunkType::Function)
.unwrap();
assert!(add_fn.doc.is_some(), "Should extract doc comment");
let doc = add_fn.doc.as_ref().unwrap();
assert!(
doc.contains("Adds two numbers"),
"Doc should contain description"
);
}
#[test]
fn test_language_from_extension() {
assert_eq!(Language::from_extension("rs"), Some(Language::Rust));
assert_eq!(Language::from_extension("py"), Some(Language::Python));
assert_eq!(Language::from_extension("pyi"), Some(Language::Python));
assert_eq!(Language::from_extension("ts"), Some(Language::TypeScript));
assert_eq!(Language::from_extension("tsx"), Some(Language::TypeScript));
assert_eq!(Language::from_extension("js"), Some(Language::JavaScript));
assert_eq!(Language::from_extension("jsx"), Some(Language::JavaScript));
assert_eq!(Language::from_extension("mjs"), Some(Language::JavaScript));
assert_eq!(Language::from_extension("go"), Some(Language::Go));
assert_eq!(Language::from_extension("txt"), None);
}
#[test]
fn test_supported_extensions() {
let parser = Parser::new().unwrap();
let exts = parser.supported_extensions();
assert!(exts.contains(&"rs"));
assert!(exts.contains(&"py"));
assert!(exts.contains(&"ts"));
assert!(exts.contains(&"js"));
assert!(exts.contains(&"go"));
}
#[test]
fn test_parse_c_fixture() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.c");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should find at least some chunks in C file"
);
for chunk in &chunks {
assert_eq!(
chunk.language,
Language::C,
"All chunks should be Language::C"
);
}
let function_count = chunks
.iter()
.filter(|c| c.chunk_type == ChunkType::Function)
.count();
assert!(
function_count > 0,
"Should find at least one function in C file"
);
}
#[test]
fn test_parse_java_fixture() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("Sample.java");
let chunks = parser.parse_file(&path).unwrap();
let names: Vec<&str> = chunks.iter().map(|c| c.name.as_str()).collect();
assert!(
names.contains(&"TaskManager"),
"Should find TaskManager class"
);
assert!(names.contains(&"addTask"), "Should find addTask method");
assert!(
names.contains(&"findByName"),
"Should find findByName method"
);
assert!(
names.contains(&"getHighPriority"),
"Should find getHighPriority method"
);
assert!(names.contains(&"size"), "Should find size method");
assert!(names.contains(&"Task"), "Should find Task class");
for chunk in &chunks {
assert_eq!(
chunk.language,
Language::Java,
"All chunks should be Language::Java"
);
}
let add_task = chunks.iter().find(|c| c.name == "addTask");
assert!(add_task.is_some(), "Should find addTask chunk");
let add_task = add_task.unwrap();
assert_eq!(
add_task.chunk_type,
ChunkType::Method,
"addTask should be a method"
);
assert!(
add_task.content.contains("tasks.add"),
"addTask should contain tasks.add call"
);
let task_manager = chunks.iter().find(|c| c.name == "TaskManager");
assert!(task_manager.is_some(), "Should find TaskManager chunk");
let task_manager = task_manager.unwrap();
if let Some(doc) = &task_manager.doc {
assert!(doc.contains("task manager"), "Should extract doc comment");
}
}
#[test]
fn test_parse_sql_fixture() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sql");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 4,
"Expected at least 4 chunks, got {}",
chunks.len()
);
let proc = chunks.iter().find(|c| c.name.contains("usp_GetOrders"));
assert!(proc.is_some(), "Should find usp_GetOrders procedure");
let proc = proc.unwrap();
assert_eq!(proc.chunk_type, ChunkType::StoredProc);
assert_eq!(proc.language, Language::Sql);
let func = chunks.iter().find(|c| c.name.contains("fn_CalcTotal"));
assert!(func.is_some(), "Should find fn_CalcTotal function");
assert_eq!(func.unwrap().chunk_type, ChunkType::Function);
let view = chunks
.iter()
.find(|c| c.name.contains("vw_ActiveCustomers"));
assert!(view.is_some(), "Should find vw_ActiveCustomers view");
assert_eq!(view.unwrap().chunk_type, ChunkType::StoredProc);
}
#[test]
fn test_sql_signature_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sql");
let chunks = parser.parse_file(&path).unwrap();
let func = chunks
.iter()
.find(|c| c.name.contains("fn_CalcTotal"))
.expect("Should find fn_CalcTotal");
assert!(
func.signature.contains("fn_CalcTotal"),
"Signature should contain function name: {}",
func.signature
);
assert!(
!func.signature.contains("BEGIN"),
"Signature should stop before BEGIN: {}",
func.signature
);
}
#[test]
fn test_sql_schema_qualified_names() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sql");
let chunks = parser.parse_file(&path).unwrap();
let proc = chunks
.iter()
.find(|c| c.name.contains("usp_GetOrders"))
.expect("Should find usp_GetOrders");
assert!(
proc.name.contains("dbo"),
"Should preserve schema prefix: {}",
proc.name
);
}
#[test]
fn test_sql_go_separator() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sql");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 4,
"GO separators should not break parsing, got {} chunks",
chunks.len()
);
}
#[test]
fn test_sql_call_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sql");
let chunks = parser.parse_file(&path).unwrap();
let process = chunks
.iter()
.find(|c| c.name.contains("usp_ProcessOrder"))
.expect("Should find usp_ProcessOrder");
assert!(
process.content.contains("EXEC"),
"usp_ProcessOrder body should contain EXEC call"
);
let calls = parser.extract_calls(&process.content, Language::Sql, 0, process.content.len(), 0);
assert!(
!calls.is_empty(),
"Should extract calls from usp_ProcessOrder"
);
}
#[test]
fn test_parse_markdown_fixture() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.md");
let chunks = parser.parse_file(&path).unwrap();
assert!(!chunks.is_empty(), "Should find chunks in markdown file");
let md_chunks: Vec<_> = chunks
.iter()
.filter(|c| c.language == Language::Markdown)
.collect();
for chunk in &md_chunks {
assert_eq!(chunk.chunk_type, ChunkType::Section);
}
let names: Vec<&str> = md_chunks.iter().map(|c| c.name.as_str()).collect();
assert!(
names.contains(&"Getting Started"),
"Should find 'Getting Started' section, got: {:?}",
names
);
assert!(
names.contains(&"Advanced Topics"),
"Should find 'Advanced Topics' section, got: {:?}",
names
);
let py_chunks: Vec<_> = chunks
.iter()
.filter(|c| c.language == Language::Python)
.collect();
assert!(
py_chunks.iter().any(|c| c.name == "example"),
"Should extract Python function 'example' from fenced block, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.language))
.collect::<Vec<_>>()
);
}
#[test]
fn test_markdown_breadcrumb_signatures() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.md");
let chunks = parser.parse_file(&path).unwrap();
let getting_started = chunks.iter().find(|c| c.name == "Getting Started");
assert!(getting_started.is_some(), "Should find 'Getting Started'");
let gs = getting_started.unwrap();
assert!(
gs.signature.contains("Sample Documentation"),
"Breadcrumb should contain title, got: {}",
gs.signature
);
}
#[test]
fn test_markdown_code_block_headings_ignored() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.md");
let chunks = parser.parse_file(&path).unwrap();
let names: Vec<&str> = chunks.iter().map(|c| c.name.as_str()).collect();
assert!(
!names.contains(&"This heading inside a code block should NOT be parsed"),
"Should not parse heading inside code block, got: {:?}",
names
);
assert!(
!names.contains(&"Also not a heading"),
"Should not parse heading inside code block, got: {:?}",
names
);
}
#[test]
fn test_markdown_cross_references() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.md");
let refs = parser.parse_file_calls(&path).unwrap();
let all_callees: Vec<&str> = refs
.iter()
.flat_map(|fc| fc.calls.iter().map(|c| c.callee_name.as_str()))
.collect();
assert!(
all_callees.contains(&"Configuration Guide"),
"Should extract link text, got: {:?}",
all_callees
);
assert!(
all_callees.contains(&"API Reference"),
"Should extract link text, got: {:?}",
all_callees
);
assert!(
all_callees.contains(&"TagRead"),
"Should extract backtick function ref, got: {:?}",
all_callees
);
assert!(
all_callees.contains(&"Module.func"),
"Should extract backtick module.func ref, got: {:?}",
all_callees
);
assert!(
all_callees.contains(&"Class::method"),
"Should extract backtick Class::method ref, got: {:?}",
all_callees
);
}
#[test]
fn test_markdown_image_links_skipped() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.md");
let refs = parser.parse_file_calls(&path).unwrap();
let all_callees: Vec<&str> = refs
.iter()
.flat_map(|fc| fc.calls.iter().map(|c| c.callee_name.as_str()))
.collect();
assert!(
!all_callees.contains(&"architecture diagram"),
"Should NOT extract image link text, got: {:?}",
all_callees
);
}
#[test]
fn test_markdown_code_blocks_in_content() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.md");
let chunks = parser.parse_file(&path).unwrap();
let has_code_block = chunks.iter().any(|c| c.content.contains("def example():"));
assert!(
has_code_block,
"Code block content should be preserved in parent chunk"
);
}
#[test]
fn test_markdown_supported_extensions() {
let parser = Parser::new().unwrap();
let exts = parser.supported_extensions();
assert!(exts.contains(&"md"), "Should support .md extension");
assert!(exts.contains(&"mdx"), "Should support .mdx extension");
}
#[test]
fn test_markdown_language_from_extension() {
assert_eq!(Language::from_extension("md"), Some(Language::Markdown));
assert_eq!(Language::from_extension("mdx"), Some(Language::Markdown));
}
#[test]
fn test_bash_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sh");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 4,
"Expected at least 4 Bash functions, got {}",
chunks.len()
);
let deploy = chunks.iter().find(|c| c.name == "deploy");
assert!(deploy.is_some(), "Should find 'deploy' function");
let deploy = deploy.unwrap();
assert_eq!(deploy.language, Language::Bash);
assert_eq!(deploy.chunk_type, ChunkType::Function);
assert!(deploy.content.contains("build_artifacts"));
}
#[test]
fn test_bash_call_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sh");
let refs = parser.parse_file_calls(&path).unwrap();
let all_callees: Vec<&str> = refs
.iter()
.flat_map(|fc| fc.calls.iter().map(|c| c.callee_name.as_str()))
.collect();
assert!(
all_callees.contains(&"build_artifacts"),
"deploy should call build_artifacts, got: {:?}",
all_callees
);
}
#[test]
fn test_hcl_block_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.tf");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 4,
"Expected at least 4 HCL blocks, got {}",
chunks.len()
);
let region = chunks.iter().find(|c| c.name == "region");
assert!(region.is_some(), "Should find 'region' variable");
let region = region.unwrap();
assert_eq!(region.language, Language::Hcl);
let web_instance = chunks
.iter()
.find(|c| c.name.contains("aws_instance") && c.name.contains("web"));
assert!(
web_instance.is_some(),
"Should find aws_instance.web resource"
);
}
#[test]
fn test_kotlin_class_and_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.kt");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 4,
"Expected at least 4 Kotlin chunks, got {}",
chunks.len()
);
let stack = chunks
.iter()
.find(|c| c.name == "Stack" && c.chunk_type == ChunkType::Class);
assert!(stack.is_some(), "Should find 'Stack' class");
assert_eq!(stack.unwrap().language, Language::Kotlin);
let config = chunks
.iter()
.find(|c| c.name == "Config" && c.chunk_type == ChunkType::Interface);
assert!(config.is_some(), "Should find 'Config' interface");
let log_level = chunks
.iter()
.find(|c| c.name == "LogLevel" && c.chunk_type == ChunkType::Enum);
assert!(log_level.is_some(), "Should find 'LogLevel' enum");
let format_fn = chunks.iter().find(|c| c.name == "formatDuration");
assert!(format_fn.is_some(), "Should find 'formatDuration' function");
}
#[test]
fn test_swift_struct_class_protocol_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.swift");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 4,
"Expected at least 4 Swift chunks, got {}",
chunks.len()
);
let point = chunks
.iter()
.find(|c| c.name == "Point" && c.chunk_type == ChunkType::Struct);
assert!(point.is_some(), "Should find 'Point' struct");
assert_eq!(point.unwrap().language, Language::Swift);
let shape = chunks
.iter()
.find(|c| c.name == "Shape" && c.chunk_type == ChunkType::Trait);
assert!(shape.is_some(), "Should find 'Shape' protocol (as Trait)");
let circle = chunks
.iter()
.find(|c| c.name == "Circle" && c.chunk_type == ChunkType::Class);
assert!(circle.is_some(), "Should find 'Circle' class");
let direction = chunks
.iter()
.find(|c| c.name == "Direction" && c.chunk_type == ChunkType::Enum);
assert!(direction.is_some(), "Should find 'Direction' enum");
let greet = chunks.iter().find(|c| c.name == "greet");
assert!(greet.is_some(), "Should find 'greet' function");
}
#[test]
fn test_objc_class_and_protocol_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.m");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 3,
"Expected at least 3 Objective-C chunks, got {}",
chunks.len()
);
let drawable = chunks
.iter()
.find(|c| c.name == "Drawable" && c.chunk_type == ChunkType::Interface);
assert!(drawable.is_some(), "Should find 'Drawable' protocol");
assert_eq!(drawable.unwrap().language, Language::ObjC);
let rect = chunks
.iter()
.find(|c| c.name == "Rectangle" && c.chunk_type == ChunkType::Class);
assert!(rect.is_some(), "Should find 'Rectangle' class");
let calc = chunks.iter().find(|c| c.name == "calculateDistance");
assert!(calc.is_some(), "Should find 'calculateDistance' function");
}
#[test]
fn test_protobuf_message_and_service_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.proto");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 4,
"Expected at least 4 Protobuf chunks, got {}",
chunks.len()
);
let user = chunks
.iter()
.find(|c| c.name == "User" && c.chunk_type == ChunkType::Struct);
assert!(user.is_some(), "Should find 'User' message (as Struct)");
assert_eq!(user.unwrap().language, Language::Protobuf);
let svc = chunks
.iter()
.find(|c| c.name == "UserService" && c.chunk_type == ChunkType::Service);
assert!(
svc.is_some(),
"Should find 'UserService' service (as Service)"
);
let status = chunks
.iter()
.find(|c| c.name == "Status" && c.chunk_type == ChunkType::Enum);
assert!(status.is_some(), "Should find 'Status' enum");
let rpc = chunks
.iter()
.find(|c| c.name == "GetUser" && c.chunk_type == ChunkType::Method);
assert!(
rpc.is_some(),
"Should find 'GetUser' RPC (as Method). Types: {:?}",
chunks
.iter()
.map(|c| format!("{}:{}", c.name, c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
fn test_graphql_type_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.graphql");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 6,
"Expected at least 6 GraphQL chunks, got {}",
chunks.len()
);
let user = chunks
.iter()
.find(|c| c.name == "User" && c.chunk_type == ChunkType::Struct);
assert!(user.is_some(), "Should find 'User' type (as Struct)");
assert_eq!(user.unwrap().language, Language::GraphQL);
let node = chunks
.iter()
.find(|c| c.name == "Node" && c.chunk_type == ChunkType::Interface);
assert!(node.is_some(), "Should find 'Node' interface");
let status = chunks
.iter()
.find(|c| c.name == "Status" && c.chunk_type == ChunkType::Enum);
assert!(status.is_some(), "Should find 'Status' enum");
let search = chunks
.iter()
.find(|c| c.name == "SearchResult" && c.chunk_type == ChunkType::TypeAlias);
assert!(
search.is_some(),
"Should find 'SearchResult' union (as TypeAlias)"
);
let query = chunks
.iter()
.find(|c| c.name == "GetUser" && c.chunk_type == ChunkType::Function);
assert!(
query.is_some(),
"Should find 'GetUser' operation (as Function)"
);
let frag = chunks
.iter()
.find(|c| c.name == "UserFields" && c.chunk_type == ChunkType::Function);
assert!(
frag.is_some(),
"Should find 'UserFields' fragment (as Function)"
);
}
#[test]
fn test_php_class_and_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.php");
let chunks = parser.parse_file(&path).unwrap();
assert!(
chunks.len() >= 5,
"Expected at least 5 PHP chunks, got {}",
chunks.len()
);
let user = chunks
.iter()
.find(|c| c.name == "User" && c.chunk_type == ChunkType::Class);
assert!(user.is_some(), "Should find 'User' class");
assert_eq!(user.unwrap().language, Language::Php);
let printable = chunks
.iter()
.find(|c| c.name == "Printable" && c.chunk_type == ChunkType::Interface);
assert!(printable.is_some(), "Should find 'Printable' interface");
let ts = chunks
.iter()
.find(|c| c.name == "Timestampable" && c.chunk_type == ChunkType::Trait);
assert!(ts.is_some(), "Should find 'Timestampable' trait");
let status = chunks
.iter()
.find(|c| c.name == "Status" && c.chunk_type == ChunkType::Enum);
assert!(status.is_some(), "Should find 'Status' enum");
let fmt = chunks.iter().find(|c| c.name == "formatDuration");
assert!(fmt.is_some(), "Should find 'formatDuration' function");
}
#[test]
#[cfg(feature = "lang-lua")]
fn test_lua_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.lua");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Lua chunks from sample.lua"
);
let greet = chunks.iter().find(|c| c.name == "greet");
assert!(greet.is_some(), "Should find 'greet' function");
assert_eq!(greet.unwrap().chunk_type, ChunkType::Function);
let fibonacci = chunks.iter().find(|c| c.name == "fibonacci");
assert!(fibonacci.is_some(), "Should find 'fibonacci' function");
}
#[test]
#[cfg(feature = "lang-zig")]
fn test_zig_function_and_struct_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.zig");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Zig chunks from sample.zig"
);
let add = chunks.iter().find(|c| c.name == "add");
assert!(add.is_some(), "Should find 'add' function");
assert_eq!(add.unwrap().chunk_type, ChunkType::Function);
let point = chunks
.iter()
.find(|c| c.name == "Point" && c.chunk_type == ChunkType::Struct);
assert!(point.is_some(), "Should find 'Point' struct");
let color = chunks
.iter()
.find(|c| c.name == "Color" && c.chunk_type == ChunkType::Enum);
assert!(color.is_some(), "Should find 'Color' enum");
}
#[test]
#[cfg(feature = "lang-r")]
fn test_r_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.r");
let chunks = parser.parse_file(&path).unwrap();
assert!(!chunks.is_empty(), "Should extract R chunks from sample.r");
let calc = chunks.iter().find(|c| c.name == "calculate_mean");
assert!(calc.is_some(), "Should find 'calculate_mean' function");
assert_eq!(calc.unwrap().chunk_type, ChunkType::Function);
let filter = chunks.iter().find(|c| c.name == "filter_above");
assert!(filter.is_some(), "Should find 'filter_above' function");
}
#[test]
#[cfg(feature = "lang-yaml")]
fn test_yaml_key_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.yaml");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract YAML chunks from sample.yaml"
);
let names: Vec<_> = chunks.iter().map(|c| c.name.as_str()).collect();
assert!(
names.contains(&"name"),
"Should find 'name' key, got: {:?}",
names
);
}
#[test]
#[cfg(feature = "lang-toml")]
fn test_toml_table_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.toml");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract TOML chunks from sample.toml"
);
let names: Vec<_> = chunks.iter().map(|c| c.name.as_str()).collect();
assert!(
names.contains(&"package"),
"Should find 'package' table, got: {:?}",
names
);
}
#[test]
#[cfg(feature = "lang-elixir")]
fn test_elixir_function_and_module_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.ex");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Elixir chunks from sample.ex"
);
let add = chunks.iter().find(|c| c.name == "add");
assert!(add.is_some(), "Should find 'add' function");
assert_eq!(add.unwrap().chunk_type, ChunkType::Function);
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Module);
assert!(calc.is_some(), "Should find 'Calculator' module");
}
#[test]
#[cfg(feature = "lang-erlang")]
fn test_erlang_function_and_module_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.erl");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Erlang chunks from sample.erl"
);
let add = chunks.iter().find(|c| c.name == "add");
assert!(add.is_some(), "Should find 'add' function");
assert_eq!(add.unwrap().chunk_type, ChunkType::Function);
let module = chunks
.iter()
.find(|c| c.name == "calculator" && c.chunk_type == ChunkType::Module);
assert!(module.is_some(), "Should find 'calculator' module");
}
#[test]
#[cfg(feature = "lang-ocaml")]
fn test_ocaml_function_and_type_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.ml");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract OCaml chunks from sample.ml"
);
let add = chunks.iter().find(|c| c.name == "add");
assert!(add.is_some(), "Should find 'add' function");
assert_eq!(add.unwrap().chunk_type, ChunkType::Function);
let color = chunks
.iter()
.find(|c| c.name == "color" && c.chunk_type == ChunkType::Enum);
assert!(color.is_some(), "Should find 'color' variant type as Enum");
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Module);
assert!(calc.is_some(), "Should find 'Calculator' module");
}
#[test]
#[cfg(feature = "lang-julia")]
fn test_julia_function_and_struct_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.jl");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Julia chunks from sample.jl"
);
let greet = chunks.iter().find(|c| c.name == "greet");
assert!(greet.is_some(), "Should find 'greet' function");
assert_eq!(greet.unwrap().chunk_type, ChunkType::Function);
let point = chunks
.iter()
.find(|c| c.name == "Point" && c.chunk_type == ChunkType::Struct);
assert!(point.is_some(), "Should find 'Point' struct");
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Module);
assert!(calc.is_some(), "Should find 'Calculator' module");
}
#[test]
#[cfg(feature = "lang-gleam")]
fn test_gleam_function_and_type_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.gleam");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Gleam chunks from sample.gleam"
);
let add = chunks.iter().find(|c| c.name == "add");
assert!(add.is_some(), "Should find 'add' function");
assert_eq!(add.unwrap().chunk_type, ChunkType::Function);
let color = chunks
.iter()
.find(|c| c.name == "Color" && c.chunk_type == ChunkType::Enum);
assert!(color.is_some(), "Should find 'Color' type as Enum");
let user_id = chunks
.iter()
.find(|c| c.name == "UserId" && c.chunk_type == ChunkType::TypeAlias);
assert!(user_id.is_some(), "Should find 'UserId' type alias");
let max = chunks
.iter()
.find(|c| c.name == "max_retries" && c.chunk_type == ChunkType::Constant);
assert!(max.is_some(), "Should find 'max_retries' constant");
}
#[test]
#[cfg(feature = "lang-css")]
fn test_css_rule_set_and_keyframes_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.css");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract CSS chunks from sample.css"
);
let container = chunks
.iter()
.find(|c| c.name.contains("container") && c.chunk_type == ChunkType::Property);
assert!(
container.is_some(),
"Should find '.container' rule set as Property"
);
let fade = chunks
.iter()
.find(|c| c.name == "fadeIn" && c.chunk_type == ChunkType::Section);
assert!(fade.is_some(), "Should find 'fadeIn' keyframes as Section");
}
#[test]
#[cfg(feature = "lang-perl")]
fn test_perl_subroutine_and_package_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.pl");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Perl chunks from sample.pl"
);
let greet = chunks.iter().find(|c| c.name == "greet");
assert!(greet.is_some(), "Should find 'greet' subroutine");
assert_eq!(greet.unwrap().chunk_type, ChunkType::Function);
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Module);
assert!(calc.is_some(), "Should find 'Calculator' package as Module");
}
#[test]
#[cfg(feature = "lang-haskell")]
fn test_haskell_function_and_data_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.hs");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Haskell chunks from sample.hs"
);
let add = chunks.iter().find(|c| c.name == "add");
assert!(add.is_some(), "Should find 'add' function");
assert_eq!(add.unwrap().chunk_type, ChunkType::Function);
let color = chunks
.iter()
.find(|c| c.name == "Color" && c.chunk_type == ChunkType::Enum);
assert!(color.is_some(), "Should find 'Color' data type");
let printable = chunks
.iter()
.find(|c| c.name == "Printable" && c.chunk_type == ChunkType::Trait);
assert!(printable.is_some(), "Should find 'Printable' typeclass");
}
#[test]
#[cfg(feature = "lang-html")]
fn test_html_heading_and_landmark_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.html");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract HTML chunks from sample.html"
);
let h1 = chunks
.iter()
.find(|c| c.name == "Welcome to the Sample" && c.chunk_type == ChunkType::Section);
assert!(h1.is_some(), "Should find h1 heading as Section");
let script = chunks
.iter()
.find(|c| c.name.contains("main.js") && c.chunk_type == ChunkType::Module);
assert!(
script.is_some(),
"Should find script as Module, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let js_funcs: Vec<_> = chunks
.iter()
.filter(|c| c.language == Language::JavaScript)
.collect();
assert!(
js_funcs.iter().any(|c| c.name == "handleClick"),
"Should find injected JS function 'handleClick', got: {:?}",
js_funcs.iter().map(|c| &c.name).collect::<Vec<_>>()
);
assert!(
js_funcs.iter().any(|c| c.name == "setupListeners"),
"Should find injected JS function 'setupListeners', got: {:?}",
js_funcs.iter().map(|c| &c.name).collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-json")]
fn test_json_top_level_key_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.json");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract JSON chunks from sample.json"
);
let names: Vec<_> = chunks.iter().map(|c| c.name.as_str()).collect();
assert!(
names.contains(&"name"),
"Should find 'name' key, got: {:?}",
names
);
assert!(
names.contains(&"version"),
"Should find 'version' key, got: {:?}",
names
);
}
#[test]
#[cfg(feature = "lang-xml")]
fn test_xml_element_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.xml");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract XML chunks from sample.xml"
);
let catalog = chunks
.iter()
.find(|c| c.name == "catalog" && c.chunk_type == ChunkType::Struct);
assert!(
catalog.is_some(),
"Should find 'catalog' element as Struct, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-ini")]
fn test_ini_section_and_setting_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.ini");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract INI chunks from sample.ini"
);
let database = chunks
.iter()
.find(|c| c.name == "database" && c.chunk_type == ChunkType::Module);
assert!(
database.is_some(),
"Should find 'database' section as Module, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let host = chunks
.iter()
.find(|c| c.name == "host" && c.chunk_type == ChunkType::ConfigKey);
assert!(host.is_some(), "Should find 'host' setting as ConfigKey");
}
#[test]
#[cfg(feature = "lang-nix")]
fn test_nix_function_and_attrset_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.nix");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Nix chunks from sample.nix"
);
let func = chunks
.iter()
.find(|c| c.name == "greet" && c.chunk_type == ChunkType::Function);
assert!(
func.is_some(),
"Should find 'greet' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let attrset = chunks
.iter()
.find(|c| c.name == "config" && c.chunk_type == ChunkType::Struct);
assert!(
attrset.is_some(),
"Should find 'config' attrset as Struct, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-make")]
fn test_make_rule_and_variable_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.mk");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Make chunks from sample.mk"
);
let rule = chunks
.iter()
.find(|c| c.name == "clean" && c.chunk_type == ChunkType::Function);
assert!(
rule.is_some(),
"Should find 'clean' rule as Function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let var = chunks
.iter()
.find(|c| c.name == "CC" && c.chunk_type == ChunkType::Property);
assert!(
var.is_some(),
"Should find 'CC' variable as Property, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-latex")]
fn test_latex_section_and_command_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.tex");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract LaTeX chunks from sample.tex"
);
let section = chunks
.iter()
.find(|c| c.name == "Introduction" && c.chunk_type == ChunkType::Section);
assert!(
section.is_some(),
"Should find 'Introduction' section, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let cmd = chunks
.iter()
.find(|c| c.name == "highlight" && c.chunk_type == ChunkType::Function);
assert!(
cmd.is_some(),
"Should find 'highlight' command as Function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-solidity")]
fn test_solidity_contract_and_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.sol");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Solidity chunks from sample.sol"
);
let contract = chunks
.iter()
.find(|c| c.name == "Token" && c.chunk_type == ChunkType::Class);
assert!(
contract.is_some(),
"Should find 'Token' contract as Class, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let iface = chunks
.iter()
.find(|c| c.name == "IERC20" && c.chunk_type == ChunkType::Interface);
assert!(
iface.is_some(),
"Should find 'IERC20' interface, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let lib = chunks
.iter()
.find(|c| c.name == "SafeMath" && c.chunk_type == ChunkType::Module);
assert!(
lib.is_some(),
"Should find 'SafeMath' library as Module, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-cuda")]
fn test_cuda_kernel_and_struct_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.cu");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract CUDA chunks from sample.cu"
);
let kernel = chunks
.iter()
.find(|c| c.name == "vectorAdd" && c.chunk_type == ChunkType::Function);
assert!(
kernel.is_some(),
"Should find 'vectorAdd' kernel as Function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let s = chunks
.iter()
.find(|c| c.name == "DeviceConfig" && c.chunk_type == ChunkType::Struct);
assert!(
s.is_some(),
"Should find 'DeviceConfig' struct, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-glsl")]
fn test_glsl_function_and_struct_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.vert");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract GLSL chunks from sample.vert"
);
let func = chunks
.iter()
.find(|c| c.name == "transformNormal" && c.chunk_type == ChunkType::Function);
assert!(
func.is_some(),
"Should find 'transformNormal' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let s = chunks
.iter()
.find(|c| c.name == "Material" && c.chunk_type == ChunkType::Struct);
assert!(
s.is_some(),
"Should find 'Material' struct, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
fn test_html_injection_end_to_end() {
use std::io::Write;
let content = r#"<html>
<head>
<style>
.container { display: flex; gap: 1rem; }
@media (max-width: 768px) { .container { flex-direction: column; } }
</style>
</head>
<body>
<h1>Dashboard</h1>
<script>
function loadData(url) {
return fetch(url).then(r => r.json());
}
function renderChart(data) {
loadData('/api/stats');
console.log(data);
}
</script>
<script src="vendor.js"></script>
</body>
</html>
"#;
let mut file = tempfile::Builder::new().suffix(".html").tempfile().unwrap();
file.write_all(content.as_bytes()).unwrap();
file.flush().unwrap();
let parser = Parser::new().unwrap();
let chunks = parser.parse_file(file.path()).unwrap();
assert!(
chunks
.iter()
.any(|c| c.name == "Dashboard" && c.chunk_type == ChunkType::Section),
"HTML heading should be extracted"
);
let js_chunks: Vec<_> = chunks
.iter()
.filter(|c| c.language == Language::JavaScript)
.collect();
assert!(
js_chunks.iter().any(|c| c.name == "loadData"),
"JS function 'loadData' should be extracted via injection"
);
assert!(
js_chunks.iter().any(|c| c.name == "renderChart"),
"JS function 'renderChart' should be extracted via injection"
);
let css_chunks: Vec<_> = chunks
.iter()
.filter(|c| c.language == Language::Css)
.collect();
assert!(
!css_chunks.is_empty(),
"CSS chunks should be extracted from <style>"
);
assert!(
chunks
.iter()
.any(|c| c.chunk_type == ChunkType::Module && c.name.contains("vendor.js")),
"External script Module should be preserved"
);
let (calls, _types) = parser.parse_file_relationships(file.path()).unwrap();
let render_calls = calls.iter().find(|c| c.name == "renderChart");
assert!(
render_calls.is_some(),
"Call graph should include 'renderChart', got: {:?}",
calls.iter().map(|c| &c.name).collect::<Vec<_>>()
);
let callees: Vec<_> = render_calls
.unwrap()
.calls
.iter()
.map(|c| c.callee_name.as_str())
.collect();
assert!(
callees.contains(&"loadData"),
"renderChart should call loadData, got: {:?}",
callees
);
let render_chunk = chunks.iter().find(|c| c.name == "renderChart").unwrap();
let chunk_calls = parser.extract_calls_from_chunk(render_chunk);
let chunk_callees: Vec<_> = chunk_calls.iter().map(|c| c.callee_name.as_str()).collect();
assert!(
chunk_callees.contains(&"loadData"),
"extract_calls_from_chunk should find loadData, got: {:?}",
chunk_callees
);
}
#[test]
fn test_fenced_blocks_call_extraction() {
let md_content = r#"# Example
```rust
fn caller() {
helper();
another_func();
}
fn helper() -> i32 {
42
}
fn another_func() {}
```
"#;
let tmp = std::env::temp_dir().join("test_fenced_calls.md");
std::fs::write(&tmp, md_content).unwrap();
let parser = Parser::new().unwrap();
let (chunks, calls, _type_refs) = parser.parse_file_all(&tmp).unwrap();
std::fs::remove_file(&tmp).ok();
assert!(
!chunks.is_empty(),
"should extract chunks from fenced Rust block"
);
let names: Vec<&str> = chunks.iter().map(|c| c.name.as_str()).collect();
assert!(names.contains(&"caller"), "missing 'caller' function");
assert!(names.contains(&"helper"), "missing 'helper' function");
let caller_calls: Vec<_> = calls.iter().filter(|c| c.name == "caller").collect();
assert!(
caller_calls.is_empty(),
"Known limitation: fenced block call extraction does not produce calls for \
inner functions. If this starts passing, the limitation is fixed — \
update this test to assert the calls."
);
}
#[test]
#[cfg(feature = "lang-csharp")]
fn test_csharp_class_and_method_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.cs");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract C# chunks from sample.cs"
);
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Class);
assert!(
calc.is_some(),
"Should find 'Calculator' class, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
assert_eq!(calc.unwrap().language, Language::CSharp);
let add = chunks.iter().find(|c| {
c.name == "Add" && matches!(c.chunk_type, ChunkType::Method | ChunkType::Function)
});
assert!(
add.is_some(),
"Should find 'Add' method, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let op = chunks
.iter()
.find(|c| c.name == "Operation" && c.chunk_type == ChunkType::Enum);
assert!(
op.is_some(),
"Should find 'Operation' enum, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-fsharp")]
fn test_fsharp_module_and_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.fs");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract F# chunks from sample.fs"
);
let add = chunks.iter().find(|c| {
c.name == "add" && matches!(c.chunk_type, ChunkType::Function | ChunkType::Method)
});
assert!(
add.is_some(),
"Should find 'add' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
assert_eq!(add.unwrap().language, Language::FSharp);
let area = chunks.iter().find(|c| {
c.name == "area" && matches!(c.chunk_type, ChunkType::Function | ChunkType::Method)
});
assert!(
area.is_some(),
"Should find 'area' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-powershell")]
fn test_powershell_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.ps1");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract PowerShell chunks from sample.ps1"
);
let get_user = chunks
.iter()
.find(|c| c.name == "Get-UserInfo" && c.chunk_type == ChunkType::Function);
assert!(
get_user.is_some(),
"Should find 'Get-UserInfo' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
assert_eq!(get_user.unwrap().language, Language::PowerShell);
let set_user = chunks
.iter()
.find(|c| c.name == "Set-UserStatus" && c.chunk_type == ChunkType::Function);
assert!(
set_user.is_some(),
"Should find 'Set-UserStatus' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-scala")]
fn test_scala_class_and_trait_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.scala");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Scala chunks from sample.scala"
);
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Class);
assert!(
calc.is_some(),
"Should find 'Calculator' class, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
assert_eq!(calc.unwrap().language, Language::Scala);
let printable = chunks.iter().find(|c| {
c.name == "Printable" && matches!(c.chunk_type, ChunkType::Interface | ChunkType::Trait)
});
assert!(
printable.is_some(),
"Should find 'Printable' trait, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let math_utils = chunks.iter().find(|c| {
c.name == "MathUtils"
&& matches!(
c.chunk_type,
ChunkType::Object | ChunkType::Module | ChunkType::Class
)
});
assert!(
math_utils.is_some(),
"Should find 'MathUtils' object, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-ruby")]
fn test_ruby_class_and_module_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.rb");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Ruby chunks from sample.rb"
);
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Class);
assert!(
calc.is_some(),
"Should find 'Calculator' class, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
assert_eq!(calc.unwrap().language, Language::Ruby);
let add = chunks.iter().find(|c| {
c.name == "add" && matches!(c.chunk_type, ChunkType::Method | ChunkType::Function)
});
assert!(
add.is_some(),
"Should find 'add' method, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let helpers = chunks
.iter()
.find(|c| c.name == "MathHelpers" && c.chunk_type == ChunkType::Module);
assert!(
helpers.is_some(),
"Should find 'MathHelpers' module, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-vue")]
fn test_vue_script_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.vue");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Vue chunks from sample.vue"
);
let has_js = chunks.iter().any(|c| c.language == Language::JavaScript);
assert!(
has_js,
"Should extract JavaScript chunks from Vue <script>, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type, &c.language))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-svelte")]
fn test_svelte_script_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.svelte");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Svelte chunks from sample.svelte"
);
let has_js = chunks.iter().any(|c| c.language == Language::JavaScript);
assert!(
has_js,
"Should extract JavaScript chunks from Svelte <script>, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type, &c.language))
.collect::<Vec<_>>()
);
let increment = chunks.iter().find(|c| c.name == "increment");
assert!(
increment.is_some(),
"Should find 'increment' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}
#[test]
#[cfg(feature = "lang-razor")]
fn test_razor_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.cshtml");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract Razor chunks from sample.cshtml, got empty"
);
let names: Vec<_> = chunks.iter().map(|c| (&c.name, &c.chunk_type)).collect();
assert!(
chunks.len() >= 1,
"Should extract at least 1 chunk from Razor file, got: {:?}",
names
);
}
#[test]
#[cfg(feature = "lang-vbnet")]
fn test_vbnet_class_and_function_extraction() {
let parser = Parser::new().unwrap();
let path = fixtures_path().join("sample.vb");
let chunks = parser.parse_file(&path).unwrap();
assert!(
!chunks.is_empty(),
"Should extract VB.NET chunks from sample.vb"
);
let calc = chunks
.iter()
.find(|c| c.name == "Calculator" && c.chunk_type == ChunkType::Class);
assert!(
calc.is_some(),
"Should find 'Calculator' class, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
assert_eq!(calc.unwrap().language, Language::VbNet);
let add = chunks.iter().find(|c| {
c.name == "Add" && matches!(c.chunk_type, ChunkType::Function | ChunkType::Method)
});
assert!(
add.is_some(),
"Should find 'Add' function, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
let op = chunks
.iter()
.find(|c| c.name == "Operation" && c.chunk_type == ChunkType::Enum);
assert!(
op.is_some(),
"Should find 'Operation' enum, got: {:?}",
chunks
.iter()
.map(|c| (&c.name, &c.chunk_type))
.collect::<Vec<_>>()
);
}