use super::*;
use crate::index::{Symbol, SymbolKind};
use std::path::PathBuf;
use std::sync::Once;
static INIT: Once = Once::new();
fn init_grammar_cache() {
INIT.call_once(|| {
let config = tree_sitter_language_pack::PackConfig {
cache_dir: Some(crate::lang::grammar_cache_dir()),
..Default::default()
};
tree_sitter_language_pack::configure(&config)
.expect("failed to configure grammar cache");
});
}
fn extract(lang: &str, src: &str, file: &str) -> Vec<Symbol> {
init_grammar_cache();
parse_and_extract(lang, src.as_bytes(), &PathBuf::from(file)).unwrap()
}
#[test]
fn rust_function() {
let src = "pub fn calculate_fee(amount: u64) -> u64 {\n amount * 3 / 1000\n}";
let syms = extract("rust", src, "test.rs");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "calculate_fee");
assert_eq!(syms[0].kind, SymbolKind::Fn);
assert!(!syms[0].signature.contains('{'));
assert!(syms[0].signature.contains("pub fn"));
}
#[test]
fn rust_struct() {
let src = "pub struct FeeConfig {\n pub rate: u64,\n}";
let syms = extract("rust", src, "test.rs");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "FeeConfig");
assert_eq!(syms[0].kind, SymbolKind::Struct);
}
#[test]
fn rust_enum() {
let src = "pub enum FeeTier {\n Low,\n High,\n}";
let syms = extract("rust", src, "test.rs");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "FeeTier");
assert_eq!(syms[0].kind, SymbolKind::Enum);
}
#[test]
fn rust_trait() {
let src = "pub trait Configurable {\n fn configure(&self);\n}";
let syms = extract("rust", src, "test.rs");
let trait_sym = syms.iter().find(|s| s.name == "Configurable").unwrap();
assert_eq!(trait_sym.kind, SymbolKind::Trait);
}
#[test]
fn rust_multiple_symbols() {
let src = "pub fn foo() {}\nfn bar() {}\npub struct Baz;";
let syms = extract("rust", src, "test.rs");
assert!(syms.len() >= 3);
let names: Vec<&str> = syms.iter().map(|s| s.name.as_str()).collect();
assert!(names.contains(&"foo"));
assert!(names.contains(&"bar"));
assert!(names.contains(&"Baz"));
}
#[test]
fn rust_byte_range() {
let src = "pub fn test_func() -> u32 { 42 }";
let syms = extract("rust", src, "test.rs");
assert_eq!(syms.len(), 1);
let (start, end) = syms[0].byte_range;
assert!(start < end);
assert!(end <= src.len());
assert!(src[start..end].contains("test_func"));
}
#[test]
fn ts_function() {
let src = "function greet(name: string): string { return name; }";
let syms = extract("typescript", src, "test.ts");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "greet");
assert_eq!(syms[0].kind, SymbolKind::Fn);
}
#[test]
fn ts_class() {
let src = "export class UserService {\n getName() { return 'test'; }\n}";
let syms = extract("typescript", src, "test.ts");
let class = syms.iter().find(|s| s.name == "UserService").unwrap();
assert_eq!(class.kind, SymbolKind::Class);
let method = syms.iter().find(|s| s.name == "getName").unwrap();
assert_eq!(method.kind, SymbolKind::Fn);
}
#[test]
fn ts_interface() {
let src = "export interface Config {\n host: string;\n port: number;\n}";
let syms = extract("typescript", src, "test.ts");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "Config");
assert_eq!(syms[0].kind, SymbolKind::Interface);
}
#[test]
fn ts_arrow_function() {
let src = "const add = (a: number, b: number) => a + b;";
let syms = extract("typescript", src, "test.ts");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "add");
assert_eq!(syms[0].kind, SymbolKind::Fn);
assert!(syms[0].signature.contains("const add"), "should include const: {}", syms[0].signature);
assert!(!syms[0].signature.contains("a + b"), "should not include body: {}", syms[0].signature);
}
#[test]
fn ts_tsx() {
let src = "export function App() { return <div />; }";
let syms = extract("typescript", src, "test.tsx");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "App");
}
#[test]
fn py_function() {
let src = "def greet(name: str) -> str:\n return f'Hello, {name}'";
let syms = extract("python", src, "test.py");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "greet");
assert_eq!(syms[0].kind, SymbolKind::Fn);
assert!(syms[0].signature.contains("-> str"), "should preserve return type: {}", syms[0].signature);
assert!(syms[0].signature.contains("name: str"), "should preserve param types: {}", syms[0].signature);
}
#[test]
fn py_class() {
let src = "class UserService:\n def get_name(self):\n return 'test'";
let syms = extract("python", src, "test.py");
let class = syms.iter().find(|s| s.name == "UserService").unwrap();
assert_eq!(class.kind, SymbolKind::Class);
}
#[test]
fn py_constant() {
let src = "MAX_SIZE = 100";
let syms = extract("python", src, "test.py");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "MAX_SIZE");
assert_eq!(syms[0].kind, SymbolKind::Const);
}
#[test]
fn py_multiple_symbols() {
let src = "def foo():\n pass\n\ndef bar():\n pass\n\nclass Baz:\n pass";
let syms = extract("python", src, "test.py");
assert!(syms.len() >= 3);
let names: Vec<&str> = syms.iter().map(|s| s.name.as_str()).collect();
assert!(names.contains(&"foo"));
assert!(names.contains(&"bar"));
assert!(names.contains(&"Baz"));
}
#[test]
fn py_type_annotation_preserved() {
let src = "def foo(x: int, y: list[str]) -> bool:\n return True";
let syms = extract("python", src, "test.py");
assert_eq!(syms.len(), 1);
assert!(syms[0].signature.contains("int"), "sig: {}", syms[0].signature);
assert!(syms[0].signature.contains("bool"), "sig: {}", syms[0].signature);
}
#[test]
fn py_method_in_class() {
let src = "class Foo:\n def bar(self):\n pass";
let syms = extract("python", src, "test.py");
let cls = syms.iter().find(|s| s.name == "Foo").unwrap();
assert_eq!(cls.kind, SymbolKind::Class);
let bar = syms.iter().find(|s| s.name == "bar").unwrap();
assert_eq!(bar.kind, SymbolKind::Fn);
}
#[test]
fn py_decorated_method() {
let src = "class Foo:\n @property\n def name(self):\n return self._name";
let syms = extract("python", src, "test.py");
let name = syms.iter().find(|s| s.name == "name").unwrap();
assert_eq!(name.kind, SymbolKind::Fn);
}
#[test]
fn py_classmethod() {
let src = "class Foo:\n @classmethod\n def create(cls):\n return cls()";
let syms = extract("python", src, "test.py");
let create = syms.iter().find(|s| s.name == "create").unwrap();
assert_eq!(create.kind, SymbolKind::Fn);
}
#[test]
fn py_staticmethod() {
let src = "class Foo:\n @staticmethod\n def helper():\n pass";
let syms = extract("python", src, "test.py");
let helper = syms.iter().find(|s| s.name == "helper").unwrap();
assert_eq!(helper.kind, SymbolKind::Fn);
}
#[test]
fn py_decorated_top_level_fn() {
let src = "@timer\ndef run():\n pass";
let syms = extract("python", src, "test.py");
let run = syms.iter().find(|s| s.name == "run").unwrap();
assert_eq!(run.kind, SymbolKind::Fn);
}
#[test]
fn py_decorated_class() {
let src = "@dataclass\nclass Point:\n x: int\n y: int";
let syms = extract("python", src, "test.py");
let point = syms.iter().find(|s| s.name == "Point").unwrap();
assert_eq!(point.kind, SymbolKind::Class);
}
#[test]
fn py_async_method() {
let src = "class Server:\n async def handle(self, req):\n pass";
let syms = extract("python", src, "test.py");
let handle = syms.iter().find(|s| s.name == "handle").unwrap();
assert_eq!(handle.kind, SymbolKind::Fn);
}
#[test]
fn py_nested_class() {
let src = "class Outer:\n class Inner:\n pass";
let syms = extract("python", src, "test.py");
let outer = syms.iter().find(|s| s.name == "Outer").unwrap();
assert_eq!(outer.kind, SymbolKind::Class);
let inner = syms.iter().find(|s| s.name == "Inner").unwrap();
assert_eq!(inner.kind, SymbolKind::Class);
}
#[test]
fn py_dataclass_fields() {
let src = "@dataclass\nclass Point:\n x: int\n y: int\n z: float = 0.0";
let syms = extract("python", src, "test.py");
let point = syms.iter().find(|s| s.name == "Point").unwrap();
assert_eq!(point.kind, SymbolKind::Class);
let x = syms.iter().find(|s| s.name == "x").unwrap();
assert_eq!(x.kind, SymbolKind::Field);
let y = syms.iter().find(|s| s.name == "y").unwrap();
assert_eq!(y.kind, SymbolKind::Field);
let z = syms.iter().find(|s| s.name == "z").unwrap();
assert_eq!(z.kind, SymbolKind::Field);
}
#[test]
fn py_typed_class_variable() {
let src = "class Config:\n count: int = 0\n name: str = 'default'\n x = 5";
let syms = extract("python", src, "test.py");
let config = syms.iter().find(|s| s.name == "Config").unwrap();
assert_eq!(config.kind, SymbolKind::Class);
let count = syms.iter().find(|s| s.name == "count").unwrap();
assert_eq!(count.kind, SymbolKind::Field);
let name = syms.iter().find(|s| s.name == "name").unwrap();
assert_eq!(name.kind, SymbolKind::Field);
assert!(syms.iter().find(|s| s.name == "x").is_none(),
"plain class body assignment without type annotation should not be captured");
}
#[test]
fn go_function() {
let src = "func Calculate(amount int) int {\n\treturn amount * 3\n}";
let syms = extract("go", src, "test.go");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "Calculate");
assert_eq!(syms[0].kind, SymbolKind::Fn);
assert!(syms[0].signature.contains("func"), "sig: {}", syms[0].signature);
}
#[test]
fn go_method() {
let src = "func (s *Server) Start() error {\n\treturn nil\n}";
let syms = extract("go", src, "test.go");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "Start");
assert_eq!(syms[0].kind, SymbolKind::Fn);
}
#[test]
fn go_type() {
let src = "type Config struct {\n\tHost string\n}";
let syms = extract("go", src, "test.go");
assert_eq!(syms.len(), 2);
let config = syms.iter().find(|s| s.name == "Config").unwrap();
assert_eq!(config.kind, SymbolKind::Struct);
let host = syms.iter().find(|s| s.name == "Host").unwrap();
assert_eq!(host.kind, SymbolKind::Field);
}
#[test]
fn c_function() {
let src = "int calculate(int amount) {\n return amount * 3;\n}";
let syms = extract("c", src, "test.c");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "calculate");
assert_eq!(syms[0].kind, SymbolKind::Fn);
}
#[test]
fn c_pointer_returning_function() {
let src = "char *strdup(const char *s) {\n return NULL;\n}";
let syms = extract("c", src, "test.c");
let f = syms.iter().find(|s| s.name == "strdup");
assert!(f.is_some(), "should find pointer-returning fn: {:?}", syms);
assert_eq!(f.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn c_struct() {
let src = "struct Config {\n int rate;\n};";
let syms = extract("c", src, "test.c");
let s = syms.iter().find(|s| s.name == "Config");
assert!(s.is_some(), "should find struct: {:?}", syms);
assert_eq!(s.unwrap().kind, SymbolKind::Struct);
}
#[test]
fn cpp_class() {
let src = "class Server {\npublic:\n void start();\n};";
let syms = extract("cpp", src, "test.cpp");
let class = syms.iter().find(|s| s.name == "Server");
assert!(class.is_some(), "should find class: {:?}", syms);
assert_eq!(class.unwrap().kind, SymbolKind::Class);
}
#[test]
fn java_class_and_method() {
let src = "public class UserService {\n public String getName() {\n return \"test\";\n }\n}";
let syms = extract("java", src, "Test.java");
let class = syms.iter().find(|s| s.name == "UserService");
assert!(class.is_some(), "should find class: {:?}", syms);
assert_eq!(class.unwrap().kind, SymbolKind::Class);
}
#[test]
fn ruby_class_and_method() {
let src = "class UserService\n def get_name\n 'test'\n end\nend";
let syms = extract("ruby", src, "test.rb");
let class = syms.iter().find(|s| s.name == "UserService");
assert!(class.is_some(), "should find class: {:?}", syms);
assert_eq!(class.unwrap().kind, SymbolKind::Class);
let method = syms.iter().find(|s| s.name == "get_name");
assert!(method.is_some(), "should find method: {:?}", syms);
}
#[test]
fn lua_function() {
let src = "function greet(name)\n return 'Hello, ' .. name\nend";
let syms = extract("lua", src, "test.lua");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "greet");
assert_eq!(syms[0].kind, SymbolKind::Fn);
}
#[test]
fn zig_function() {
let src = "pub fn calculate(amount: u64) u64 {\n return amount * 3;\n}";
let syms = extract("zig", src, "test.zig");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "calculate");
assert_eq!(syms[0].kind, SymbolKind::Fn);
}
#[test]
fn zig_struct() {
let src = "const Point = struct {\n x: f32,\n y: f32,\n};";
let syms = extract("zig", src, "test.zig");
let point = syms.iter().find(|s| s.name == "Point").unwrap();
assert_eq!(point.kind, SymbolKind::Struct);
let x = syms.iter().find(|s| s.name == "x").unwrap();
assert_eq!(x.kind, SymbolKind::Field);
let y = syms.iter().find(|s| s.name == "y").unwrap();
assert_eq!(y.kind, SymbolKind::Field);
}
#[test]
fn zig_enum() {
let src = "const Color = enum {\n red,\n green,\n blue,\n};";
let syms = extract("zig", src, "test.zig");
let color = syms.iter().find(|s| s.name == "Color").unwrap();
assert_eq!(color.kind, SymbolKind::Enum);
}
#[test]
fn zig_union() {
let src = "const Msg = union {\n int: i32,\n float: f64,\n};";
let syms = extract("zig", src, "test.zig");
let msg = syms.iter().find(|s| s.name == "Msg").unwrap();
assert_eq!(msg.kind, SymbolKind::Struct);
assert!(syms.iter().any(|s| s.name == "int" && s.kind == SymbolKind::Field));
}
#[test]
fn zig_pub_struct() {
let src = "pub const Point = struct {\n x: f32,\n y: f32,\n};";
let syms = extract("zig", src, "test.zig");
let point = syms.iter().find(|s| s.name == "Point").unwrap();
assert_eq!(point.kind, SymbolKind::Struct);
assert_eq!(syms.iter().filter(|s| s.kind == SymbolKind::Field).count(), 2);
}
#[test]
fn zig_error_set() {
let src = "const MyError = error {\n OutOfMemory,\n InvalidInput,\n};";
let syms = extract("zig", src, "test.zig");
let err = syms.iter().find(|s| s.name == "MyError").unwrap();
assert_eq!(err.kind, SymbolKind::Enum);
}
#[test]
fn zig_const_and_test() {
let src = "const std = @import(\"std\");\npub const max_size: usize = 1024;\ntest \"basic\" {}";
let syms = extract("zig", src, "test.zig");
let ms = syms.iter().find(|s| s.name == "max_size").unwrap();
assert_eq!(ms.kind, SymbolKind::Const);
let t = syms.iter().find(|s| s.name.contains("basic")).unwrap();
assert_eq!(t.kind, SymbolKind::Fn);
}
#[test]
fn bash_function() {
let src = "function greet() {\n echo \"Hello\"\n}";
let syms = extract("bash", src, "test.sh");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "greet");
assert_eq!(syms[0].kind, SymbolKind::Fn);
}
#[test]
fn solidity_contract_and_function() {
let src = "contract Token {\n function transfer(address to, uint amount) public {\n }\n}";
let syms = extract("solidity", src, "test.sol");
let contract = syms.iter().find(|s| s.name == "Token");
assert!(contract.is_some(), "should find contract: {:?}", syms);
let func = syms.iter().find(|s| s.name == "transfer");
assert!(func.is_some(), "should find function: {:?}", syms);
}
#[test]
fn solidity_event() {
let src = "contract Token {\n event Transfer(address indexed from, address indexed to, uint256 value);\n}";
let syms = extract("solidity", src, "test.sol");
let event = syms.iter().find(|s| s.name == "Transfer");
assert!(event.is_some(), "should find event: {:?}", syms);
assert_eq!(event.unwrap().kind, SymbolKind::Event);
}
#[test]
fn elixir_module_and_function() {
let src = "defmodule MyApp.Users do\n def get_user(id) do\n id\n end\nend";
let syms = extract("elixir", src, "test.ex");
let module = syms.iter().find(|s| s.name == "MyApp.Users");
assert!(module.is_some(), "should find module: {:?}", syms);
assert_eq!(module.unwrap().kind, SymbolKind::Module);
let func = syms.iter().find(|s| s.name == "get_user");
assert!(func.is_some(), "should find function: {:?}", syms);
assert_eq!(func.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn elixir_type_definitions() {
let src = "defmodule MyApp do\n @type status :: :active | :inactive\n @typep internal :: map()\n @opaque token :: binary()\nend";
let syms = extract("elixir", src, "test.ex");
let status = syms.iter().find(|s| s.name == "status");
assert!(status.is_some(), "should find @type: {:?}", syms);
assert_eq!(status.unwrap().kind, SymbolKind::Type);
let internal = syms.iter().find(|s| s.name == "internal");
assert!(internal.is_some(), "should find @typep: {:?}", syms);
assert_eq!(internal.unwrap().kind, SymbolKind::Type);
let token = syms.iter().find(|s| s.name == "token");
assert!(token.is_some(), "should find @opaque: {:?}", syms);
assert_eq!(token.unwrap().kind, SymbolKind::Type);
}
#[test]
fn elixir_callback() {
let src = "defmodule MyBehaviour do\n @callback validate(term()) :: :ok | {:error, term()}\n @callback format(term()) :: String.t()\nend";
let syms = extract("elixir", src, "test.ex");
let validate = syms.iter().find(|s| s.name == "validate");
assert!(validate.is_some(), "should find @callback validate: {:?}", syms);
assert_eq!(validate.unwrap().kind, SymbolKind::Fn);
let format = syms.iter().find(|s| s.name == "format");
assert!(format.is_some(), "should find @callback format: {:?}", syms);
assert_eq!(format.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn elixir_defimpl() {
let src = "defimpl String.Chars, for: MyApp.User do\n def to_string(user), do: user.name\nend";
let syms = extract("elixir", src, "test.ex");
let impl_sym = syms.iter().find(|s| s.name == "String.Chars");
assert!(impl_sym.is_some(), "should find defimpl: {:?}", syms);
assert_eq!(impl_sym.unwrap().kind, SymbolKind::Module);
let func = syms.iter().find(|s| s.name == "to_string");
assert!(func.is_some(), "should find function in impl: {:?}", syms);
}
#[test]
fn elixir_protocol() {
let src = "defprotocol Renderable do\n @spec render(t()) :: String.t()\n def render(data)\nend";
let syms = extract("elixir", src, "test.ex");
let proto = syms.iter().find(|s| s.name == "Renderable");
assert!(proto.is_some(), "should find defprotocol: {:?}", syms);
assert_eq!(proto.unwrap().kind, SymbolKind::Module);
}
#[test]
fn swift_function() {
let src = "func greet(name: String) -> String {\n return \"Hello, \\(name)\"\n}";
let syms = extract("swift", src, "test.swift");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "greet");
assert_eq!(syms[0].kind, SymbolKind::Fn);
assert!(syms[0].signature.contains("func greet"));
}
#[test]
fn swift_class_and_method() {
let src = "class Animal {\n func speak() -> String {\n return \"...\"\n }\n}";
let syms = extract("swift", src, "test.swift");
let cls = syms.iter().find(|s| s.name == "Animal");
assert!(cls.is_some(), "should find class: {:?}", syms);
assert_eq!(cls.unwrap().kind, SymbolKind::Class);
let method = syms.iter().find(|s| s.name == "speak");
assert!(method.is_some(), "should find method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_struct() {
let src = "struct Point {\n var x: Double\n var y: Double\n}";
let syms = extract("swift", src, "test.swift");
let s = syms.iter().find(|s| s.name == "Point");
assert!(s.is_some(), "should find struct: {:?}", syms);
assert_eq!(s.unwrap().kind, SymbolKind::Struct);
let x = syms.iter().find(|s| s.name == "x");
assert!(x.is_some(), "should find property x: {:?}", syms);
assert_eq!(x.unwrap().kind, SymbolKind::Const);
let y = syms.iter().find(|s| s.name == "y");
assert!(y.is_some(), "should find property y: {:?}", syms);
assert_eq!(y.unwrap().kind, SymbolKind::Const);
}
#[test]
fn swift_enum() {
let src = "enum Direction {\n case north, south, east, west\n}";
let syms = extract("swift", src, "test.swift");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "Direction");
assert_eq!(syms[0].kind, SymbolKind::Enum);
}
#[test]
fn swift_enum_methods() {
let src = "enum Direction {\n case north, south\n func opposite() -> Direction {\n switch self {\n case .north: return .south\n default: return .north\n }\n }\n init?(rawValue: String) {\n switch rawValue {\n case \"n\": self = .north\n default: return nil\n }\n }\n}";
let syms = extract("swift", src, "test.swift");
let e = syms.iter().find(|s| s.name == "Direction");
assert!(e.is_some(), "should find enum: {:?}", syms);
assert_eq!(e.unwrap().kind, SymbolKind::Enum);
let method = syms.iter().find(|s| s.name == "opposite");
assert!(method.is_some(), "should find method in enum: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
let init_sym = syms.iter().find(|s| s.name == "init");
assert!(init_sym.is_some(), "should find init in enum: {:?}", syms);
assert_eq!(init_sym.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_protocol() {
let src = "protocol Drawable {\n func draw()\n}";
let syms = extract("swift", src, "test.swift");
let proto = syms.iter().find(|s| s.name == "Drawable");
assert!(proto.is_some(), "should find protocol: {:?}", syms);
assert_eq!(proto.unwrap().kind, SymbolKind::Interface);
let draw = syms.iter().find(|s| s.name == "draw");
assert!(draw.is_some(), "should find protocol method: {:?}", syms);
assert_eq!(draw.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_typealias() {
let src = "typealias Callback = (Int) -> Void";
let syms = extract("swift", src, "test.swift");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "Callback");
assert_eq!(syms[0].kind, SymbolKind::Type);
}
#[test]
fn swift_init() {
let src = "class Foo {\n init(x: Int) {\n self.x = x\n }\n}";
let syms = extract("swift", src, "test.swift");
let init_sym = syms.iter().find(|s| s.name == "init");
assert!(init_sym.is_some(), "should find init: {:?}", syms);
assert_eq!(init_sym.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_deinit() {
let src = "class Foo {\n deinit {\n print(\"bye\")\n }\n}";
let syms = extract("swift", src, "test.swift");
let deinit_sym = syms.iter().find(|s| s.name == "deinit");
assert!(deinit_sym.is_some(), "should find deinit: {:?}", syms);
assert_eq!(deinit_sym.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_actor() {
let src = "actor BankAccount {\n var balance: Double\n func deposit(_ amount: Double) {\n balance += amount\n }\n}";
let syms = extract("swift", src, "test.swift");
let actor = syms.iter().find(|s| s.name == "BankAccount");
assert!(actor.is_some(), "should find actor: {:?}", syms);
assert_eq!(actor.unwrap().kind, SymbolKind::Class);
let method = syms.iter().find(|s| s.name == "deposit");
assert!(method.is_some(), "should find actor method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
let prop = syms.iter().find(|s| s.name == "balance");
assert!(prop.is_some(), "should find actor property: {:?}", syms);
assert_eq!(prop.unwrap().kind, SymbolKind::Const);
}
#[test]
fn swift_extension() {
let src = "extension String {\n func reversed() -> String {\n return String(self.reversed())\n }\n}";
let syms = extract("swift", src, "test.swift");
let ext = syms.iter().find(|s| s.name == "String");
assert!(ext.is_some(), "should find extension: {:?}", syms);
assert_eq!(ext.unwrap().kind, SymbolKind::Module);
let method = syms.iter().find(|s| s.name == "reversed");
assert!(method.is_some(), "should find extension method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_extension_constrained() {
let src = "extension Array where Element: Comparable {\n func sorted() -> [Element] {\n return []\n }\n}";
let syms = extract("swift", src, "test.swift");
let ext = syms.iter().find(|s| s.kind == SymbolKind::Module);
assert!(ext.is_some(), "should find constrained extension: {:?}", syms);
let method = syms.iter().find(|s| s.name == "sorted");
assert!(method.is_some(), "should find method in constrained extension: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_subscript() {
let src = "struct Matrix {\n subscript(row: Int, col: Int) -> Double {\n return 0.0\n }\n}";
let syms = extract("swift", src, "test.swift");
let sub = syms.iter().find(|s| s.name == "subscript");
assert!(sub.is_some(), "should find subscript: {:?}", syms);
assert_eq!(sub.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn swift_protocol_property() {
let src = "protocol Named {\n var name: String { get }\n func greet() -> String\n}";
let syms = extract("swift", src, "test.swift");
let proto = syms.iter().find(|s| s.name == "Named");
assert!(proto.is_some(), "should find protocol: {:?}", syms);
assert_eq!(proto.unwrap().kind, SymbolKind::Interface);
let prop = syms.iter().find(|s| s.name == "name");
assert!(prop.is_some(), "should find protocol property: {:?}", syms);
assert_eq!(prop.unwrap().kind, SymbolKind::Const);
let method = syms.iter().find(|s| s.name == "greet");
assert!(method.is_some(), "should find protocol method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn dart_class_and_method() {
let src = "class Animal {\n String speak() { return \"...\"; }\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "class + method: {:?}", syms);
let cls = syms.iter().find(|s| s.name == "Animal");
assert!(cls.is_some(), "should find class: {:?}", syms);
assert_eq!(cls.unwrap().kind, SymbolKind::Class);
let method = syms.iter().find(|s| s.name == "speak");
assert!(method.is_some(), "should find method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn dart_mixin() {
let src = "mixin Swimming {\n void swim() { print(\"swimming\"); }\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "mixin + method: {:?}", syms);
let mixin = syms.iter().find(|s| s.name == "Swimming");
assert!(mixin.is_some(), "should find mixin: {:?}", syms);
assert_eq!(mixin.unwrap().kind, SymbolKind::Class);
let method = syms.iter().find(|s| s.name == "swim");
assert!(method.is_some(), "should find mixin method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn dart_extension() {
let src = "extension StringExt on String {\n String reversed() => split('').reversed.join('');\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "extension + method: {:?}", syms);
let ext = syms.iter().find(|s| s.name == "StringExt");
assert!(ext.is_some(), "should find extension: {:?}", syms);
assert_eq!(ext.unwrap().kind, SymbolKind::Module);
}
#[test]
fn dart_enum() {
let src = "enum Color { red, green, blue }";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "Color");
assert_eq!(syms[0].kind, SymbolKind::Enum);
}
#[test]
fn dart_top_level_function() {
let src = "void greet(String name) {\n print(\"Hello $name\");\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "greet");
assert_eq!(syms[0].kind, SymbolKind::Fn);
assert!(syms[0].signature.contains("greet"), "sig: {}", syms[0].signature);
}
#[test]
fn dart_typedef() {
let src = "typedef Callback = void Function(int);";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 1);
assert_eq!(syms[0].name, "Callback");
assert_eq!(syms[0].kind, SymbolKind::Type);
}
#[test]
fn dart_getter_setter() {
let src = "class Foo {\n String get displayName => \"\";\n set displayName(String value) {}\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 3, "class + getter + setter: {:?}", syms);
let getters_setters: Vec<_> = syms.iter().filter(|s| s.name == "displayName").collect();
assert_eq!(getters_setters.len(), 2, "should find getter and setter: {:?}", syms);
assert!(getters_setters.iter().all(|s| s.kind == SymbolKind::Fn));
}
#[test]
fn dart_constructor() {
let src = "class Animal {\n Animal(this.name);\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "class + constructor: {:?}", syms);
let ctor = syms.iter().find(|s| s.name == "Animal" && s.kind == SymbolKind::Fn);
assert!(ctor.is_some(), "should find constructor: {:?}", syms);
}
#[test]
fn dart_named_constructor() {
let src = "class Point {\n final int x;\n Point(this.x);\n Point.origin() : x = 0;\n}";
let syms = extract("dart", src, "test.dart");
let named = syms.iter().find(|s| s.name == "origin" && s.kind == SymbolKind::Fn);
assert!(named.is_some(), "should find named constructor 'origin': {:?}", syms);
let unnamed = syms.iter().find(|s| s.name == "Point" && s.kind == SymbolKind::Fn);
assert!(unnamed.is_some(), "should find unnamed constructor: {:?}", syms);
}
#[test]
fn dart_factory_constructor() {
let src = "class Animal {\n factory Animal.create(String name) => Animal(name);\n}";
let syms = extract("dart", src, "test.dart");
let factory = syms.iter().find(|s| s.kind == SymbolKind::Fn && s.name == "create");
assert!(factory.is_some(), "should find named factory 'create': {:?}", syms);
}
#[test]
fn dart_abstract_method() {
let src = "abstract class Repo {\n Future<int> getById(int id);\n Future<void> save(int item);\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 3, "class + 2 abstract methods: {:?}", syms);
let get_by_id = syms.iter().find(|s| s.name == "getById");
assert!(get_by_id.is_some(), "should find abstract method: {:?}", syms);
assert_eq!(get_by_id.unwrap().kind, SymbolKind::Fn);
let save = syms.iter().find(|s| s.name == "save");
assert!(save.is_some(), "should find abstract method save: {:?}", syms);
assert_eq!(save.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn dart_static_method() {
let src = "class Utils {\n static void doStuff() {}\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "class + static method (no duplicates): {:?}", syms);
let method = syms.iter().find(|s| s.name == "doStuff");
assert!(method.is_some(), "should find static method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn dart_operator_overload() {
let src = "class Vector {\n Vector operator +(Vector other) => Vector();\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "class + operator: {:?}", syms);
let op = syms.iter().find(|s| s.name == "operator" && s.kind == SymbolKind::Fn);
assert!(op.is_some(), "should find operator overload: {:?}", syms);
assert!(op.unwrap().signature.contains("operator +"), "sig should show operator: {}", op.unwrap().signature);
}
#[test]
fn dart_extension_getter() {
let src = "extension StringUtils on String {\n bool get isBlank => trim().isEmpty;\n String capitalize() => this[0] + substring(1);\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 3, "extension + getter + method: {:?}", syms);
let getter = syms.iter().find(|s| s.name == "isBlank");
assert!(getter.is_some(), "should find extension getter: {:?}", syms);
assert_eq!(getter.unwrap().kind, SymbolKind::Fn);
let method = syms.iter().find(|s| s.name == "capitalize");
assert!(method.is_some(), "should find extension method: {:?}", syms);
assert_eq!(method.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn dart_enum_getter() {
let src = "enum Status {\n active;\n String get label => name.toUpperCase();\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "enum + getter: {:?}", syms);
let e = syms.iter().find(|s| s.name == "Status");
assert!(e.is_some(), "should find enum: {:?}", syms);
assert_eq!(e.unwrap().kind, SymbolKind::Enum);
let getter = syms.iter().find(|s| s.name == "label");
assert!(getter.is_some(), "should find enum getter: {:?}", syms);
assert_eq!(getter.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn dart_sealed_class() {
let src = "sealed class Shape {}\nbase class Circle extends Shape {}\ninterface class Printable {}\nmixin class Both {}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 4, "4 class variants: {:?}", syms);
let names: Vec<&str> = syms.iter().map(|s| s.name.as_str()).collect();
assert!(names.contains(&"Shape"), "should find sealed class: {:?}", syms);
assert!(names.contains(&"Circle"), "should find base class: {:?}", syms);
assert!(names.contains(&"Printable"), "should find interface class: {:?}", syms);
assert!(names.contains(&"Both"), "should find mixin class: {:?}", syms);
assert!(syms.iter().all(|s| s.kind == SymbolKind::Class));
}
#[test]
fn dart_extension_type() {
let src = "extension type Wrapper(int value) {\n int get doubled => value * 2;\n}";
let syms = extract("dart", src, "test.dart");
assert_eq!(syms.len(), 2, "extension type + getter: {:?}", syms);
let ext = syms.iter().find(|s| s.name == "Wrapper");
assert!(ext.is_some(), "should find extension type: {:?}", syms);
assert_eq!(ext.unwrap().kind, SymbolKind::Class);
let getter = syms.iter().find(|s| s.name == "doubled");
assert!(getter.is_some(), "should find extension type getter: {:?}", syms);
assert_eq!(getter.unwrap().kind, SymbolKind::Fn);
}
#[test]
fn refs_rust_finds_all_usages() {
init_grammar_cache();
let src = "struct Foo { x: i32 }\nfn bar(f: Foo) -> Foo { f }";
let refs = find_references("rust", src.as_bytes(), &PathBuf::from("test.rs"), "Foo").unwrap();
assert_eq!(refs.len(), 3, "should find struct def + 2 usages: {:?}", refs.iter().map(|r| r.line).collect::<Vec<_>>());
}
#[test]
fn refs_rust_no_match() {
init_grammar_cache();
let src = "fn main() {}";
let refs = find_references("rust", src.as_bytes(), &PathBuf::from("test.rs"), "nonexistent").unwrap();
assert!(refs.is_empty());
}
#[test]
fn refs_line_column_correct() {
init_grammar_cache();
let src = "let x = 1;\nlet y = x + x;";
let refs = find_references("rust", src.as_bytes(), &PathBuf::from("test.rs"), "x").unwrap();
assert_eq!(refs.len(), 3);
assert_eq!(refs[0].line, 1);
assert_eq!(refs[1].line, 2);
assert_eq!(refs[2].line, 2);
}
#[test]
fn refs_typescript_identifier() {
init_grammar_cache();
let src = "const foo = 1;\nconsole.log(foo);";
let refs = find_references("typescript", src.as_bytes(), &PathBuf::from("test.ts"), "foo").unwrap();
assert_eq!(refs.len(), 2);
}
#[test]
fn refs_python_identifier() {
init_grammar_cache();
let src = "def greet(name):\n return name";
let refs = find_references("python", src.as_bytes(), &PathBuf::from("test.py"), "name").unwrap();
assert_eq!(refs.len(), 2);
}
#[test]
fn rust_test_attribute_detected() {
let syms = extract("rust", "#[test]\nfn test_foo() { assert!(true); }", "test.rs");
let sym = syms.iter().find(|s| s.name == "test_foo").unwrap();
assert!(sym.is_test, "function with #[test] should be marked as test");
}
#[test]
fn rust_cfg_test_mod_detected() {
let src = r#"
fn main() {}
#[cfg(test)]
mod tests {
fn helper() {}
}
"#;
let syms = extract("rust", src, "lib.rs");
let main_sym = syms.iter().find(|s| s.name == "main").unwrap();
assert!(!main_sym.is_test, "main should not be marked as test");
let tests_mod = syms.iter().find(|s| s.name == "tests").unwrap();
assert!(tests_mod.is_test, "#[cfg(test)] mod should be marked as test");
if let Some(helper) = syms.iter().find(|s| s.name == "helper") {
assert!(helper.is_test, "function inside #[cfg(test)] mod should be marked as test");
}
}
#[test]
fn rust_normal_fn_not_test() {
let syms = extract("rust", "pub fn add(a: i32, b: i32) -> i32 { a + b }", "lib.rs");
let sym = syms.iter().find(|s| s.name == "add").unwrap();
assert!(!sym.is_test, "normal function should not be marked as test");
}
#[test]
fn rust_test_and_normal_mixed() {
let src = r#"
pub fn real_fn() {}
#[test]
fn test_real_fn() {}
pub struct MyStruct;
"#;
let syms = extract("rust", src, "lib.rs");
let real_fn = syms.iter().find(|s| s.name == "real_fn").unwrap();
assert!(!real_fn.is_test);
let test_fn = syms.iter().find(|s| s.name == "test_real_fn").unwrap();
assert!(test_fn.is_test);
let my_struct = syms.iter().find(|s| s.name == "MyStruct").unwrap();
assert!(!my_struct.is_test);
}
#[test]
fn go_struct_interface_const_field() {
let src = "package main\ntype MyStruct struct {\n Name string\n}\ntype MyInterface interface {\n DoSomething() error\n}\ntype Duration int64\nconst MaxRetries = 3\n";
let syms = extract("go", src, "test.go");
let ms = syms.iter().find(|s| s.name == "MyStruct").unwrap();
assert_eq!(ms.kind, SymbolKind::Struct);
let mi = syms.iter().find(|s| s.name == "MyInterface").unwrap();
assert_eq!(mi.kind, SymbolKind::Interface);
let name = syms.iter().find(|s| s.name == "Name").unwrap();
assert_eq!(name.kind, SymbolKind::Field);
let ds = syms.iter().find(|s| s.name == "DoSomething").unwrap();
assert_eq!(ds.kind, SymbolKind::Fn);
let dur = syms.iter().find(|s| s.name == "Duration").unwrap();
assert_eq!(dur.kind, SymbolKind::Type);
let mr = syms.iter().find(|s| s.name == "MaxRetries").unwrap();
assert_eq!(mr.kind, SymbolKind::Const);
}
#[test]
fn rust_const_and_static() {
let src = "pub const MAX_SIZE: usize = 1024;\nstatic GLOBAL: &str = \"hello\";";
let syms = extract("rust", src, "test.rs");
let c = syms.iter().find(|s| s.name == "MAX_SIZE").unwrap();
assert_eq!(c.kind, SymbolKind::Const);
let s = syms.iter().find(|s| s.name == "GLOBAL").unwrap();
assert_eq!(s.kind, SymbolKind::Const);
}
#[test]
fn go_type_alias() {
let src = "package main\ntype Byte = uint8\n";
let syms = extract("go", src, "test.go");
let b = syms.iter().find(|s| s.name == "Byte").unwrap();
assert_eq!(b.kind, SymbolKind::Type);
}
#[test]
fn java_constructor_and_record() {
let src = "public class Foo {\n public Foo(int x) {}\n}\n";
let syms = extract("java", src, "Test.java");
let ctor = syms.iter().find(|s| s.name == "Foo" && s.kind == SymbolKind::Fn);
assert!(ctor.is_some(), "should find constructor: {:?}", syms);
}
#[test]
fn java_field_and_enum_constant() {
let src = "public class Config {\n private int port;\n}\nenum Color { RED, GREEN, BLUE }";
let syms = extract("java", src, "Test.java");
let field = syms.iter().find(|s| s.name == "port").unwrap();
assert_eq!(field.kind, SymbolKind::Field);
let red = syms.iter().find(|s| s.name == "RED").unwrap();
assert_eq!(red.kind, SymbolKind::Const);
}
#[test]
fn cpp_namespace() {
let src = "namespace utils {\n void helper() {}\n}";
let syms = extract("cpp", src, "test.cpp");
let ns = syms.iter().find(|s| s.name == "utils").unwrap();
assert_eq!(ns.kind, SymbolKind::Module);
let fn_ = syms.iter().find(|s| s.name == "helper").unwrap();
assert_eq!(fn_.kind, SymbolKind::Fn);
}
#[test]
fn cpp_template_class() {
let src = "template<typename T>\nclass Container {\npublic:\n T value;\n};";
let syms = extract("cpp", src, "test.cpp");
let c = syms.iter().find(|s| s.name == "Container").unwrap();
assert_eq!(c.kind, SymbolKind::Class);
}
#[test]
fn cpp_using_alias() {
let src = "using MyInt = int;";
let syms = extract("cpp", src, "test.cpp");
let t = syms.iter().find(|s| s.name == "MyInt").unwrap();
assert_eq!(t.kind, SymbolKind::Type);
}
#[test]
fn c_union() {
let src = "union Data {\n int i;\n float f;\n};";
let syms = extract("c", src, "test.c");
let u = syms.iter().find(|s| s.name == "Data").unwrap();
assert_eq!(u.kind, SymbolKind::Struct);
}
#[test]
fn c_function_prototype() {
let src = "void foo(int x);\nint bar(void);";
let syms = extract("c", src, "test.c");
assert_eq!(syms.len(), 2);
assert!(syms.iter().all(|s| s.kind == SymbolKind::Fn));
}
#[test]
fn solidity_modifier_and_state_var() {
let src = "contract Vault {\n uint256 public balance;\n modifier onlyOwner() { _; }\n}";
let syms = extract("solidity", src, "test.sol");
let bal = syms.iter().find(|s| s.name == "balance").unwrap();
assert_eq!(bal.kind, SymbolKind::Field);
let m = syms.iter().find(|s| s.name == "onlyOwner").unwrap();
assert_eq!(m.kind, SymbolKind::Fn);
}
#[test]
fn solidity_error_declaration() {
let src = "error Unauthorized(address caller);";
let syms = extract("solidity", src, "test.sol");
let e = syms.iter().find(|s| s.name == "Unauthorized").unwrap();
assert_eq!(e.kind, SymbolKind::Type);
}
#[test]
fn ruby_constant() {
let src = "MAX_SIZE = 100\nclass Foo\nend";
let syms = extract("ruby", src, "test.rb");
let c = syms.iter().find(|s| s.name == "MAX_SIZE").unwrap();
assert_eq!(c.kind, SymbolKind::Const);
}
#[test]
fn lua_top_level_local() {
let src = "local M = {}\nfunction M.setup()\nend\n";
let syms = extract("lua", src, "test.lua");
let m = syms.iter().find(|s| s.name == "M").unwrap();
assert_eq!(m.kind, SymbolKind::Const);
let setup = syms.iter().find(|s| s.name == "setup").unwrap();
assert_eq!(setup.kind, SymbolKind::Fn);
}
#[test]
fn bash_top_level_var() {
let src = "#!/bin/bash\nVERSION=\"1.0\"\nfoo() {\n local x=1\n}\n";
let syms = extract("bash", src, "test.sh");
let v = syms.iter().find(|s| s.name == "VERSION").unwrap();
assert_eq!(v.kind, SymbolKind::Const);
let f = syms.iter().find(|s| s.name == "foo").unwrap();
assert_eq!(f.kind, SymbolKind::Fn);
assert!(syms.iter().find(|s| s.name == "x").is_none(), "local vars should not be captured");
}