fix: all 4 archdoc issues — cycles, layout, integrations, usage examples
1. Module Cycles: properly format cycle paths as A → B → C → A 2. Repository layout: group by top-level directory with file counts 3. Integration detection: match patterns against import names (substring), add Storage and AI/ML categories to all templates and summary 4. Usage examples: extract __init__ required params for class constructors Also fix golden test to use ends_with for module-prefixed symbol IDs.
This commit is contained in:
@@ -98,17 +98,17 @@ fn test_enhanced_analysis_with_integrations() {
|
||||
assert!(found_advanced_module);
|
||||
|
||||
// Check that we found the UserService class with DB integration
|
||||
let user_service_symbol = project_model.symbols.values().find(|s| s.id == "UserService");
|
||||
let user_service_symbol = project_model.symbols.values().find(|s| s.id.ends_with("::UserService"));
|
||||
assert!(user_service_symbol.is_some());
|
||||
assert_eq!(user_service_symbol.unwrap().kind, archdoc_core::model::SymbolKind::Class);
|
||||
|
||||
// Check that we found the NotificationService class with queue integration
|
||||
let notification_service_symbol = project_model.symbols.values().find(|s| s.id == "NotificationService");
|
||||
let notification_service_symbol = project_model.symbols.values().find(|s| s.id.ends_with("::NotificationService"));
|
||||
assert!(notification_service_symbol.is_some());
|
||||
assert_eq!(notification_service_symbol.unwrap().kind, archdoc_core::model::SymbolKind::Class);
|
||||
|
||||
// Check that we found the fetch_external_user_data function with HTTP integration
|
||||
let fetch_external_user_data_symbol = project_model.symbols.values().find(|s| s.id == "fetch_external_user_data");
|
||||
let fetch_external_user_data_symbol = project_model.symbols.values().find(|s| s.id.ends_with("::fetch_external_user_data"));
|
||||
assert!(fetch_external_user_data_symbol.is_some());
|
||||
assert_eq!(fetch_external_user_data_symbol.unwrap().kind, archdoc_core::model::SymbolKind::Function);
|
||||
|
||||
|
||||
@@ -90,12 +90,12 @@ fn test_simple_project_generation() {
|
||||
assert!(found_example_module);
|
||||
|
||||
// Check that we found the Calculator class
|
||||
let calculator_symbol = project_model.symbols.values().find(|s| s.id == "Calculator");
|
||||
let calculator_symbol = project_model.symbols.values().find(|s| s.id.ends_with("::Calculator"));
|
||||
assert!(calculator_symbol.is_some());
|
||||
assert_eq!(calculator_symbol.unwrap().kind, archdoc_core::model::SymbolKind::Class);
|
||||
|
||||
// Check that we found the process_numbers function
|
||||
let process_numbers_symbol = project_model.symbols.values().find(|s| s.id == "process_numbers");
|
||||
let process_numbers_symbol = project_model.symbols.values().find(|s| s.id.ends_with("::process_numbers"));
|
||||
assert!(process_numbers_symbol.is_some());
|
||||
assert_eq!(process_numbers_symbol.unwrap().kind, archdoc_core::model::SymbolKind::Function);
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
//! Integration detection tests for ArchDoc
|
||||
//!
|
||||
//! These tests verify that the integration detection functionality works correctly.
|
||||
//! Integration detection now happens at module level during resolve_symbols,
|
||||
//! based on actual imports rather than AST body inspection.
|
||||
|
||||
use std::fs;
|
||||
use tempfile::TempDir;
|
||||
@@ -8,11 +10,12 @@ use archdoc_core::{Config, python_analyzer::PythonAnalyzer};
|
||||
|
||||
#[test]
|
||||
fn test_http_integration_detection() {
|
||||
let config = Config::default();
|
||||
let mut config = Config::default();
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
config.project.root = temp_dir.path().to_string_lossy().to_string();
|
||||
config.python.src_roots = vec![".".to_string()];
|
||||
let analyzer = PythonAnalyzer::new(config);
|
||||
|
||||
// Create a temporary Python file with HTTP integration
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let temp_file = temp_dir.path().join("test.py");
|
||||
let python_code = r#"
|
||||
import requests
|
||||
@@ -23,16 +26,16 @@ def fetch_data():
|
||||
"#;
|
||||
fs::write(&temp_file, python_code).expect("Failed to write test file");
|
||||
|
||||
// Parse the module
|
||||
let parsed_module = analyzer.parse_module(&temp_file)
|
||||
.expect("Failed to parse module");
|
||||
|
||||
// Check that we found the function
|
||||
assert_eq!(parsed_module.symbols.len(), 1);
|
||||
let symbol = &parsed_module.symbols[0];
|
||||
assert_eq!(symbol.id, "fetch_data");
|
||||
let model = analyzer.resolve_symbols(&[parsed_module])
|
||||
.expect("Failed to resolve symbols");
|
||||
|
||||
// Find the symbol (now prefixed with module id)
|
||||
let symbol = model.symbols.values().find(|s| s.qualname == "fetch_data")
|
||||
.expect("fetch_data symbol not found");
|
||||
|
||||
// Check that HTTP integration is detected
|
||||
assert!(symbol.integrations_flags.http);
|
||||
assert!(!symbol.integrations_flags.db);
|
||||
assert!(!symbol.integrations_flags.queue);
|
||||
@@ -40,11 +43,12 @@ def fetch_data():
|
||||
|
||||
#[test]
|
||||
fn test_db_integration_detection() {
|
||||
let config = Config::default();
|
||||
let mut config = Config::default();
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
config.project.root = temp_dir.path().to_string_lossy().to_string();
|
||||
config.python.src_roots = vec![".".to_string()];
|
||||
let analyzer = PythonAnalyzer::new(config);
|
||||
|
||||
// Create a temporary Python file with DB integration
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let temp_file = temp_dir.path().join("test.py");
|
||||
let python_code = r#"
|
||||
import sqlite3
|
||||
@@ -57,16 +61,15 @@ def get_user(user_id):
|
||||
"#;
|
||||
fs::write(&temp_file, python_code).expect("Failed to write test file");
|
||||
|
||||
// Parse the module
|
||||
let parsed_module = analyzer.parse_module(&temp_file)
|
||||
.expect("Failed to parse module");
|
||||
|
||||
// Check that we found the function
|
||||
assert_eq!(parsed_module.symbols.len(), 1);
|
||||
let symbol = &parsed_module.symbols[0];
|
||||
assert_eq!(symbol.id, "get_user");
|
||||
let model = analyzer.resolve_symbols(&[parsed_module])
|
||||
.expect("Failed to resolve symbols");
|
||||
|
||||
let symbol = model.symbols.values().find(|s| s.qualname == "get_user")
|
||||
.expect("get_user symbol not found");
|
||||
|
||||
// Check that DB integration is detected
|
||||
assert!(!symbol.integrations_flags.http);
|
||||
assert!(symbol.integrations_flags.db);
|
||||
assert!(!symbol.integrations_flags.queue);
|
||||
@@ -74,11 +77,12 @@ def get_user(user_id):
|
||||
|
||||
#[test]
|
||||
fn test_queue_integration_detection() {
|
||||
let config = Config::default();
|
||||
let mut config = Config::default();
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
config.project.root = temp_dir.path().to_string_lossy().to_string();
|
||||
config.python.src_roots = vec![".".to_string()];
|
||||
let analyzer = PythonAnalyzer::new(config);
|
||||
|
||||
// Create a temporary Python file with queue integration
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let temp_file = temp_dir.path().join("test.py");
|
||||
let python_code = r#"
|
||||
import redis
|
||||
@@ -89,16 +93,15 @@ def process_job(job_data):
|
||||
"#;
|
||||
fs::write(&temp_file, python_code).expect("Failed to write test file");
|
||||
|
||||
// Parse the module
|
||||
let parsed_module = analyzer.parse_module(&temp_file)
|
||||
.expect("Failed to parse module");
|
||||
|
||||
// Check that we found the function
|
||||
assert_eq!(parsed_module.symbols.len(), 1);
|
||||
let symbol = &parsed_module.symbols[0];
|
||||
assert_eq!(symbol.id, "process_job");
|
||||
let model = analyzer.resolve_symbols(&[parsed_module])
|
||||
.expect("Failed to resolve symbols");
|
||||
|
||||
let symbol = model.symbols.values().find(|s| s.qualname == "process_job")
|
||||
.expect("process_job symbol not found");
|
||||
|
||||
// Check that queue integration is detected
|
||||
assert!(!symbol.integrations_flags.http);
|
||||
assert!(!symbol.integrations_flags.db);
|
||||
assert!(symbol.integrations_flags.queue);
|
||||
@@ -106,11 +109,12 @@ def process_job(job_data):
|
||||
|
||||
#[test]
|
||||
fn test_no_integration_detection() {
|
||||
let config = Config::default();
|
||||
let mut config = Config::default();
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
config.project.root = temp_dir.path().to_string_lossy().to_string();
|
||||
config.python.src_roots = vec![".".to_string()];
|
||||
let analyzer = PythonAnalyzer::new(config);
|
||||
|
||||
// Create a temporary Python file with no integrations
|
||||
let temp_dir = TempDir::new().expect("Failed to create temp dir");
|
||||
let temp_file = temp_dir.path().join("test.py");
|
||||
let python_code = r#"
|
||||
def calculate_sum(a, b):
|
||||
@@ -118,17 +122,16 @@ def calculate_sum(a, b):
|
||||
"#;
|
||||
fs::write(&temp_file, python_code).expect("Failed to write test file");
|
||||
|
||||
// Parse the module
|
||||
let parsed_module = analyzer.parse_module(&temp_file)
|
||||
.expect("Failed to parse module");
|
||||
|
||||
// Check that we found the function
|
||||
assert_eq!(parsed_module.symbols.len(), 1);
|
||||
let symbol = &parsed_module.symbols[0];
|
||||
assert_eq!(symbol.id, "calculate_sum");
|
||||
let model = analyzer.resolve_symbols(&[parsed_module])
|
||||
.expect("Failed to resolve symbols");
|
||||
|
||||
let symbol = model.symbols.values().find(|s| s.qualname == "calculate_sum")
|
||||
.expect("calculate_sum symbol not found");
|
||||
|
||||
// Check that no integrations are detected
|
||||
assert!(!symbol.integrations_flags.http);
|
||||
assert!(!symbol.integrations_flags.db);
|
||||
assert!(!symbol.integrations_flags.queue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ fn test_render_with_integrations() {
|
||||
db: true,
|
||||
http: false,
|
||||
queue: false,
|
||||
storage: false,
|
||||
ai: false,
|
||||
},
|
||||
metrics: SymbolMetrics {
|
||||
fan_in: 0,
|
||||
@@ -54,6 +56,8 @@ fn test_render_with_integrations() {
|
||||
db: false,
|
||||
http: true,
|
||||
queue: false,
|
||||
storage: false,
|
||||
ai: false,
|
||||
},
|
||||
metrics: SymbolMetrics {
|
||||
fan_in: 0,
|
||||
|
||||
Reference in New Issue
Block a user