#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analyzer_creation() {
let path = PathBuf::from("test.py");
let analyzer = UnifiedPythonAnalyzer::new(path.clone());
assert_eq!(analyzer.file_path(), path.as_path());
}
#[test]
fn test_analyzer_creation_absolute_path() {
let path = PathBuf::from("/home/user/project/main.py");
let analyzer = UnifiedPythonAnalyzer::new(path.clone());
assert_eq!(analyzer.file_path(), path.as_path());
}
#[test]
fn test_analyzer_creation_relative_path() {
let path = PathBuf::from("src/app.py");
let analyzer = UnifiedPythonAnalyzer::new(path.clone());
assert_eq!(analyzer.file_path(), Path::new("src/app.py"));
}
#[test]
fn test_initial_parse_count_is_zero() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
assert_eq!(analyzer.parse_count(), 0);
}
#[tokio::test]
async fn test_parse_count_increments() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(temp_file.path(), "def main():\n pass").unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
assert_eq!(analyzer.parse_count(), 0);
let _ = analyzer.analyze().await;
assert_eq!(analyzer.parse_count(), 1);
}
#[tokio::test]
async fn test_parse_count_increments_twice() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(temp_file.path(), "def main():\n pass").unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let _ = analyzer.analyze().await;
let _ = analyzer.analyze().await;
assert_eq!(analyzer.parse_count(), 2);
}
#[tokio::test]
async fn test_analyze_simple_function() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(temp_file.path(), "def hello():\n print('Hello')").unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(!result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_multiple_functions() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(
temp_file.path(),
r#"
def one():
pass
def two():
pass
def three():
pass
"#,
)
.unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert_eq!(result.file_metrics.functions.len(), 3);
}
#[tokio::test]
async fn test_analyze_async_function() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(
temp_file.path(),
r#"
async def fetch_data():
return "data"
"#,
)
.unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(!result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_with_control_flow() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(
temp_file.path(),
r#"
def complex_function(x):
if x > 0:
if x > 10:
return x * 2
return x + 1
else:
return 0
"#,
)
.unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(!result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_with_loops() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(
temp_file.path(),
r#"
def sum_range(n):
total = 0
for i in range(n):
total += i
return total
"#,
)
.unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(!result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_with_while_loop() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(
temp_file.path(),
r#"
def countdown(n):
while n > 0:
n -= 1
return n
"#,
)
.unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(!result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_with_try_except() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(
temp_file.path(),
r#"
def safe_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return 0
"#,
)
.unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(!result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_empty_file() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(temp_file.path(), "").unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_only_comments() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(
temp_file.path(),
r#"
# This is a comment
"""
This is a docstring
"""
"#,
)
.unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let result = analyzer.analyze().await.unwrap();
assert!(result.file_metrics.functions.is_empty());
}
#[tokio::test]
async fn test_analyze_nonexistent_file() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("/nonexistent/path/file.py"));
let result = analyzer.analyze().await;
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), AnalysisError::Io(_)));
}
#[tokio::test]
async fn test_unified_analysis_has_timestamp() {
let temp_file = tempfile::NamedTempFile::with_suffix(".py").unwrap();
std::fs::write(temp_file.path(), "def main():\n pass").unwrap();
let analyzer = UnifiedPythonAnalyzer::new(temp_file.path().to_path_buf());
let before = std::time::Instant::now();
let result = analyzer.analyze().await.unwrap();
let after = std::time::Instant::now();
assert!(result.parsed_at >= before);
assert!(result.parsed_at <= after);
}
#[test]
fn test_analysis_error_io_display() {
let error = AnalysisError::Io(std::io::Error::new(
std::io::ErrorKind::NotFound,
"File not found",
));
assert!(error.to_string().contains("Failed to read file"));
}
#[test]
fn test_analysis_error_parse_display() {
let error = AnalysisError::Parse("unexpected token".to_string());
assert!(error.to_string().contains("Failed to parse Python syntax"));
}
#[test]
fn test_analysis_error_analysis_display() {
let error = AnalysisError::Analysis("internal error".to_string());
assert!(error.to_string().contains("Analysis error"));
}
#[test]
fn test_estimate_complexity_simple() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
let content = "def simple():\n return 1";
let complexity = analyzer.estimate_complexity(content);
assert_eq!(complexity, 1); }
#[test]
fn test_estimate_complexity_with_if() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
let content = "def test():\n if x:\n return 1";
let complexity = analyzer.estimate_complexity(content);
assert!(complexity > 1); }
#[test]
fn test_estimate_complexity_with_for() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
let content = "def test():\n for i in range(10):\n print(i)";
let complexity = analyzer.estimate_complexity(content);
assert!(complexity > 1); }
#[test]
fn test_estimate_complexity_with_while() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
let content = "def test():\n while x:\n pass";
let complexity = analyzer.estimate_complexity(content);
assert!(complexity > 1); }
#[test]
fn test_estimate_complexity_with_try_except() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
let content = "def test():\n try:\n pass\n except:\n pass";
let complexity = analyzer.estimate_complexity(content);
assert!(complexity >= 2); }
#[test]
fn test_estimate_complexity_with_logical_operators() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
let content = "def test():\n if x and y or z:\n return True";
let complexity = analyzer.estimate_complexity(content);
assert!(complexity >= 3);
}
#[test]
fn test_estimate_complexity_with_elif() {
let analyzer = UnifiedPythonAnalyzer::new(PathBuf::from("test.py"));
let content = "def test():\n if x:\n pass\n elif y:\n pass";
let complexity = analyzer.estimate_complexity(content);
assert!(complexity >= 2);
}
#[test]
fn test_file_path_with_spaces() {
let path = PathBuf::from("path with spaces/file.py");
let analyzer = UnifiedPythonAnalyzer::new(path.clone());
assert_eq!(analyzer.file_path(), path.as_path());
}
#[test]
fn test_file_path_with_unicode() {
let path = PathBuf::from("проект/файл.py");
let analyzer = UnifiedPythonAnalyzer::new(path.clone());
assert_eq!(analyzer.file_path(), path.as_path());
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
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);
}
}
}