use std::fs; use std::path::PathBuf; use serde_json::Value; fn read_json_lines(path: &str) -> Vec { let p = PathBuf::from(path); if !p.exists() { return vec![]; } let content = fs::read_to_string(p).unwrap_or_default(); content .lines() .filter_map(|l| serde_json::from_str::(l).ok()) .collect() } fn summarize(items: Vec) -> (usize, usize, f64, Vec<(String, f64)>) { let mut total = 0usize; let mut failed = 0usize; let mut duration = 0f64; let mut tests = Vec::new(); for v in items { let t = v.get("type").and_then(|x| x.as_str()).unwrap_or(""); if t == "test" { let name = v.get("name").and_then(|x| x.as_str()).unwrap_or("").to_string(); let event = v.get("event").and_then(|x| x.as_str()).unwrap_or(""); let time = v.get("exec_time").and_then(|x| x.as_f64()).unwrap_or(0.0); total += 1; if event == "failed" { failed += 1; } duration += time; tests.push((name, time)); } } tests.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap()); (total, failed, duration, tests) } fn main() { let out_dir = PathBuf::from("target/test-reports"); let _ = fs::create_dir_all(&out_dir); let default = read_json_lines("target/test-report-default.json"); let js = read_json_lines("target/test-report-js.json"); let (t1, f1, d1, s1) = summarize(default); let (t2, f2, d2, s2) = summarize(js); let mut md = String::new(); md.push_str("# dsl-flow Test Report\n"); md.push_str("\n"); md.push_str("## Default features\n"); md.push_str(&format!("- total: {}\n- failed: {}\n- duration: {:.3}s\n", t1, f1, d1)); md.push_str("- top slow tests:\n"); for (name, time) in s1.iter().take(5) { md.push_str(&format!(" - {}: {:.3}s\n", name, time)); } md.push_str("\n"); md.push_str("## JS feature\n"); md.push_str(&format!("- total: {}\n- failed: {}\n- duration: {:.3}s\n", t2, f2, d2)); md.push_str("- top slow tests:\n"); for (name, time) in s2.iter().take(5) { md.push_str(&format!(" - {}: {:.3}s\n", name, time)); } let out_path = out_dir.join("summary.md"); let _ = fs::write(out_path, md); println!("report generated in target/test-reports/summary.md"); }