bctx_forge/awareness/
test.rs1use super::{AwarenessMap, EcosystemAwareness};
2use once_cell::sync::Lazy;
3use regex::Regex;
4
5static RUST_RESULT_RE: Lazy<Regex> = Lazy::new(|| {
6 Regex::new(r"test result: (\w+)\. (\d+) passed; (\d+) failed; (\d+) ignored").unwrap()
7});
8static RUST_FAIL_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"^FAILED\s+(.+)$").unwrap());
9static PYTEST_RE: Lazy<Regex> =
10 Lazy::new(|| Regex::new(r"(\d+) passed(?:, (\d+) failed)?(?:, (\d+) error)?").unwrap());
11
12pub struct TestAwareness;
13
14impl EcosystemAwareness for TestAwareness {
15 fn matches(&self, program: &str, args: &[String]) -> bool {
16 let prog = program.split('/').next_back().unwrap_or(program);
17 let sub = args.first().map(|s| s.as_str()).unwrap_or("");
18 matches!(prog, "pytest" | "jest" | "vitest" | "rspec" | "mocha")
19 || (prog == "cargo" && sub == "test")
20 || (prog == "go" && sub == "test")
21 || (prog == "npm" && args.get(1).map(|s| s.as_str()) == Some("test"))
22 }
23
24 fn extract(&self, stdout: &str, stderr: &str, exit_code: i32) -> AwarenessMap {
25 let mut map = AwarenessMap::new("test", "run");
26 map.insert("exit_code", exit_code.to_string());
27
28 let combined = format!("{stdout}\n{stderr}");
29
30 if let Some(cap) = RUST_RESULT_RE.captures(&combined) {
31 map.insert("status", cap[1].to_string());
32 map.insert("passed", cap[2].to_string());
33 map.insert("failed", cap[3].to_string());
34 map.insert("ignored", cap[4].to_string());
35 } else if let Some(cap) = PYTEST_RE.captures(&combined) {
36 map.insert("passed", cap[1].to_string());
37 if let Some(f) = cap.get(2) {
38 map.insert("failed", f.as_str().to_string());
39 }
40 }
41
42 let failures: Vec<&str> = RUST_FAIL_RE
43 .captures_iter(&combined)
44 .filter_map(|c| c.get(1).map(|m| m.as_str()))
45 .collect();
46 if !failures.is_empty() {
47 map.insert("failed_tests", failures.join(", "));
48 }
49
50 map
51 }
52}