ctrf_rs/
summary.rs

1use crate::{extra::Extra, impl_extra};
2
3use std::{
4    collections::HashMap,
5    time::{SystemTime, UNIX_EPOCH},
6};
7
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10
11/// Result summary element for a CTRF report.
12/// Corresponds to the spec's ["Summary"](https://ctrf.io/docs/specification/summary) object.
13#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
14#[serde(rename_all = "camelCase")]
15pub struct Summary {
16    tests: usize,
17    passed: usize,
18    failed: usize,
19    pending: usize,
20    skipped: usize,
21    other: usize,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    suites: Option<usize>,
24    start: u64,
25    stop: u64,
26    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
27    extra: HashMap<String, Value>,
28}
29
30impl Summary {
31    /// Creates a report Summary instance
32    pub fn new(start: SystemTime, stop: SystemTime) -> Self {
33        Self {
34            tests: 0,
35            passed: 0,
36            failed: 0,
37            pending: 0,
38            skipped: 0,
39            other: 0,
40            suites: None,
41            start: start.duration_since(UNIX_EPOCH).unwrap().as_millis() as u64,
42            stop: stop.duration_since(UNIX_EPOCH).unwrap().as_millis() as u64,
43            extra: HashMap::new(),
44        }
45    }
46
47    /// Sets the count of passed tests and updates the overall total
48    pub fn passed(&mut self, count: usize) {
49        self.passed = count;
50
51        self.update_tests();
52    }
53
54    /// Sets the count of failed tests and updates the overall total
55    pub fn failed(&mut self, count: usize) {
56        self.failed = count;
57
58        self.update_tests();
59    }
60
61    /// Sets the count of pending tests and updates the overall total
62    pub fn pending(&mut self, count: usize) {
63        self.pending = count;
64
65        self.update_tests();
66    }
67
68    /// Sets the count of skipped tests and updates the overall total
69    pub fn skipped(&mut self, count: usize) {
70        self.skipped = count;
71
72        self.update_tests();
73    }
74
75    /// Sets the count of other tests and updates the overall total
76    pub fn other(&mut self, count: usize) {
77        self.other = count;
78
79        self.update_tests();
80    }
81
82    /// Sets the number of Suites, can be None
83    pub fn suites(&mut self, suites: Option<usize>) {
84        self.suites = suites;
85    }
86
87    /// Updates the total test count
88    fn update_tests(&mut self) {
89        self.tests = self.passed + self.failed + self.pending + self.skipped + self.other;
90    }
91}
92
93impl_extra!(Summary);
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    use std::time::SystemTime;
100
101    #[test]
102    fn add_passed() {
103        const PASSED_COUNT: usize = 5;
104        let time = SystemTime::now();
105        let mut summary = Summary::new(time, time);
106
107        summary.passed(PASSED_COUNT);
108
109        assert_eq!(summary.passed, PASSED_COUNT);
110        assert_eq!(summary.tests, PASSED_COUNT);
111    }
112
113    #[test]
114    fn add_failed() {
115        const FAILED_COUNT: usize = 20;
116        let time = SystemTime::now();
117        let mut summary = Summary::new(time, time);
118
119        summary.passed(FAILED_COUNT);
120
121        assert_eq!(summary.passed, FAILED_COUNT);
122        assert_eq!(summary.tests, FAILED_COUNT);
123    }
124
125    #[test]
126    fn add_pending() {
127        const PENDING_COUNT: usize = 10;
128        let time = SystemTime::now();
129        let mut summary = Summary::new(time, time);
130
131        summary.passed(PENDING_COUNT);
132
133        assert_eq!(summary.passed, PENDING_COUNT);
134        assert_eq!(summary.tests, PENDING_COUNT);
135    }
136
137    #[test]
138    fn add_skipped() {
139        const SKIPPED_COUNT: usize = 2;
140        let time = SystemTime::now();
141        let mut summary = Summary::new(time, time);
142
143        summary.passed(SKIPPED_COUNT);
144
145        assert_eq!(summary.passed, SKIPPED_COUNT);
146        assert_eq!(summary.tests, SKIPPED_COUNT);
147    }
148
149    #[test]
150    fn add_other() {
151        const OTHER_COUNT: usize = 50;
152        let time = SystemTime::now();
153        let mut summary = Summary::new(time, time);
154
155        summary.passed(OTHER_COUNT);
156
157        assert_eq!(summary.passed, OTHER_COUNT);
158        assert_eq!(summary.tests, OTHER_COUNT);
159    }
160
161    #[test]
162    fn add_all_types() {
163        const PASSED_COUNT: usize = 5;
164        const FAILED_COUNT: usize = 40;
165        const PENDING_COUNT: usize = 300;
166        const SKIPPED_COUNT: usize = 2000;
167        const OTHER_COUNT: usize = 10000;
168        let time = SystemTime::now();
169        let mut summary = Summary::new(time, time);
170
171        summary.passed(PASSED_COUNT);
172        summary.failed(FAILED_COUNT);
173        summary.skipped(SKIPPED_COUNT);
174        summary.pending(PENDING_COUNT);
175        summary.other(OTHER_COUNT);
176
177        assert_eq!(summary.passed, PASSED_COUNT);
178        assert_eq!(summary.failed, FAILED_COUNT);
179        assert_eq!(summary.skipped, SKIPPED_COUNT);
180        assert_eq!(summary.pending, PENDING_COUNT);
181        assert_eq!(summary.other, OTHER_COUNT);
182        assert_eq!(
183            summary.tests,
184            PASSED_COUNT + FAILED_COUNT + PENDING_COUNT + SKIPPED_COUNT + OTHER_COUNT,
185        );
186    }
187
188    #[test]
189    fn revise_value() {
190        const PASSED_COUNT: usize = 5;
191        const FAILED_COUNT: usize = 40;
192        const PENDING_COUNT: usize = 300;
193        const SKIPPED_COUNT: usize = 2000;
194        const OTHER_COUNT: usize = 10000;
195        let time = SystemTime::now();
196        let mut summary = Summary::new(time, time);
197
198        summary.passed(PASSED_COUNT);
199        summary.failed(FAILED_COUNT);
200        summary.skipped(SKIPPED_COUNT);
201        summary.pending(PENDING_COUNT);
202        summary.other(OTHER_COUNT);
203
204        assert_eq!(summary.passed, PASSED_COUNT);
205        assert_eq!(summary.failed, FAILED_COUNT);
206        assert_eq!(summary.skipped, SKIPPED_COUNT);
207        assert_eq!(summary.pending, PENDING_COUNT);
208        assert_eq!(summary.other, OTHER_COUNT);
209        assert_eq!(
210            summary.tests,
211            PASSED_COUNT + FAILED_COUNT + PENDING_COUNT + SKIPPED_COUNT + OTHER_COUNT,
212        );
213
214        const NEW_PASSED: usize = 24681;
215        summary.passed(NEW_PASSED);
216
217        assert_eq!(summary.passed, NEW_PASSED);
218        assert_eq!(summary.failed, FAILED_COUNT);
219        assert_eq!(summary.skipped, SKIPPED_COUNT);
220        assert_eq!(summary.pending, PENDING_COUNT);
221        assert_eq!(summary.other, OTHER_COUNT);
222        assert_eq!(
223            summary.tests,
224            NEW_PASSED + FAILED_COUNT + PENDING_COUNT + SKIPPED_COUNT + OTHER_COUNT,
225        );
226    }
227
228    #[test]
229    fn add_suites() {
230        const SUITES: Option<usize> = Some(16);
231        let time = SystemTime::now();
232        let mut summary = Summary::new(time, time);
233
234        summary.suites(SUITES);
235
236        assert_eq!(summary.suites, SUITES)
237    }
238}