use super::*;
#[test]
fn test_rust_strategy_supports_rs_extension() {
let strategy = RustAstStrategy;
assert!(strategy.supports_extension("rs"));
}
#[test]
fn test_rust_strategy_rejects_other_extensions() {
let strategy = RustAstStrategy;
assert!(!strategy.supports_extension("py"));
assert!(!strategy.supports_extension("ts"));
assert!(!strategy.supports_extension("js"));
assert!(!strategy.supports_extension("c"));
assert!(!strategy.supports_extension("cpp"));
assert!(!strategy.supports_extension("kt"));
assert!(!strategy.supports_extension(""));
assert!(!strategy.supports_extension("rust"));
}
#[test]
fn test_strategy_registry_new() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("rs").is_some());
}
#[test]
fn test_strategy_registry_default() {
let registry = StrategyRegistry::default();
assert!(registry.get_strategy("rs").is_some());
}
#[test]
fn test_strategy_registry_get_rust_strategy() {
let registry = StrategyRegistry::new();
let strategy = registry.get_strategy("rs");
assert!(strategy.is_some());
let strategy = strategy.unwrap();
assert!(strategy.supports_extension("rs"));
}
#[test]
fn test_strategy_registry_get_nonexistent_strategy() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("unknown").is_none());
assert!(registry.get_strategy("xyz").is_none());
assert!(registry.get_strategy("").is_none());
}
#[test]
fn test_strategy_registry_register_custom_strategy() {
let mut registry = StrategyRegistry::new();
let rust_strategy = Arc::new(RustAstStrategy) as Arc<dyn AstStrategy>;
registry.register_strategy("custom".to_string(), rust_strategy);
assert!(registry.get_strategy("custom").is_some());
let strategy = registry.get_strategy("custom").unwrap();
assert!(strategy.supports_extension("rs"));
}
#[test]
fn test_strategy_registry_override_existing() {
let mut registry = StrategyRegistry::new();
let new_strategy = Arc::new(RustAstStrategy) as Arc<dyn AstStrategy>;
registry.register_strategy("rs".to_string(), new_strategy.clone());
let retrieved = registry.get_strategy("rs");
assert!(retrieved.is_some());
}
#[cfg(feature = "typescript-ast")]
mod typescript_tests {
use super::*;
#[test]
fn test_typescript_strategy_supports_ts() {
let strategy = TypeScriptAstStrategy;
assert!(strategy.supports_extension("ts"));
}
#[test]
fn test_typescript_strategy_supports_tsx() {
let strategy = TypeScriptAstStrategy;
assert!(strategy.supports_extension("tsx"));
}
#[test]
fn test_typescript_strategy_rejects_others() {
let strategy = TypeScriptAstStrategy;
assert!(!strategy.supports_extension("js"));
assert!(!strategy.supports_extension("jsx"));
assert!(!strategy.supports_extension("rs"));
assert!(!strategy.supports_extension(""));
}
#[test]
fn test_registry_has_typescript_strategy() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("ts").is_some());
assert!(registry.get_strategy("tsx").is_some());
}
}
#[cfg(feature = "typescript-ast")]
mod javascript_tests {
use super::*;
#[test]
fn test_javascript_strategy_supports_js() {
let strategy = JavaScriptAstStrategy;
assert!(strategy.supports_extension("js"));
}
#[test]
fn test_javascript_strategy_supports_jsx() {
let strategy = JavaScriptAstStrategy;
assert!(strategy.supports_extension("jsx"));
}
#[test]
fn test_javascript_strategy_rejects_others() {
let strategy = JavaScriptAstStrategy;
assert!(!strategy.supports_extension("ts"));
assert!(!strategy.supports_extension("tsx"));
assert!(!strategy.supports_extension("rs"));
assert!(!strategy.supports_extension(""));
}
#[test]
fn test_registry_has_javascript_strategy() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("js").is_some());
assert!(registry.get_strategy("jsx").is_some());
}
}
#[cfg(feature = "python-ast")]
mod python_tests {
use super::*;
#[test]
fn test_python_strategy_supports_py() {
let strategy = PythonAstStrategy;
assert!(strategy.supports_extension("py"));
}
#[test]
fn test_python_strategy_rejects_others() {
let strategy = PythonAstStrategy;
assert!(!strategy.supports_extension("pyw"));
assert!(!strategy.supports_extension("pyc"));
assert!(!strategy.supports_extension("rs"));
assert!(!strategy.supports_extension(""));
}
#[test]
fn test_registry_has_python_strategy() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("py").is_some());
}
}
#[cfg(feature = "c-ast")]
mod c_tests {
use super::*;
#[test]
fn test_c_strategy_supports_c() {
let strategy = CAstStrategy;
assert!(strategy.supports_extension("c"));
}
#[test]
fn test_c_strategy_supports_h() {
let strategy = CAstStrategy;
assert!(strategy.supports_extension("h"));
}
#[test]
fn test_c_strategy_rejects_others() {
let strategy = CAstStrategy;
assert!(!strategy.supports_extension("cpp"));
assert!(!strategy.supports_extension("hpp"));
assert!(!strategy.supports_extension("rs"));
assert!(!strategy.supports_extension(""));
}
#[test]
fn test_registry_has_c_strategy() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("c").is_some());
assert!(registry.get_strategy("h").is_some());
}
#[test]
fn test_c_extract_function_name_simple() {
let source = "int main(int argc, char **argv)";
let name = CAstStrategy::extract_function_name(source);
assert_eq!(name, Some("main".to_string()));
}
#[test]
fn test_c_extract_function_name_with_pointer() {
let source = "void *allocate_memory(size_t size)";
let name = CAstStrategy::extract_function_name(source);
assert_eq!(name, Some("allocate_memory".to_string()));
}
#[test]
fn test_c_extract_function_name_no_params() {
let source = "void no_params()";
let name = CAstStrategy::extract_function_name(source);
assert_eq!(name, Some("no_params".to_string()));
}
#[test]
fn test_c_extract_function_name_no_paren() {
let source = "int variable = 42";
let name = CAstStrategy::extract_function_name(source);
assert_eq!(name, None);
}
#[test]
fn test_c_extract_function_name_empty() {
let source = "";
let name = CAstStrategy::extract_function_name(source);
assert_eq!(name, None);
}
#[test]
fn test_c_extract_type_name_struct() {
let source = "struct MyStruct { int x; }";
let name = CAstStrategy::extract_type_name(source);
assert_eq!(name, Some("MyStruct".to_string()));
}
#[test]
fn test_c_extract_type_name_enum() {
let source = "enum Color { RED, GREEN, BLUE }";
let name = CAstStrategy::extract_type_name(source);
assert_eq!(name, Some("Color".to_string()));
}
#[test]
fn test_c_extract_type_name_union() {
let source = "union Data { int i; float f; }";
let name = CAstStrategy::extract_type_name(source);
assert_eq!(name, Some("Data".to_string()));
}
#[test]
fn test_c_extract_type_name_typedef() {
let source = "typedef int MyInt";
let name = CAstStrategy::extract_type_name(source);
assert_eq!(name, Some("int".to_string()));
}
#[test]
fn test_c_extract_type_name_no_keyword() {
let source = "int x = 5";
let name = CAstStrategy::extract_type_name(source);
assert_eq!(name, None);
}
#[test]
fn test_c_extract_type_name_single_word() {
let source = "struct";
let name = CAstStrategy::extract_type_name(source);
assert_eq!(name, None);
}
#[test]
fn test_c_byte_pos_to_line_first_line() {
let content_lines = vec!["first line", "second line", "third line"];
let line = CAstStrategy::byte_pos_to_line(0, &content_lines);
assert_eq!(line, 1);
}
#[test]
fn test_c_byte_pos_to_line_second_line() {
let content_lines = vec!["first line", "second line", "third line"];
let line = CAstStrategy::byte_pos_to_line(11, &content_lines);
assert_eq!(line, 2);
}
#[test]
fn test_c_byte_pos_to_line_third_line() {
let content_lines = vec!["first line", "second line", "third line"];
let line = CAstStrategy::byte_pos_to_line(23, &content_lines);
assert_eq!(line, 3);
}
#[test]
fn test_c_byte_pos_to_line_beyond_content() {
let content_lines = vec!["first line", "second line"];
let line = CAstStrategy::byte_pos_to_line(1000, &content_lines);
assert_eq!(line, 2); }
#[test]
fn test_c_byte_pos_to_line_empty() {
let content_lines: Vec<&str> = vec![];
let line = CAstStrategy::byte_pos_to_line(0, &content_lines);
assert_eq!(line, 0);
}
}
#[cfg(feature = "c-ast")]
mod cpp_tests {
use super::*;
#[test]
fn test_cpp_strategy_supports_cpp() {
let strategy = CppAstStrategy;
assert!(strategy.supports_extension("cpp"));
}
#[test]
fn test_cpp_strategy_supports_cc() {
let strategy = CppAstStrategy;
assert!(strategy.supports_extension("cc"));
}
#[test]
fn test_cpp_strategy_supports_cxx() {
let strategy = CppAstStrategy;
assert!(strategy.supports_extension("cxx"));
}
#[test]
fn test_cpp_strategy_supports_hpp() {
let strategy = CppAstStrategy;
assert!(strategy.supports_extension("hpp"));
}
#[test]
fn test_cpp_strategy_supports_hxx() {
let strategy = CppAstStrategy;
assert!(strategy.supports_extension("hxx"));
}
#[test]
fn test_cpp_strategy_rejects_c() {
let strategy = CppAstStrategy;
assert!(!strategy.supports_extension("c"));
assert!(!strategy.supports_extension("h"));
}
#[test]
fn test_cpp_strategy_rejects_others() {
let strategy = CppAstStrategy;
assert!(!strategy.supports_extension("rs"));
assert!(!strategy.supports_extension("py"));
assert!(!strategy.supports_extension(""));
}
#[test]
fn test_registry_has_cpp_strategy() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("cpp").is_some());
assert!(registry.get_strategy("cc").is_some());
assert!(registry.get_strategy("cxx").is_some());
assert!(registry.get_strategy("hpp").is_some());
assert!(registry.get_strategy("hxx").is_some());
}
#[test]
fn test_cpp_extract_function_name_simple() {
let source = "void processData(int value)";
let name = CppAstStrategy::extract_function_name(source);
assert_eq!(name, Some("processData".to_string()));
}
#[test]
fn test_cpp_extract_function_name_with_pointer() {
let source = "std::string* getName()";
let name = CppAstStrategy::extract_function_name(source);
assert_eq!(name, Some("getName".to_string()));
}
#[test]
fn test_cpp_extract_function_name_destructor() {
let source = "~MyClass()";
let name = CppAstStrategy::extract_function_name(source);
assert_eq!(name, Some("MyClass".to_string()));
}
#[test]
fn test_cpp_extract_function_name_operator() {
let source = "bool operator==(const MyClass& other)";
let name = CppAstStrategy::extract_function_name(source);
assert_eq!(name, Some("operator_overload".to_string()));
}
#[test]
fn test_cpp_extract_function_name_no_paren() {
let source = "int member_variable";
let name = CppAstStrategy::extract_function_name(source);
assert_eq!(name, None);
}
#[test]
fn test_cpp_extract_type_name_class() {
let source = "class MyClass { public: };";
let name = CppAstStrategy::extract_type_name(source);
assert_eq!(name, Some("MyClass".to_string()));
}
#[test]
fn test_cpp_extract_type_name_struct() {
let source = "struct Point { int x; int y; };";
let name = CppAstStrategy::extract_type_name(source);
assert_eq!(name, Some("Point".to_string()));
}
#[test]
fn test_cpp_extract_type_name_enum() {
let source = "enum class Status { OK, ERROR };";
let name = CppAstStrategy::extract_type_name(source);
assert_eq!(name, Some("Status".to_string()));
}
#[test]
fn test_cpp_extract_type_name_union() {
let source = "union Variant { int i; float f; };";
let name = CppAstStrategy::extract_type_name(source);
assert_eq!(name, Some("Variant".to_string()));
}
#[test]
fn test_cpp_extract_type_name_template() {
let source = "class Vector<T> { };";
let name = CppAstStrategy::extract_type_name(source);
assert_eq!(name, Some("Vector".to_string()));
}
#[test]
fn test_cpp_extract_type_name_with_brace() {
let source = "struct Data{ int x; }";
let name = CppAstStrategy::extract_type_name(source);
assert_eq!(name, Some("Data".to_string()));
}
#[test]
fn test_cpp_extract_type_name_no_keyword() {
let source = "int main() { }";
let name = CppAstStrategy::extract_type_name(source);
assert_eq!(name, None);
}
#[test]
fn test_cpp_byte_pos_to_line_first_line() {
let content_lines = vec!["// comment", "int main() {", "}"];
let line = CppAstStrategy::byte_pos_to_line(0, &content_lines);
assert_eq!(line, 1);
}
#[test]
fn test_cpp_byte_pos_to_line_middle() {
let content_lines = vec!["first", "second", "third"];
let line = CppAstStrategy::byte_pos_to_line(6, &content_lines);
assert_eq!(line, 2);
}
#[test]
fn test_cpp_byte_pos_to_line_end() {
let content_lines = vec!["a", "b"];
let line = CppAstStrategy::byte_pos_to_line(100, &content_lines);
assert_eq!(line, 2);
}
}
#[cfg(feature = "kotlin-ast")]
mod kotlin_tests {
use super::*;
#[test]
fn test_kotlin_strategy_supports_kt() {
let strategy = KotlinAstStrategy;
assert!(strategy.supports_extension("kt"));
}
#[test]
fn test_kotlin_strategy_supports_kts() {
let strategy = KotlinAstStrategy;
assert!(strategy.supports_extension("kts"));
}
#[test]
fn test_kotlin_strategy_rejects_others() {
let strategy = KotlinAstStrategy;
assert!(!strategy.supports_extension("java"));
assert!(!strategy.supports_extension("rs"));
assert!(!strategy.supports_extension(""));
}
#[test]
fn test_registry_has_kotlin_strategy() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("kt").is_some());
assert!(registry.get_strategy("kts").is_some());
}
#[test]
fn test_kotlin_extract_function_name_simple() {
let source = "fun greet(name: String): String";
let name = KotlinAstStrategy::extract_function_name(source);
assert_eq!(name, Some("greet".to_string()));
}
#[test]
fn test_kotlin_extract_function_name_no_params() {
let source = "fun main()";
let name = KotlinAstStrategy::extract_function_name(source);
assert_eq!(name, Some("main".to_string()));
}
#[test]
fn test_kotlin_extract_function_name_no_fun() {
let source = "val x = 5";
let name = KotlinAstStrategy::extract_function_name(source);
assert_eq!(name, None);
}
#[test]
fn test_kotlin_extract_function_name_no_paren() {
let source = "fun incomplete";
let name = KotlinAstStrategy::extract_function_name(source);
assert_eq!(name, None);
}
#[test]
fn test_kotlin_extract_class_name_regular() {
let source = "class MyClass";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("MyClass".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_with_constructor() {
let source = "class Person(val name: String)";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("Person".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_with_inheritance() {
let source = "class Child: Parent";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("Child".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_data_class() {
let source = "data class User(val id: Int, val name: String)";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("User".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_enum_class() {
let source = "enum class Color { RED, GREEN, BLUE }";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("Color".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_interface() {
let source = "interface Drawable";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("Drawable".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_object() {
let source = "object Singleton";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("Singleton".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_with_generic() {
let source = "class Container<T>";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, Some("Container".to_string()));
}
#[test]
fn test_kotlin_extract_class_name_no_keyword() {
let source = "fun main() {}";
let name = KotlinAstStrategy::extract_class_name(source);
assert_eq!(name, None);
}
#[test]
fn test_kotlin_byte_pos_to_line_first() {
let content_lines = vec!["package com.example", "class Test"];
let line = KotlinAstStrategy::byte_pos_to_line(0, &content_lines);
assert_eq!(line, 1);
}
#[test]
fn test_kotlin_byte_pos_to_line_second() {
let content_lines = vec!["package com.example", "class Test"];
let line = KotlinAstStrategy::byte_pos_to_line(20, &content_lines);
assert_eq!(line, 2);
}
#[test]
fn test_kotlin_byte_pos_to_line_beyond() {
let content_lines = vec!["line1"];
let line = KotlinAstStrategy::byte_pos_to_line(1000, &content_lines);
assert_eq!(line, 1);
}
#[test]
fn test_kotlin_byte_pos_to_line_empty() {
let content_lines: Vec<&str> = vec![];
let line = KotlinAstStrategy::byte_pos_to_line(0, &content_lines);
assert_eq!(line, 0);
}
}
#[test]
fn test_strategy_registry_multiple_gets() {
let registry = StrategyRegistry::new();
let s1 = registry.get_strategy("rs");
let s2 = registry.get_strategy("rs");
assert!(s1.is_some());
assert!(s2.is_some());
}
#[test]
fn test_strategy_registry_case_sensitivity() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy("rs").is_some());
assert!(registry.get_strategy("RS").is_none());
assert!(registry.get_strategy("Rs").is_none());
}
#[test]
fn test_strategy_registry_whitespace() {
let registry = StrategyRegistry::new();
assert!(registry.get_strategy(" rs").is_none());
assert!(registry.get_strategy("rs ").is_none());
assert!(registry.get_strategy(" rs ").is_none());
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use super::*;
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);
}
#[test]
fn rust_strategy_only_supports_rs(ext in "[a-z]{1,5}") {
let strategy = RustAstStrategy;
if ext == "rs" {
prop_assert!(strategy.supports_extension(&ext));
} else {
prop_assert!(!strategy.supports_extension(&ext));
}
}
#[test]
fn registry_always_has_rust(_seed in 0u32..1000) {
let registry = StrategyRegistry::new();
prop_assert!(registry.get_strategy("rs").is_some());
}
#[test]
fn registered_strategy_retrievable(ext in "[a-z]{1,10}") {
let mut registry = StrategyRegistry::new();
let strategy = Arc::new(RustAstStrategy) as Arc<dyn AstStrategy>;
registry.register_strategy(ext.clone(), strategy);
prop_assert!(registry.get_strategy(&ext).is_some());
}
#[test]
fn unknown_extension_returns_none(ext in "[a-z0-9]{6,15}") {
let registry = StrategyRegistry::new();
if ext.len() > 5 {
prop_assert!(registry.get_strategy(&ext).is_none());
}
}
}
#[cfg(feature = "c-ast")]
proptest! {
#[test]
fn c_byte_pos_always_returns_valid_line(pos in 0usize..10000, num_lines in 1usize..100) {
let lines: Vec<&str> = (0..num_lines).map(|_| "content").collect();
let result = CAstStrategy::byte_pos_to_line(pos, &lines);
prop_assert!(result >= 1 || lines.is_empty());
prop_assert!(result <= num_lines || lines.is_empty());
}
#[test]
fn c_function_name_requires_paren(source in "[a-z ]+") {
let result = CAstStrategy::extract_function_name(&source);
if !source.contains('(') {
prop_assert!(result.is_none());
}
}
}
#[cfg(feature = "c-ast")]
proptest! {
#[test]
fn cpp_byte_pos_always_returns_valid_line(pos in 0usize..10000, num_lines in 1usize..100) {
let lines: Vec<&str> = (0..num_lines).map(|_| "code").collect();
let result = CppAstStrategy::byte_pos_to_line(pos, &lines);
prop_assert!(result >= 1 || lines.is_empty());
prop_assert!(result <= num_lines || lines.is_empty());
}
}
#[cfg(feature = "kotlin-ast")]
proptest! {
#[test]
fn kotlin_byte_pos_always_returns_valid_line(pos in 0usize..10000, num_lines in 1usize..100) {
let lines: Vec<&str> = (0..num_lines).map(|_| "kotlin").collect();
let result = KotlinAstStrategy::byte_pos_to_line(pos, &lines);
prop_assert!(result >= 1 || lines.is_empty());
prop_assert!(result <= num_lines || lines.is_empty());
}
#[test]
fn kotlin_function_name_requires_fun(source in "[a-z ()]+") {
let result = KotlinAstStrategy::extract_function_name(&source);
if !source.contains("fun ") {
prop_assert!(result.is_none());
}
}
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod integration_tests {
use super::*;
use std::path::Path;
use tempfile::TempDir;
#[tokio::test]
async fn test_rust_strategy_analyze_simple_file() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("test.rs");
std::fs::write(
&file_path,
r#"
fn main() {
println!("Hello, world!");
}
/// Helper.
pub fn helper() -> i32 {
42
}
"#,
)
.expect("Failed to write test file");
let strategy = RustAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert_eq!(context.language, "rust");
assert!(!context.items.is_empty());
}
#[tokio::test]
async fn test_rust_strategy_analyze_nonexistent_file() {
let strategy = RustAstStrategy;
let classifier = FileClassifier::default();
let result = strategy
.analyze(Path::new("/nonexistent/path/file.rs"), &classifier)
.await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_rust_strategy_analyze_empty_file() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("empty.rs");
std::fs::write(&file_path, "").expect("Failed to write test file");
let strategy = RustAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert!(context.items.is_empty());
}
#[tokio::test]
async fn test_rust_strategy_analyze_syntax_error() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("invalid.rs");
std::fs::write(&file_path, "fn main( { incomplete syntax")
.expect("Failed to write test file");
let strategy = RustAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
let _ = result;
}
#[tokio::test]
async fn test_rust_strategy_analyze_complex_file() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("complex.rs");
std::fs::write(
&file_path,
r#"
use std::collections::HashMap;
/// My struct.
pub struct MyStruct {
field1: i32,
field2: String,
}
/// My enum.
pub enum MyEnum {
Variant1,
Variant2(i32),
}
/// Trait defining My trait behavior.
pub trait MyTrait {
fn do_something(&self);
}
impl MyTrait for MyStruct {
fn do_something(&self) {
println!("{}", self.field1);
}
}
pub async fn async_function() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
mod inner_module {
/// Inner function.
pub fn inner_function() {}
}
"#,
)
.expect("Failed to write test file");
let strategy = RustAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert_eq!(context.language, "rust");
assert!(context.items.len() >= 4);
}
#[cfg(feature = "typescript-ast")]
mod typescript_integration {
use super::*;
#[tokio::test]
async fn test_typescript_strategy_analyze_simple() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("test.ts");
std::fs::write(
&file_path,
r#"
function greet(name: string): string {
return `Hello, ${name}!`;
}
export class Greeter {
private name: string;
constructor(name: string) {
this.name = name;
}
greet(): string {
return `Hello, ${this.name}!`;
}
}
"#,
)
.expect("Failed to write test file");
let strategy = TypeScriptAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert!(context.language == "typescript" || context.language == "ts");
}
}
#[cfg(feature = "python-ast")]
mod python_integration {
use super::*;
#[tokio::test]
async fn test_python_strategy_analyze_simple() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("test.py");
std::fs::write(
&file_path,
r#"
def greet(name: str) -> str:
return f"Hello, {name}!"
class Greeter:
def __init__(self, name: str):
self.name = name
def greet(self) -> str:
return f"Hello, {self.name}!"
"#,
)
.expect("Failed to write test file");
let strategy = PythonAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert!(context.language == "python" || context.language == "py");
}
}
#[cfg(feature = "c-ast")]
mod c_integration {
use super::*;
#[tokio::test]
async fn test_c_strategy_analyze_simple() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("test.c");
std::fs::write(
&file_path,
r#"
#include <stdio.h>
struct Point {
int x;
int y;
};
int add(int a, int b) {
return a + b;
}
int main(int argc, char *argv[]) {
printf("Hello, World!\n");
return 0;
}
"#,
)
.expect("Failed to write test file");
let strategy = CAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert_eq!(context.language, "c");
}
#[tokio::test]
async fn test_cpp_strategy_analyze_simple() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("test.cpp");
std::fs::write(
&file_path,
r#"
#include <iostream>
#include <string>
class Greeter {
public:
std::string name;
Greeter(const std::string& n) : name(n) {}
void greet() const {
std::cout << "Hello, " << name << "!" << std::endl;
}
};
int main() {
Greeter g("World");
g.greet();
return 0;
}
"#,
)
.expect("Failed to write test file");
let strategy = CppAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert_eq!(context.language, "cpp");
}
}
#[cfg(feature = "kotlin-ast")]
mod kotlin_integration {
use super::*;
#[tokio::test]
async fn test_kotlin_strategy_analyze_simple() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file_path = temp_dir.path().join("test.kt");
std::fs::write(
&file_path,
r#"
package com.example
fun greet(name: String): String {
return "Hello, $name!"
}
class Greeter(private val name: String) {
fun greet(): String = "Hello, $name!"
}
data class User(val id: Int, val name: String)
enum class Status { ACTIVE, INACTIVE }
"#,
)
.expect("Failed to write test file");
let strategy = KotlinAstStrategy;
let classifier = FileClassifier::default();
let result = strategy.analyze(&file_path, &classifier).await;
assert!(result.is_ok());
let context = result.unwrap();
assert!(context.language == "kotlin" || context.language == "kt");
}
}
}