Skip to main content

bctx_forge/awareness/
test.rs

1use 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}