1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4#[derive(Clone, Debug, Eq, Hash, PartialEq)]
6pub struct TestCase {
7 pub name: String,
8 pub description: Option<String>,
9}
10
11impl TestCase {
12 pub fn new(name: impl Into<String>) -> Self {
13 Self {
14 name: name.into(),
15 description: None,
16 }
17 }
18
19 pub fn with_description(name: impl Into<String>, description: impl Into<String>) -> Self {
20 Self {
21 name: name.into(),
22 description: Some(description.into()),
23 }
24 }
25
26 pub fn name(&self) -> &str {
27 &self.name
28 }
29
30 pub fn description(&self) -> Option<&str> {
31 self.description.as_deref()
32 }
33}
34
35#[derive(Clone, Debug, Eq, Hash, PartialEq)]
37pub struct TestCaseData<I, O> {
38 pub name: String,
39 pub input: I,
40 pub expected: O,
41}
42
43impl<I, O> TestCaseData<I, O> {
44 pub fn new(name: impl Into<String>, input: I, expected: O) -> Self {
45 Self {
46 name: name.into(),
47 input,
48 expected,
49 }
50 }
51
52 pub fn name(&self) -> &str {
53 &self.name
54 }
55
56 pub const fn input(&self) -> &I {
57 &self.input
58 }
59
60 pub const fn expected(&self) -> &O {
61 &self.expected
62 }
63
64 pub fn into_parts(self) -> (String, I, O) {
65 (self.name, self.input, self.expected)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::{TestCase, TestCaseData};
72
73 #[test]
74 fn creates_named_case() {
75 let case = TestCase::new("basic");
76
77 assert_eq!(case.name(), "basic");
78 assert_eq!(case.description(), None);
79 }
80
81 #[test]
82 fn creates_described_case() {
83 let case = TestCase::with_description("trim", "removes whitespace");
84
85 assert_eq!(case.name(), "trim");
86 assert_eq!(case.description(), Some("removes whitespace"));
87 }
88
89 #[test]
90 fn stores_case_data() {
91 let data = TestCaseData::new("length", "abc", 3);
92
93 assert_eq!(data.name(), "length");
94 assert_eq!(data.input(), &"abc");
95 assert_eq!(data.expected(), &3);
96 assert_eq!(data.into_parts(), ("length".to_string(), "abc", 3));
97 }
98}