use std::fs;
use tempfile::TempDir;
#[tokio::test]
async fn test_issue_67_extracted_function_line_numbers() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let test_file = temp_dir.path().join("extracted_functions.rs");
let content = r#"//! Extracted utility functions
use std::result::Result;
/// Parse attribute arguments from token stream
///
/// This function was extracted from parser/utils.rs:500-550
/// It should now report line numbers from THIS file, not the old location
pub fn parse_rust_attribute_arguments(
tokens: &[String],
start: usize,
) -> Result<(Vec<String>, usize), String> {
let mut args = Vec::new();
let mut current = start;
// Complexity: 6 (cyclomatic)
while current < tokens.len() {
if tokens[current] == "," {
current += 1;
continue;
}
if tokens[current].starts_with("key") {
args.push(tokens[current].clone());
current += 1;
} else {
break;
}
}
Ok((args, current))
}
"#;
fs::write(&test_file, content).expect("Failed to write test file");
use pmat::services::complexity::analyze_file_complexity_uncached;
let result = analyze_file_complexity_uncached(&test_file, None)
.await
.expect("Analysis should succeed");
assert!(!result.functions.is_empty(), "Should detect the function");
let func = result
.functions
.iter()
.find(|f| f.name == "parse_rust_attribute_arguments")
.expect("Should find parse_rust_attribute_arguments");
let total_lines = content.lines().count() as u32;
assert!(
func.line_start > 0,
"line_start should be > 0 (1-indexed), got {}",
func.line_start
);
assert!(
func.line_start <= total_lines,
"line_start ({}) exceeds file length ({} lines)",
func.line_start,
total_lines
);
assert!(
func.line_end <= total_lines,
"Function line_end ({}) exceeds file length ({} lines). \
Issue #67 REGRESSION: Line numbers from cached old location",
func.line_end,
total_lines
);
assert!(
func.line_start < 100,
"Issue #67 REGRESSION DETECTED! \
line_start={} suggests stale cache from old file location (expected 500-550 from utils.rs). \
The fix should report line numbers from CURRENT file location (1-{})",
func.line_start,
total_lines
);
assert!(
func.line_start <= func.line_end,
"line_start ({}) must be <= line_end ({})",
func.line_start,
func.line_end
);
println!("✅ Issue #67 fix verified!");
println!(" Function: {}", func.name);
println!(
" Lines: {}-{} (in current file)",
func.line_start, func.line_end
);
println!(" File has {} total lines", total_lines);
println!(" ✅ Line numbers are accurate (not from old cached location 500-550)");
}
#[tokio::test]
async fn test_issue_67_multiple_extractions() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let file1 = temp_dir.path().join("file1.rs");
fs::write(&file1, "fn helper1() { let x = 1; x + 1 }").expect("Failed to write file1");
let file2 = temp_dir.path().join("file2.rs");
fs::write(
&file2,
"// Header comment\n\nfn helper1() { let x = 1; x + 1 }",
)
.expect("Failed to write file2");
use pmat::services::complexity::analyze_file_complexity_uncached;
let result1 = analyze_file_complexity_uncached(&file1, None)
.await
.expect("File1 analysis should succeed");
let result2 = analyze_file_complexity_uncached(&file2, None)
.await
.expect("File2 analysis should succeed");
assert!(!result1.functions.is_empty(), "File1 should have functions");
assert!(!result2.functions.is_empty(), "File2 should have functions");
let func1 = &result1.functions[0];
let func2 = &result2.functions[0];
assert!(
func1.line_start > 0,
"File1 function should have valid line_start, got {}",
func1.line_start
);
assert!(
func2.line_start > 0,
"File2 function should have valid line_start, got {}",
func2.line_start
);
assert_ne!(
func1.line_start, func2.line_start,
"Issue #67: Same function in different files should have different line numbers. \
Got same line {} for both, suggesting cache is keyed by content hash only",
func1.line_start
);
println!("✅ Issue #67 multi-file test passed!");
println!(" File1: function at line {}", func1.line_start);
println!(
" File2: function at line {} (different!)",
func2.line_start
);
}
#[tokio::test]
async fn test_issue_67_pre_commit_hook_scenario() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let extracted_file = temp_dir
.path()
.join("src")
.join("frontend")
.join("parser")
.join("utils_helpers");
fs::create_dir_all(&extracted_file).expect("Failed to create directory structure");
let attributes_file = extracted_file.join("attributes.rs");
let preamble = "// File header\n".repeat(147);
let function = r#"pub fn parse_rust_attribute_arguments(
tokens: &[Token],
start: usize,
) -> Result<(Vec<AttributeArg>, usize), String> {
let mut args = Vec::new();
let mut current = start;
while current < tokens.len() {
if tokens[current].is_comma() {
current += 1;
continue;
}
let (arg, next) = parse_single_arg(tokens, current)?;
args.push(arg);
current = next;
}
Ok((args, current))
}
"#;
let content = format!("{}{}", preamble, function);
fs::write(&attributes_file, &content).expect("Failed to write attributes file");
use pmat::services::complexity::analyze_file_complexity_uncached;
let result = analyze_file_complexity_uncached(&attributes_file, None)
.await
.expect("Pre-commit analysis should succeed");
let func = result
.functions
.iter()
.find(|f| f.name == "parse_rust_attribute_arguments")
.expect("Should find the extracted function");
let total_lines = content.lines().count() as u32;
assert!(
func.line_start > 0,
"Function should have valid line_start, got {}",
func.line_start
);
assert!(
func.line_start >= 140 && func.line_start <= 170,
"PRE-COMMIT HOOK FAILURE! \
Expected function around line 148 (current location), \
but got line {}. \
This would cause pre-commit hook to report wrong location.",
func.line_start
);
assert!(
func.line_start < 300,
"Issue #67 CRITICAL REGRESSION! \
line_start={} suggests bug is back. \
Pre-commit hooks would fail with 'complexity at line 500' \
for a {}-line file!",
func.line_start,
total_lines
);
println!("✅ Issue #67 pre-commit hook scenario PASSED!");
println!(" Function extracted from: utils.rs:500-550 (old location)");
println!(
" Function now at: attributes.rs:{}-{} (current location)",
func.line_start, func.line_end
);
println!(" ✅ Pre-commit hooks will report correct line numbers!");
}