Skip to main content

serial_unit_testing/tests/
test_suite.rs

1/*
2 * File: tests/test_suite.rs
3 * Date: 03.10.2018
4 * Author: MarkAtk
5 * 
6 * MIT License
7 * 
8 * Copyright (c) 2018 MarkAtk
9 * 
10 * Permission is hereby granted, free of charge, to any person obtaining a copy of
11 * this software and associated documentation files (the "Software"), to deal in
12 * the Software without restriction, including without limitation the rights to
13 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
14 * of the Software, and to permit persons to whom the Software is furnished to do
15 * so, subject to the following conditions:
16 * 
17 * The above copyright notice and this permission notice shall be included in all
18 * copies or substantial portions of the Software.
19 * 
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29use crate::serial::Serial;
30
31pub use crate::tests::test_case::{TestCase, TestCaseSettings};
32
33/// Settings for running a test suite.
34#[derive(Debug, Clone)]
35pub struct TestSuiteSettings {
36    /// If set the test suite will stop on first test failing.
37    pub stop_on_failure: bool,
38    /// If set the test suites will not be run.
39    pub disabled: bool
40}
41
42impl Default for TestSuiteSettings {
43    fn default() -> TestSuiteSettings {
44        TestSuiteSettings {
45            stop_on_failure: false,
46            disabled: false
47        }
48    }
49}
50
51/// Test suite representing a group of tests.
52#[derive(Debug)]
53pub struct TestSuite {
54    /// Name of the test group.
55    pub name: String,
56    /// Settings to use for the test suite.
57    pub settings: TestSuiteSettings,
58    /// Test settings to use for all tests.
59    pub test_settings: TestCaseSettings,
60    tests: Vec<TestCase>
61}
62
63impl TestSuite {
64    /// Create a new test suite.
65    pub fn new(name: String) -> TestSuite {
66        TestSuite {
67            name,
68            settings: Default::default(),
69            test_settings: Default::default(),
70            tests: Vec::new()
71        }
72    }
73
74    /// Create a new test suite with given suite and test settings.
75    pub fn new_with_settings(name: String, settings: TestSuiteSettings, test_settings: TestCaseSettings) -> TestSuite {
76        TestSuite {
77            name,
78            settings,
79            test_settings,
80            tests: Vec::new()
81        }
82    }
83
84    /// Add a test to the suite.
85    ///
86    /// Tests added to the suite will be run when the suite is executed.
87    pub fn push(&mut self, test: TestCase) {
88        self.tests.push(test);
89
90        if let Some(pushed_test) = self.tests.last_mut() {
91            pushed_test.settings.merge_weak(&self.test_settings);
92        }
93    }
94
95    /// Run all tests belonging to the test suite on given serial port.
96    ///
97    /// Execution will stop early if stop_on_failure is set and a test fails.
98    pub fn run(&mut self, serial: &mut Serial) -> Result<bool, String> {
99        if self.settings.disabled {
100            return Ok(true);
101        }
102
103        for test in self.tests.iter_mut() {
104            let result = test.run(serial)?;
105
106            if self.settings.stop_on_failure && result == false {
107                return Ok(false);
108            }
109        }
110
111        Ok(true)
112    }
113
114    /// Run all tests belonging to the test suite on given serial port and print the results.
115    ///
116    /// Execution will stop early if stop_on_failure is set and a test fails.
117    pub fn run_and_print(&mut self, serial: &mut Serial, quiet: bool) -> bool {
118        let show_title = self.name != "";
119
120        if show_title && quiet == false {
121            println!("{}", self.title());
122        }
123
124        if self.settings.disabled {
125            return true;
126        }
127
128        for test in self.tests.iter_mut() {
129            if show_title && quiet == false {
130                print!("\t");
131            }
132
133            let result = match test.run(serial) {
134                Ok(success) => success,
135                Err(_) => false
136            };
137
138            if quiet == false || result == false {
139                println!("{}", test.to_string());
140            }
141
142            if result != true && self.settings.stop_on_failure {
143                return false;
144            }
145        }
146
147        true
148    }
149
150    /// Get the number of tests belonging to the test suite.
151    pub fn len(&self) -> usize {
152        self.tests.len()
153    }
154
155    /// Check if any test belongs to the test suite.
156    pub fn is_empty(&self) -> bool {
157        self.tests.is_empty()
158    }
159
160    /// Get the number of failed tests.
161    ///
162    /// Will return 0 if not run before.
163    pub fn failed(&self) -> usize {
164        self.count_tests(false)
165    }
166
167    /// Get the number of successful tests.
168    ///
169    /// Will return 0 if not run before.
170    pub fn successful(&self) -> usize {
171        self.count_tests(true)
172    }
173
174    fn count_tests(&self, success: bool) -> usize {
175        let mut count = 0;
176
177        for test in &self.tests {
178            if test.is_successful().is_none() && test.error().is_none() {
179                continue;
180            }
181
182            if (test.is_successful().unwrap_or(false) || test.settings.allow_failure.unwrap_or(false)) == success {
183                count += 1;
184            }
185        }
186
187        count
188    }
189
190    fn title(&self) -> String {
191        if self.settings.disabled {
192            format!("{}: Disabled", self.name)
193        } else {
194            format!("{}:", self.name)
195        }
196    }
197}
198
199impl ToString for TestSuite {
200    fn to_string(&self) -> String {
201        let mut result = String::new();
202
203        let show_group = self.name != "";
204
205        if show_group {
206            result.push_str(format!("{}\n", self.title()).as_str());
207        }
208
209        for test in &self.tests {
210            if show_group {
211                result.push('\t');
212            }
213
214            result.push_str(format!("{}\n", test.to_string()).as_str());
215        }
216
217        result
218    }
219}