use codegraph::CodeGraph;
use codegraph_python::{ParseError, Parser, ParserConfig};
use std::io::Write;
use std::path::Path;
use tempfile::NamedTempFile;
#[test]
fn test_parse_simple_file() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let file_path = Path::new("tests/fixtures/simple.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(result.is_ok());
let file_info = result.unwrap();
assert!(
!file_info.functions.is_empty(),
"Should find at least 1 function"
);
assert!(
!file_info.classes.is_empty(),
"Should find at least 1 class"
);
}
#[test]
fn test_parse_empty_file() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let file_path = Path::new("tests/fixtures/empty.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(result.is_ok());
let file_info = result.unwrap();
assert_eq!(file_info.functions.len(), 0);
assert_eq!(file_info.classes.len(), 0);
}
#[test]
fn test_parse_comments_only() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let file_path = Path::new("tests/fixtures/only_comments.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(result.is_ok());
let file_info = result.unwrap();
assert_eq!(file_info.functions.len(), 0);
assert_eq!(file_info.classes.len(), 0);
}
#[test]
fn test_parse_malformed_file() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let file_path = Path::new("tests/fixtures/malformed.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(result.is_err());
}
#[test]
fn test_parse_with_custom_config() {
let mut graph = CodeGraph::in_memory().unwrap();
let config = ParserConfig {
include_private: false,
include_tests: true,
parse_docs: true,
max_file_size: 10 * 1024 * 1024, file_extensions: vec!["py".to_string()],
exclude_dirs: vec!["__pycache__".to_string()],
parallel: false,
num_threads: Some(1),
};
let parser = Parser::with_config(config);
let file_path = Path::new("tests/fixtures/simple.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(result.is_ok());
}
#[test]
fn test_parse_source_directly() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let source = r#"
def hello():
print("Hello, world!")
class Greeter:
def greet(self):
return "Hi"
"#;
let file_path = Path::new("test.py");
let result = parser.parse_source(source, file_path, &mut graph);
assert!(result.is_ok());
let file_info = result.unwrap();
assert!(!file_info.functions.is_empty());
assert!(!file_info.classes.is_empty());
}
#[test]
fn test_file_too_large() {
let mut graph = CodeGraph::in_memory().unwrap();
let config = ParserConfig {
max_file_size: 10, ..Default::default()
};
let parser = Parser::with_config(config);
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(temp_file, "# This is a file larger than 10 bytes").unwrap();
temp_file.flush().unwrap();
let result = parser.parse_file(temp_file.path(), &mut graph);
assert!(result.is_err());
if let Err(ParseError::FileTooLarge {
path,
max_size,
actual_size,
}) = result
{
assert_eq!(max_size, 10);
assert!(actual_size > 10);
let _ = path; } else {
panic!("Expected FileTooLarge error");
}
}
#[test]
fn test_file_not_found() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let file_path = Path::new("nonexistent_file.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(result.is_err());
match result {
Err(ParseError::IoError { .. }) => {
}
_ => panic!("Expected IoError"),
}
}
#[test]
fn test_syntax_error() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let source = r#"
def broken_function(
# Missing closing parenthesis and colon
"#;
let file_path = Path::new("test.py");
let result = parser.parse_source(source, file_path, &mut graph);
assert!(result.is_err());
match result {
Err(ParseError::SyntaxError { .. }) => {
}
_ => panic!("Expected SyntaxError"),
}
}
#[test]
fn test_invalid_extension() {
let mut graph = CodeGraph::in_memory().unwrap();
let config = ParserConfig {
file_extensions: vec!["py".to_string()],
..Default::default()
};
let parser = Parser::with_config(config);
let mut temp_file = NamedTempFile::with_suffix(".txt").unwrap();
writeln!(temp_file, "def foo(): pass").unwrap();
temp_file.flush().unwrap();
let result = parser.parse_file(temp_file.path(), &mut graph);
assert!(result.is_err());
match result {
Err(ParseError::InvalidConfig(_)) => {
}
_ => panic!("Expected InvalidConfig error"),
}
}
#[test]
fn test_error_message_format() {
let error = ParseError::SyntaxError {
file: "test.py".to_string(),
line: 10,
column: 5,
message: "unexpected token".to_string(),
};
let error_string = format!("{error}");
assert!(error_string.contains("test.py"));
assert!(error_string.contains("10"));
assert!(error_string.contains("5"));
assert!(error_string.contains("unexpected token"));
}
#[test]
fn test_graph_error() {
let error = ParseError::GraphError("database connection failed".to_string());
let error_string = format!("{error}");
assert!(error_string.contains("Graph operation failed"));
assert!(error_string.contains("database connection failed"));
}
#[test]
fn test_unsupported_feature() {
let error = ParseError::UnsupportedFeature {
file: "advanced.py".to_string(),
feature: "pattern matching".to_string(),
};
let error_string = format!("{error}");
assert!(error_string.contains("advanced.py"));
assert!(error_string.contains("pattern matching"));
}
#[test]
fn test_call_extraction() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let file_path = Path::new("tests/fixtures/calls.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(result.is_ok(), "Should parse file with calls successfully");
let file_info = result.unwrap();
assert_eq!(
file_info.functions.len(),
4,
"Should find 2 functions + 2 methods"
);
assert_eq!(file_info.classes.len(), 1, "Should find Calculator class");
}
#[test]
fn test_comprehensive_relationships() {
let mut graph = CodeGraph::in_memory().unwrap();
let parser = Parser::new();
let file_path = Path::new("tests/fixtures/comprehensive.py");
let result = parser.parse_file(file_path, &mut graph);
assert!(
result.is_ok(),
"Should parse comprehensive file successfully"
);
let file_info = result.unwrap();
assert!(
file_info.classes.len() >= 3,
"Should find Animal, Dog, Cat classes"
);
assert!(
file_info.functions.len() >= 2,
"Should find create_animal, main functions"
);
}