smb_server_test_dashboard/
json.rs1use crate::csv::{Summary, TestRow};
4use std::collections::BTreeMap;
5
6pub fn status_body(rows: &[TestRow], summary: &Summary) -> String {
8 format!(
9 "{{\"total\":{},\"passed\":{},\"failed\":{},\"skipped\":{},\"unknown\":{},\
10 \"suites\":[{}],\"categories\":[{}]}}",
11 summary.total,
12 summary.passed,
13 summary.failed,
14 summary.skipped,
15 summary.unknown,
16 breakdown(rows, |r| &r.suite, "suite"),
17 breakdown(rows, |r| &r.category, "category"),
18 )
19}
20
21#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] fn breakdown(rows: &[TestRow], key: impl Fn(&TestRow) -> &str, label: &str) -> String {
24 let mut groups: BTreeMap<&str, [usize; 4]> = BTreeMap::new();
25 for row in rows {
26 let slot = groups.entry(key(row)).or_insert([0, 0, 0, 0]);
27 match row.status.as_str() {
28 "pass" => slot[0] += 1,
29 "fail" => slot[1] += 1,
30 "skip" => slot[2] += 1,
31 _ => slot[3] += 1,
32 }
33 }
34 let items: Vec<String> = groups
35 .iter()
36 .map(|(name, [p, f, s, u])| {
37 format!(
38 "{{\"{label}\":{},\"passed\":{p},\"failed\":{f},\"skipped\":{s},\
39 \"unknown\":{u},\"total\":{}}}",
40 quote(name),
41 p + f + s + u
42 )
43 })
44 .collect();
45 items.join(",")
46}
47
48pub fn tests_body(rows: &[TestRow]) -> String {
50 let items: Vec<String> = rows.iter().map(row_to_json).collect();
51 format!("[{}]", items.join(","))
52}
53
54fn row_to_json(row: &TestRow) -> String {
55 format!(
56 "{{\"suite\":{},\"name\":{},\"category\":{},\"status\":{},\
57 \"duration_ms\":{},\"timestamp\":{},\"commit\":{},\"note\":{}}}",
58 quote(&row.suite),
59 quote(&row.name),
60 quote(&row.category),
61 quote(&row.status),
62 row.duration_ms,
63 quote(&row.timestamp),
64 quote(&row.commit),
65 quote(&row.note)
66 )
67}
68
69#[cfg_attr(dylint_lib = "no_magic_numbers", allow(no_magic_numbers))] fn quote(s: &str) -> String {
72 let mut out = String::with_capacity(s.len() + 2);
73 out.push('"');
74 for c in s.chars() {
75 match c {
76 '"' => out.push_str("\\\""),
77 '\\' => out.push_str("\\\\"),
78 '\n' => out.push_str("\\n"),
79 '\r' => out.push_str("\\r"),
80 '\t' => out.push_str("\\t"),
81 c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
82 c => out.push(c),
83 }
84 }
85 out.push('"');
86 out
87}