libtest2_harness/notify/
summary.rs

1use super::Event;
2use super::RunStatus;
3use super::FAILED;
4use super::OK;
5
6#[derive(Default, Clone, Debug)]
7pub(crate) struct Summary {
8    pub(crate) failures: std::collections::BTreeMap<String, Option<String>>,
9    pub(crate) elapsed_s: super::Elapsed,
10
11    pub(crate) num_run: usize,
12    /// Number of tests and benchmarks that were filtered out (either by the
13    /// filter-in pattern or by `--skip` arguments).
14    pub(crate) num_filtered_out: usize,
15
16    /// Number of passed tests.
17    pub(crate) num_passed: usize,
18    /// Number of failed tests and benchmarks.
19    pub(crate) num_failed: usize,
20    /// Number of ignored tests and benchmarks.
21    pub(crate) num_ignored: usize,
22}
23
24impl Summary {
25    pub(crate) fn has_failed(&self) -> bool {
26        0 < self.num_failed
27    }
28
29    pub(crate) fn write_start(&self, writer: &mut dyn std::io::Write) -> std::io::Result<()> {
30        let s = if self.num_run == 1 { "" } else { "s" };
31
32        writeln!(writer)?;
33        writeln!(writer, "running {} test{s}", self.num_run)?;
34        Ok(())
35    }
36
37    pub(crate) fn write_complete(&self, writer: &mut dyn ::std::io::Write) -> std::io::Result<()> {
38        let (summary, summary_style) = if self.has_failed() {
39            ("FAILED", FAILED)
40        } else {
41            ("ok", OK)
42        };
43        let num_passed = self.num_passed;
44        let num_failed = self.num_failed;
45        let num_ignored = self.num_ignored;
46        let num_filtered_out = self.num_filtered_out;
47        let elapsed_s = self.elapsed_s;
48
49        if self.has_failed() {
50            writeln!(writer)?;
51            writeln!(writer, "failures:")?;
52            writeln!(writer)?;
53
54            // Print messages of all tests
55            for (name, msg) in &self.failures {
56                if let Some(msg) = msg {
57                    writeln!(writer, "---- {name} ----")?;
58                    writeln!(writer, "{msg}")?;
59                    writeln!(writer)?;
60                }
61            }
62
63            // Print summary list of failed tests
64            writeln!(writer)?;
65            writeln!(writer, "failures:")?;
66            for name in self.failures.keys() {
67                writeln!(writer, "    {name}")?;
68            }
69        }
70        writeln!(writer)?;
71        writeln!(
72                    writer,
73                    "test result: {summary_style}{summary}{summary_style:#}. {num_passed} passed; {num_failed} failed; {num_ignored} ignored; \
74                        {num_filtered_out} filtered out; finished in {elapsed_s}",
75                )?;
76        writeln!(writer)?;
77
78        Ok(())
79    }
80}
81
82impl super::Notifier for Summary {
83    fn notify(&mut self, event: Event) -> std::io::Result<()> {
84        match event {
85            Event::DiscoverStart => {}
86            Event::DiscoverCase { run, .. } => {
87                if run {
88                    self.num_run += 1;
89                } else {
90                    self.num_filtered_out += 1;
91                }
92            }
93            Event::DiscoverComplete { .. } => {}
94            Event::SuiteStart => {}
95            Event::CaseStart { .. } => {}
96            Event::CaseComplete {
97                name,
98                status,
99                message,
100                ..
101            } => match status {
102                Some(RunStatus::Ignored) => {
103                    self.num_ignored += 1;
104                }
105                Some(RunStatus::Failed) => {
106                    self.num_failed += 1;
107                    self.failures.insert(name, message);
108                }
109                None => {
110                    self.num_passed += 1;
111                }
112            },
113            Event::SuiteComplete { elapsed_s, .. } => {
114                self.elapsed_s = elapsed_s;
115            }
116        }
117        Ok(())
118    }
119}