use crate::parse::ast::*;
use crate::parse::traits::Parameter;
#[cfg(test)]
mod zero_copy_tests {
use super::*;
#[test]
fn test_ast_node_byte_range_reference() {
let source = b"function hello() { return 42; }";
let byte_range = 0..source.len();
let node = AstNode::new(NodeType::Function, byte_range, 1, 0);
let text = node.text(source).unwrap();
assert_eq!(text, "function hello() { return 42; }");
assert_eq!(node.byte_range.start, 0);
assert_eq!(node.byte_range.end, source.len());
}
#[test]
fn test_ast_node_zero_copy_no_allocation() {
let source = b"let x = 42;";
let byte_range = 4..5;
let node = AstNode::new(NodeType::Variable, byte_range, 1, 4);
let text = node.text(source).unwrap();
assert_eq!(text, "x");
assert!(std::ptr::eq(text.as_bytes(), &source[4..5]));
}
#[test]
fn test_ast_node_lifetime_safety() {
let source = b"const value = 100;";
let node = AstNode::new(NodeType::Variable, 6..11, 1, 6);
let text = node.text(source).unwrap();
assert_eq!(text, "value");
}
#[test]
fn test_ast_node_bounds_checking() {
let source = b"short";
let node = AstNode::new(NodeType::Function, 0..100, 1, 0);
let result = node.text(source);
assert!(result.is_err());
assert!(matches!(
result,
Err(crate::parse::traits::Error::ParseFailed(_))
));
}
#[test]
fn test_function_element_zero_copy() {
let source = b"function test(a, b) { return a + b; }";
let func = FunctionElement {
name_range: 9..13, qualified_name: "test".to_string(),
parameters: vec![
Parameter {
name: "a".to_string(),
type_annotation: None,
default_value: None,
},
Parameter {
name: "b".to_string(),
type_annotation: None,
default_value: None,
},
],
return_type: None,
byte_range: 0..source.len(),
line_number: 1,
is_async: false,
docstring_range: None,
};
let text = func.get_text(source).unwrap();
assert_eq!(text, "function test(a, b) { return a + b; }");
let name = func.get_name(source).unwrap();
assert_eq!(name, Some("test"));
}
#[test]
fn test_class_element_zero_copy() {
let source = b"class MyClass extends Base { }";
let class = ClassElement {
name_range: 6..13, qualified_name: "MyClass".to_string(),
base_classes: vec!["Base".to_string()],
methods: vec![],
byte_range: 0..source.len(),
line_number: 1,
docstring_range: None,
};
assert_eq!(class.byte_range.len(), source.len());
let text = class.get_text(source).unwrap();
assert_eq!(text, "class MyClass extends Base { }");
let name = class.get_name(source).unwrap();
assert_eq!(name, Some("MyClass"));
}
#[test]
fn test_nested_ast_nodes() {
let source = b"function outer() { function inner() {} }";
let mut outer = AstNode::new(NodeType::Function, 0..source.len(), 1, 0);
outer.metadata.name_range = Some(9..14);
let inner_text = b"function inner() {}";
let inner_start = source
.windows(inner_text.len())
.position(|w| w == inner_text.as_slice())
.unwrap();
let inner_range = inner_start..(inner_start + inner_text.len());
let mut inner = AstNode::new(NodeType::Function, inner_range, 1, inner_start);
inner.metadata.name_range = Some(inner_start + 9..inner_start + 14);
outer.add_child(inner);
assert_eq!(
outer.text(source).unwrap(),
"function outer() { function inner() {} }"
);
assert_eq!(
outer.children[0].text(source).unwrap(),
"function inner() {}"
);
let outer_name = outer.name(source).unwrap();
assert_eq!(outer_name, "outer");
let inner_name = outer.children[0].name(source).unwrap();
assert_eq!(inner_name, "inner");
}
#[test]
fn test_memory_efficiency() {
let large_source = b"/* 1000 bytes of data */".repeat(100);
let byte_range = 0..large_source.len();
let node = AstNode::new(NodeType::Module, byte_range, 1, 0);
assert!(std::mem::size_of_val(&node) < large_source.len());
let text = node.text(&large_source).unwrap();
assert_eq!(text.len(), large_source.len());
}
#[test]
fn test_import_with_byte_range() {
let source = b"import std::collections::HashMap";
let import = Import {
module_path: "std::collections".to_string(),
items: vec!["HashMap".to_string()],
alias: None,
byte_range: 0..source.len(),
line_number: 1,
};
assert_eq!(import.byte_range.len(), source.len());
}
}
#[cfg(test)]
mod ast_structure_tests {
use super::*;
#[test]
fn test_node_type_variants() {
let types = vec![
NodeType::Module,
NodeType::Function,
NodeType::Class,
NodeType::Method,
NodeType::Variable,
NodeType::Import,
NodeType::Expression,
NodeType::Statement,
NodeType::Unknown,
];
for node_type in types {
let node = AstNode::new(node_type.clone(), 0..0, 1, 0);
assert_eq!(node.node_type, node_type);
}
}
#[test]
fn test_ast_node_hierarchy() {
let source = b"module test_module function test_func() end";
let mut module = AstNode::new(NodeType::Module, 0..100, 1, 0);
module.metadata.name_range = Some(7..19);
let mut func = AstNode::new(NodeType::Function, 20..50, 2, 4);
func.metadata.name_range = Some(28..37);
module.add_child(func);
assert_eq!(module.children.len(), 1);
let func_name = module.children[0].name(source).unwrap();
assert_eq!(func_name, "test_func");
}
#[test]
fn test_parameter_struct() {
let param = Parameter {
name: "x".to_string(),
type_annotation: Some("number".to_string()),
default_value: Some("42".to_string()),
};
assert_eq!(param.name, "x");
assert_eq!(param.type_annotation.unwrap(), "number");
assert_eq!(param.default_value.unwrap(), "42");
}
#[test]
fn test_import_struct() {
let import = Import {
module_path: "std::collections".to_string(),
items: vec!["HashMap".to_string(), "HashSet".to_string()],
alias: Some("collections".to_string()),
byte_range: 0..30,
line_number: 5,
};
assert_eq!(import.module_path, "std::collections");
assert_eq!(import.items.len(), 2);
assert_eq!(import.alias.unwrap(), "collections");
assert_eq!(import.line_number, 5);
assert_eq!(import.byte_range.len(), 30);
}
}
#[cfg(test)]
mod benchmark_style_tests {
use super::*;
use std::time::Instant;
#[test]
fn test_zero_copy_performance() {
let source = b"function benchmark() { /* ... */ }".repeat(1000);
let byte_range = 0..source.len();
let start = Instant::now();
let node = AstNode::new(NodeType::Function, byte_range, 1, 0);
for _ in 0..100 {
let _ = node.text(&source).unwrap();
}
let duration = start.elapsed();
assert!(duration.as_millis() < 10, "Zero-copy access should be fast");
}
#[test]
fn test_memory_overhead() {
let large_source = b"/* Large comment */".repeat(1000);
let byte_range = 0..large_source.len();
let node = AstNode::new(NodeType::Module, byte_range, 1, 0);
let node_size = std::mem::size_of_val(&node);
assert!(
node_size < 1000,
"AstNode should be small (fixed size, not storing source)"
);
let text = node.text(&large_source).unwrap();
assert_eq!(text.len(), large_source.len());
}
}