From 69bea669b00eb1db6d4adbe32931787b4f8ca02a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:31:04 +0000 Subject: [PATCH 1/4] Initial plan From ccc7848b6f1f88648f33a5e0764214e7fbeb04e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:40:38 +0000 Subject: [PATCH 2/4] test: Add comprehensive tests for phase2-log-file-symbols (closes #17) Co-authored-by: jade-codes <9397730+jade-codes@users.noreply.github.com> --- crates/mother-cli/src/commands/scan/phase2.rs | 323 ++++++++++++++++++ 1 file changed, 323 insertions(+) diff --git a/crates/mother-cli/src/commands/scan/phase2.rs b/crates/mother-cli/src/commands/scan/phase2.rs index 7e67203..9a3c608 100644 --- a/crates/mother-cli/src/commands/scan/phase2.rs +++ b/crates/mother-cli/src/commands/scan/phase2.rs @@ -1489,4 +1489,327 @@ mod tests { assert_eq!(positions[0].1, 0); assert_eq!(positions[1].1, u32::MAX); } + + // ============================================================================ + // Tests for log_file_symbols + // ============================================================================ + // + // The `log_file_symbols` function logs information about file symbol extraction. + // Since it uses `tracing::info!` and is a private function, these tests verify + // that the function can be called with various inputs without panicking. + // The actual log output is handled by the tracing infrastructure. + // ============================================================================ + + #[test] + fn test_log_file_symbols_normal_case() { + // Test with a typical file path and symbol counts + let file = create_test_file("/home/user/project/src/main.rs"); + + // This should not panic + log_file_symbols(&file, 10, 15); + } + + #[test] + fn test_log_file_symbols_zero_symbols() { + // Test with zero symbol counts + let file = create_test_file("/path/to/empty.rs"); + + log_file_symbols(&file, 0, 0); + } + + #[test] + fn test_log_file_symbols_large_counts() { + // Test with large symbol counts + let file = create_test_file("/large/file.rs"); + + log_file_symbols(&file, 1000, 2000); + log_file_symbols(&file, usize::MAX, usize::MAX); + } + + #[test] + fn test_log_file_symbols_mismatched_counts() { + // Test with different symbol counts (more symbols than LSP symbols) + let file = create_test_file("/test.rs"); + + log_file_symbols(&file, 100, 50); + + // Test with fewer symbols than LSP symbols + log_file_symbols(&file, 20, 100); + } + + #[test] + fn test_log_file_symbols_single_symbol() { + // Test with a single symbol + let file = create_test_file("/single.rs"); + + log_file_symbols(&file, 1, 1); + } + + #[test] + fn test_log_file_symbols_different_file_paths() { + // Test with various file path formats + let test_paths = vec![ + "/simple.rs", + "/path/to/deeply/nested/file.rs", + "/with-dashes.rs", + "/with_underscores.rs", + "/with.dots.rs", + "/123numeric.rs", + "relative/path.rs", + "./current/dir.rs", + "../parent/dir.rs", + ]; + + for path in test_paths { + let file = create_test_file(path); + log_file_symbols(&file, 5, 10); + } + } + + #[test] + fn test_log_file_symbols_special_characters_in_path() { + // Test with special characters in file paths + let special_paths = vec![ + "/path/with spaces/file.rs", + "/path/with'quotes.rs", + "/path/with\"doublequotes.rs", + "/path/with(parens).rs", + "/path/with[brackets].rs", + ]; + + for path in special_paths { + let file = create_test_file(path); + log_file_symbols(&file, 3, 5); + } + } + + #[test] + fn test_log_file_symbols_unicode_in_path() { + // Test with Unicode characters in file paths + let unicode_paths = vec![ + "/path/日本語.rs", + "/path/файл.rs", + "/path/αρχείο.rs", + "/path/文件.rs", + "/path/🦀emoji.rs", + ]; + + for path in unicode_paths { + let file = create_test_file(path); + log_file_symbols(&file, 7, 12); + } + } + + #[test] + fn test_log_file_symbols_different_file_extensions() { + // Test with different file extensions (different languages) + let mut file_py = create_test_file("/test.py"); + file_py.language = Language::Python; + log_file_symbols(&file_py, 5, 8); + + let mut file_ts = create_test_file("/test.ts"); + file_ts.language = Language::TypeScript; + log_file_symbols(&file_ts, 15, 20); + + let mut file_js = create_test_file("/test.js"); + file_js.language = Language::JavaScript; + log_file_symbols(&file_js, 10, 15); + + let mut file_go = create_test_file("/test.go"); + file_go.language = Language::Go; + log_file_symbols(&file_go, 8, 12); + } + + #[test] + fn test_log_file_symbols_no_extension() { + // Test with file that has no extension + let file = create_test_file("/path/to/Makefile"); + log_file_symbols(&file, 2, 3); + } + + #[test] + fn test_log_file_symbols_hidden_file() { + // Test with hidden file (starts with dot) + let file = create_test_file("/path/to/.gitignore"); + log_file_symbols(&file, 0, 0); + } + + #[test] + fn test_log_file_symbols_root_file() { + // Test with file at root + let file = create_test_file("/main.rs"); + log_file_symbols(&file, 5, 10); + } + + #[test] + fn test_log_file_symbols_very_long_filename() { + // Test with a very long filename + let long_name = "/".to_string() + &"a".repeat(200) + ".rs"; + let file = create_test_file(&long_name); + log_file_symbols(&file, 3, 5); + } + + #[test] + fn test_log_file_symbols_equal_counts() { + // Test when symbol count equals LSP count + let file = create_test_file("/equal.rs"); + + for count in [0, 1, 5, 10, 100, 1000] { + log_file_symbols(&file, count, count); + } + } + + #[test] + fn test_log_file_symbols_only_one_count_zero() { + // Test with one count zero and the other non-zero + let file = create_test_file("/test.rs"); + + log_file_symbols(&file, 0, 10); + log_file_symbols(&file, 10, 0); + } + + #[test] + fn test_log_file_symbols_all_supported_languages() { + // Test with all supported languages + let languages = vec![ + Language::Rust, + Language::Python, + Language::TypeScript, + Language::JavaScript, + Language::Go, + ]; + + for (i, lang) in languages.iter().enumerate() { + let mut file = create_test_file(&format!("/test{}.txt", i)); + file.language = *lang; + log_file_symbols(&file, i + 1, i + 2); + } + } + + #[test] + fn test_log_file_symbols_boundary_counts() { + // Test with boundary values for counts + let file = create_test_file("/boundary.rs"); + + // Minimum values + log_file_symbols(&file, 0, 0); + + // Small values + log_file_symbols(&file, 1, 1); + + // Medium values + log_file_symbols(&file, 50, 75); + + // Large values + log_file_symbols(&file, 10000, 15000); + } + + #[test] + fn test_log_file_symbols_multiple_calls() { + // Test calling the function multiple times in sequence + let file1 = create_test_file("/file1.rs"); + let file2 = create_test_file("/file2.rs"); + let file3 = create_test_file("/file3.rs"); + + log_file_symbols(&file1, 5, 10); + log_file_symbols(&file2, 3, 7); + log_file_symbols(&file3, 8, 12); + + // Call again with same file + log_file_symbols(&file1, 5, 10); + } + + #[test] + fn test_log_file_symbols_with_different_content_hashes() { + // Test that different content hashes don't affect logging + let mut file1 = create_test_file("/test.rs"); + file1.content_hash = "hash1".to_string(); + log_file_symbols(&file1, 5, 10); + + let mut file2 = create_test_file("/test.rs"); + file2.content_hash = "hash2".to_string(); + log_file_symbols(&file2, 5, 10); + } + + #[test] + fn test_log_file_symbols_with_different_file_uris() { + // Test that different URI formats work + let mut file1 = create_test_file("/test.rs"); + file1.file_uri = "file:///test.rs".to_string(); + log_file_symbols(&file1, 3, 5); + + let mut file2 = create_test_file("/test.rs"); + file2.file_uri = "file:///home/user/test.rs".to_string(); + log_file_symbols(&file2, 3, 5); + } + + #[test] + fn test_log_file_symbols_directory_path_only() { + // Test with just a directory (no filename component) + // This tests the unwrap_or_default() behavior + let file = create_test_file("/some/directory/"); + log_file_symbols(&file, 1, 2); + } + + #[test] + fn test_log_file_symbols_path_with_trailing_slash() { + // Test with path that has trailing slash + let file = create_test_file("/path/to/file.rs/"); + log_file_symbols(&file, 2, 3); + } + + #[test] + fn test_log_file_symbols_consistent_output_same_input() { + // Test that calling with same input multiple times is consistent + let file = create_test_file("/consistent.rs"); + + for _ in 0..5 { + log_file_symbols(&file, 10, 15); + } + } + + #[test] + fn test_log_file_symbols_extreme_count_difference() { + // Test with extreme differences between symbol and LSP counts + let file = create_test_file("/extreme.rs"); + + log_file_symbols(&file, 0, 10000); + log_file_symbols(&file, 10000, 0); + log_file_symbols(&file, 1, 10000); + log_file_symbols(&file, 10000, 1); + } + + #[test] + fn test_log_file_symbols_windows_style_path() { + // Test with Windows-style paths (though they may not be valid on Unix) + let file = create_test_file("C:\\Users\\test\\file.rs"); + log_file_symbols(&file, 5, 8); + } + + #[test] + fn test_log_file_symbols_mixed_separators() { + // Test with mixed path separators + let file = create_test_file("/path\\to/mixed\\file.rs"); + log_file_symbols(&file, 3, 5); + } + + #[test] + fn test_log_file_symbols_double_extension() { + // Test with double extension + let file = create_test_file("/file.test.rs"); + log_file_symbols(&file, 4, 6); + } + + #[test] + fn test_log_file_symbols_all_count_combinations() { + // Test various combinations of counts + let file = create_test_file("/combo.rs"); + let counts = vec![0, 1, 5, 10, 50, 100]; + + for &symbol_count in &counts { + for &lsp_count in &counts { + log_file_symbols(&file, symbol_count, lsp_count); + } + } + } } From 2031f680a9da59c71650a8f1f3de30562aa14363 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:46:36 +0000 Subject: [PATCH 3/4] fix: Replace vec! with array for clippy compliance Co-authored-by: jade-codes <9397730+jade-codes@users.noreply.github.com> --- crates/mother-cli/src/commands/scan/phase2.rs | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/crates/mother-cli/src/commands/scan/phase2.rs b/crates/mother-cli/src/commands/scan/phase2.rs index 9a3c608..2e9d354 100644 --- a/crates/mother-cli/src/commands/scan/phase2.rs +++ b/crates/mother-cli/src/commands/scan/phase2.rs @@ -1504,7 +1504,7 @@ mod tests { fn test_log_file_symbols_normal_case() { // Test with a typical file path and symbol counts let file = create_test_file("/home/user/project/src/main.rs"); - + // This should not panic log_file_symbols(&file, 10, 15); } @@ -1513,7 +1513,7 @@ mod tests { fn test_log_file_symbols_zero_symbols() { // Test with zero symbol counts let file = create_test_file("/path/to/empty.rs"); - + log_file_symbols(&file, 0, 0); } @@ -1521,7 +1521,7 @@ mod tests { fn test_log_file_symbols_large_counts() { // Test with large symbol counts let file = create_test_file("/large/file.rs"); - + log_file_symbols(&file, 1000, 2000); log_file_symbols(&file, usize::MAX, usize::MAX); } @@ -1530,9 +1530,9 @@ mod tests { fn test_log_file_symbols_mismatched_counts() { // Test with different symbol counts (more symbols than LSP symbols) let file = create_test_file("/test.rs"); - + log_file_symbols(&file, 100, 50); - + // Test with fewer symbols than LSP symbols log_file_symbols(&file, 20, 100); } @@ -1541,7 +1541,7 @@ mod tests { fn test_log_file_symbols_single_symbol() { // Test with a single symbol let file = create_test_file("/single.rs"); - + log_file_symbols(&file, 1, 1); } @@ -1653,7 +1653,7 @@ mod tests { fn test_log_file_symbols_equal_counts() { // Test when symbol count equals LSP count let file = create_test_file("/equal.rs"); - + for count in [0, 1, 5, 10, 100, 1000] { log_file_symbols(&file, count, count); } @@ -1663,7 +1663,7 @@ mod tests { fn test_log_file_symbols_only_one_count_zero() { // Test with one count zero and the other non-zero let file = create_test_file("/test.rs"); - + log_file_symbols(&file, 0, 10); log_file_symbols(&file, 10, 0); } @@ -1671,7 +1671,7 @@ mod tests { #[test] fn test_log_file_symbols_all_supported_languages() { // Test with all supported languages - let languages = vec![ + let languages = [ Language::Rust, Language::Python, Language::TypeScript, @@ -1690,16 +1690,16 @@ mod tests { fn test_log_file_symbols_boundary_counts() { // Test with boundary values for counts let file = create_test_file("/boundary.rs"); - + // Minimum values log_file_symbols(&file, 0, 0); - + // Small values log_file_symbols(&file, 1, 1); - + // Medium values log_file_symbols(&file, 50, 75); - + // Large values log_file_symbols(&file, 10000, 15000); } @@ -1710,11 +1710,11 @@ mod tests { let file1 = create_test_file("/file1.rs"); let file2 = create_test_file("/file2.rs"); let file3 = create_test_file("/file3.rs"); - + log_file_symbols(&file1, 5, 10); log_file_symbols(&file2, 3, 7); log_file_symbols(&file3, 8, 12); - + // Call again with same file log_file_symbols(&file1, 5, 10); } @@ -1725,7 +1725,7 @@ mod tests { let mut file1 = create_test_file("/test.rs"); file1.content_hash = "hash1".to_string(); log_file_symbols(&file1, 5, 10); - + let mut file2 = create_test_file("/test.rs"); file2.content_hash = "hash2".to_string(); log_file_symbols(&file2, 5, 10); @@ -1737,7 +1737,7 @@ mod tests { let mut file1 = create_test_file("/test.rs"); file1.file_uri = "file:///test.rs".to_string(); log_file_symbols(&file1, 3, 5); - + let mut file2 = create_test_file("/test.rs"); file2.file_uri = "file:///home/user/test.rs".to_string(); log_file_symbols(&file2, 3, 5); @@ -1762,7 +1762,7 @@ mod tests { fn test_log_file_symbols_consistent_output_same_input() { // Test that calling with same input multiple times is consistent let file = create_test_file("/consistent.rs"); - + for _ in 0..5 { log_file_symbols(&file, 10, 15); } @@ -1772,7 +1772,7 @@ mod tests { fn test_log_file_symbols_extreme_count_difference() { // Test with extreme differences between symbol and LSP counts let file = create_test_file("/extreme.rs"); - + log_file_symbols(&file, 0, 10000); log_file_symbols(&file, 10000, 0); log_file_symbols(&file, 1, 10000); @@ -1805,7 +1805,7 @@ mod tests { // Test various combinations of counts let file = create_test_file("/combo.rs"); let counts = vec![0, 1, 5, 10, 50, 100]; - + for &symbol_count in &counts { for &lsp_count in &counts { log_file_symbols(&file, symbol_count, lsp_count); From 2791d6148b22b6964e18ff0be7f1f3f6d84d03b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 6 Jan 2026 12:48:52 +0000 Subject: [PATCH 4/4] fix: Replace remaining vec! with array for clippy compliance Co-authored-by: jade-codes <9397730+jade-codes@users.noreply.github.com> --- crates/mother-cli/src/commands/scan/phase2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/mother-cli/src/commands/scan/phase2.rs b/crates/mother-cli/src/commands/scan/phase2.rs index 2e9d354..cc1261a 100644 --- a/crates/mother-cli/src/commands/scan/phase2.rs +++ b/crates/mother-cli/src/commands/scan/phase2.rs @@ -1804,7 +1804,7 @@ mod tests { fn test_log_file_symbols_all_count_combinations() { // Test various combinations of counts let file = create_test_file("/combo.rs"); - let counts = vec![0, 1, 5, 10, 50, 100]; + let counts = [0, 1, 5, 10, 50, 100]; for &symbol_count in &counts { for &lsp_count in &counts {