1747ad3c4Slazypassion //! Test commands.
2747ad3c4Slazypassion //!
3747ad3c4Slazypassion //! A `.clif` file can begin with one or more *test commands* which specify what is to be tested.
4747ad3c4Slazypassion //! The general syntax is:
5747ad3c4Slazypassion //!
6747ad3c4Slazypassion //! <pre>
7d38d387aSAlex Crichton //! test <i>&lt;command&gt;</i> <i>[options]</i>...
8747ad3c4Slazypassion //! </pre>
9747ad3c4Slazypassion //!
10747ad3c4Slazypassion //! The options are either a single identifier flag, or setting values like `identifier=value`.
11747ad3c4Slazypassion //!
12747ad3c4Slazypassion //! The parser does not understand the test commands or which options are valid. It simply parses
13747ad3c4Slazypassion //! the general format into a `TestCommand` data structure.
14747ad3c4Slazypassion 
15747ad3c4Slazypassion use std::fmt::{self, Display, Formatter};
16747ad3c4Slazypassion 
17747ad3c4Slazypassion /// A command appearing in a test file.
18747ad3c4Slazypassion #[derive(Clone, PartialEq, Eq, Debug)]
19747ad3c4Slazypassion pub struct TestCommand<'a> {
20747ad3c4Slazypassion     /// The command name as a string.
21747ad3c4Slazypassion     pub command: &'a str,
22747ad3c4Slazypassion     /// The options following the command name.
23747ad3c4Slazypassion     pub options: Vec<TestOption<'a>>,
24747ad3c4Slazypassion }
25747ad3c4Slazypassion 
26747ad3c4Slazypassion /// An option on a test command.
27747ad3c4Slazypassion #[derive(Clone, PartialEq, Eq, Debug)]
28747ad3c4Slazypassion pub enum TestOption<'a> {
29747ad3c4Slazypassion     /// Single identifier flag: `foo`.
30747ad3c4Slazypassion     Flag(&'a str),
31747ad3c4Slazypassion     /// A value assigned to an identifier: `foo=bar`.
32747ad3c4Slazypassion     Value(&'a str, &'a str),
33747ad3c4Slazypassion }
34747ad3c4Slazypassion 
35747ad3c4Slazypassion impl<'a> TestCommand<'a> {
36747ad3c4Slazypassion     /// Create a new TestCommand by parsing `s`.
37747ad3c4Slazypassion     /// The returned command contains references into `s`.
new(s: &'a str) -> Self38747ad3c4Slazypassion     pub fn new(s: &'a str) -> Self {
39747ad3c4Slazypassion         let mut parts = s.split_whitespace();
40747ad3c4Slazypassion         let cmd = parts.next().unwrap_or("");
41747ad3c4Slazypassion         Self {
42747ad3c4Slazypassion             command: cmd,
43747ad3c4Slazypassion             options: parts
44747ad3c4Slazypassion                 .filter(|s| !s.is_empty())
45747ad3c4Slazypassion                 .map(TestOption::new)
46747ad3c4Slazypassion                 .collect(),
47747ad3c4Slazypassion         }
48747ad3c4Slazypassion     }
49747ad3c4Slazypassion }
50747ad3c4Slazypassion 
51747ad3c4Slazypassion impl<'a> Display for TestCommand<'a> {
fmt(&self, f: &mut Formatter) -> fmt::Result52747ad3c4Slazypassion     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
53747ad3c4Slazypassion         write!(f, "{}", self.command)?;
54747ad3c4Slazypassion         for opt in &self.options {
55*a0442ea0SHamir Mahal             write!(f, " {opt}")?;
56747ad3c4Slazypassion         }
57747ad3c4Slazypassion         writeln!(f)
58747ad3c4Slazypassion     }
59747ad3c4Slazypassion }
60747ad3c4Slazypassion 
61747ad3c4Slazypassion impl<'a> TestOption<'a> {
62747ad3c4Slazypassion     /// Create a new TestOption by parsing `s`.
63747ad3c4Slazypassion     /// The returned option contains references into `s`.
new(s: &'a str) -> Self64747ad3c4Slazypassion     pub fn new(s: &'a str) -> Self {
65747ad3c4Slazypassion         match s.find('=') {
66747ad3c4Slazypassion             None => TestOption::Flag(s),
67747ad3c4Slazypassion             Some(p) => TestOption::Value(&s[0..p], &s[p + 1..]),
68747ad3c4Slazypassion         }
69747ad3c4Slazypassion     }
70747ad3c4Slazypassion }
71747ad3c4Slazypassion 
72747ad3c4Slazypassion impl<'a> Display for TestOption<'a> {
fmt(&self, f: &mut Formatter) -> fmt::Result73747ad3c4Slazypassion     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
74747ad3c4Slazypassion         match *self {
75*a0442ea0SHamir Mahal             TestOption::Flag(s) => write!(f, "{s}"),
76*a0442ea0SHamir Mahal             TestOption::Value(s, v) => write!(f, "{s}={v}"),
77747ad3c4Slazypassion         }
78747ad3c4Slazypassion     }
79747ad3c4Slazypassion }
80747ad3c4Slazypassion 
81747ad3c4Slazypassion #[cfg(test)]
82747ad3c4Slazypassion mod tests {
83747ad3c4Slazypassion     use super::*;
84747ad3c4Slazypassion 
85747ad3c4Slazypassion     #[test]
parse_option()86747ad3c4Slazypassion     fn parse_option() {
87747ad3c4Slazypassion         assert_eq!(TestOption::new(""), TestOption::Flag(""));
88747ad3c4Slazypassion         assert_eq!(TestOption::new("foo"), TestOption::Flag("foo"));
89747ad3c4Slazypassion         assert_eq!(TestOption::new("foo=bar"), TestOption::Value("foo", "bar"));
90747ad3c4Slazypassion     }
91747ad3c4Slazypassion 
92747ad3c4Slazypassion     #[test]
parse_command()93747ad3c4Slazypassion     fn parse_command() {
94747ad3c4Slazypassion         assert_eq!(&TestCommand::new("").to_string(), "\n");
95747ad3c4Slazypassion         assert_eq!(&TestCommand::new("cat").to_string(), "cat\n");
96747ad3c4Slazypassion         assert_eq!(&TestCommand::new("cat  ").to_string(), "cat\n");
97747ad3c4Slazypassion         assert_eq!(&TestCommand::new("cat  1  ").to_string(), "cat 1\n");
98747ad3c4Slazypassion         assert_eq!(
99747ad3c4Slazypassion             &TestCommand::new("cat  one=4   two t").to_string(),
100747ad3c4Slazypassion             "cat one=4 two t\n"
101747ad3c4Slazypassion         );
102747ad3c4Slazypassion     }
103747ad3c4Slazypassion }
104