From 98118fdc581538deee46af01383d92828eed0ae3 Mon Sep 17 00:00:00 2001 From: DevNewbie1826 Date: Fri, 13 Mar 2026 21:58:13 +0900 Subject: [PATCH] fix: handle benchmark-only go test output --- src/go_cmd.rs | 107 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/src/go_cmd.rs b/src/go_cmd.rs index 42ff0cd9..54a62512 100644 --- a/src/go_cmd.rs +++ b/src/go_cmd.rs @@ -34,6 +34,7 @@ struct PackageResult { skip: usize, build_failed: bool, build_errors: Vec, + benchmark_outputs: Vec, failed_tests: Vec<(String, Vec)>, // (test_name, output_lines) } @@ -321,13 +322,21 @@ fn filter_go_test_json(output: &str) -> String { } } "output" => { - // Collect output for current test - if let (Some(test), Some(output_text)) = (&event.test, &event.output) { + if let Some(output_text) = &event.output { + let trimmed = output_text.trim_end(); + + if is_benchmark_result_line(trimmed) { + pkg_result.benchmark_outputs.push(trimmed.to_string()); + } + + // Collect output for current test + if let Some(test) = &event.test { let key = (package.clone(), test.clone()); current_test_output .entry(key) .or_default() - .push(output_text.trim_end().to_string()); + .push(trimmed.to_string()); + } } } _ => {} // run, pause, cont, etc. @@ -340,14 +349,22 @@ fn filter_go_test_json(output: &str) -> String { let total_fail: usize = packages.values().map(|p| p.fail).sum(); let total_skip: usize = packages.values().map(|p| p.skip).sum(); let total_build_fail: usize = packages.values().filter(|p| p.build_failed).count(); + let total_benchmark_packages: usize = packages + .values() + .filter(|p| !p.benchmark_outputs.is_empty()) + .count(); let has_failures = total_fail > 0 || total_build_fail > 0; - if !has_failures && total_pass == 0 { + if !has_failures && total_pass == 0 && total_benchmark_packages == 0 { return "Go test: No tests found".to_string(); } if !has_failures { + if total_benchmark_packages > 0 { + return format_go_test_success_with_benchmarks(&packages, total_pass, total_packages); + } + return format!( "✓ Go test: {} passed in {} packages", total_pass, total_packages @@ -428,6 +445,54 @@ fn filter_go_test_json(output: &str) -> String { result.trim().to_string() } +fn is_benchmark_result_line(line: &str) -> bool { + let trimmed = line.trim(); + + trimmed.starts_with("Benchmark") + && (trimmed.contains("ns/op") + || trimmed.contains("B/op") + || trimmed.contains("allocs/op") + || trimmed.contains("MB/s")) +} + +fn format_go_test_success_with_benchmarks( + packages: &HashMap, + total_pass: usize, + total_packages: usize, +) -> String { + let benchmark_packages: Vec<_> = packages + .iter() + .filter(|(_, pkg_result)| !pkg_result.benchmark_outputs.is_empty()) + .collect(); + + let mut result = if total_pass > 0 { + format!( + "✓ Go test: {} passed in {} packages", + total_pass, total_packages + ) + } else { + format!( + "✓ Go test: benchmark results in {} packages", + benchmark_packages.len() + ) + }; + + result.push_str("\n═══════════════════════════════════════"); + + for (package, pkg_result) in benchmark_packages { + result.push_str(&format!( + "\n\n📦 {} [benchmarks]", + compact_package_name(package) + )); + + for line in &pkg_result.benchmark_outputs { + result.push_str(&format!("\n {}", truncate(line, 120))); + } + } + + result +} + /// Filter go build output - show only errors fn filter_go_build(output: &str) -> String { let mut errors: Vec = Vec::new(); @@ -544,6 +609,40 @@ mod tests { assert!(result.contains("expected 5, got 3")); } + #[test] + fn test_filter_go_test_benchmark_only() { + let output = r#"{"Time":"2024-01-01T10:00:00Z","Action":"start","Package":"example.com/foo"} +{"Time":"2024-01-01T10:00:01Z","Action":"output","Package":"example.com/foo","Output":"goos: linux\n"} +{"Time":"2024-01-01T10:00:01Z","Action":"output","Package":"example.com/foo","Output":"goarch: amd64\n"} +{"Time":"2024-01-01T10:00:01Z","Action":"run","Package":"example.com/foo","Test":"BenchmarkFib10"} +{"Time":"2024-01-01T10:00:01Z","Action":"output","Package":"example.com/foo","Test":"BenchmarkFib10","Output":"=== RUN BenchmarkFib10\n"} +{"Time":"2024-01-01T10:00:01Z","Action":"output","Package":"example.com/foo","Test":"BenchmarkFib10","Output":"BenchmarkFib10\n"} +{"Time":"2024-01-01T10:00:02Z","Action":"output","Package":"example.com/foo","Test":"BenchmarkFib10","Output":"BenchmarkFib10-6 \t 1922632\t 602.9 ns/op\n"} +{"Time":"2024-01-01T10:00:02Z","Action":"output","Package":"example.com/foo","Output":"PASS\n"} +{"Time":"2024-01-01T10:00:02Z","Action":"output","Package":"example.com/foo","Output":"ok \texample.com/foo\t1.619s\n"} +{"Time":"2024-01-01T10:00:02Z","Action":"pass","Package":"example.com/foo","Elapsed":1.619}"#; + + let result = filter_go_test_json(output); + assert!(!result.contains("No tests found")); + assert!(result.contains("BenchmarkFib10-6")); + assert!(result.contains("602.9 ns/op")); + } + + #[test] + fn test_filter_go_test_benchmark_only_package_level_output() { + let output = r#"{"Time":"2024-01-01T10:00:00Z","Action":"start","Package":"example.com/foo"} +{"Time":"2024-01-01T10:00:01Z","Action":"output","Package":"example.com/foo","Output":"goos: linux\n"} +{"Time":"2024-01-01T10:00:01Z","Action":"run","Package":"example.com/foo","Test":"BenchmarkFib10"} +{"Time":"2024-01-01T10:00:01Z","Action":"output","Package":"example.com/foo","Output":"BenchmarkFib10-6 \t 1922632\t 602.9 ns/op\n"} +{"Time":"2024-01-01T10:00:02Z","Action":"output","Package":"example.com/foo","Output":"PASS\n"} +{"Time":"2024-01-01T10:00:02Z","Action":"pass","Package":"example.com/foo","Elapsed":1.619}"#; + + let result = filter_go_test_json(output); + assert!(!result.contains("No tests found")); + assert!(result.contains("BenchmarkFib10-6")); + assert!(result.contains("602.9 ns/op")); + } + #[test] fn test_filter_go_build_success() { let output = "";