1 //! Test commands. 2 //! 3 //! A `.clif` file can begin with one or more *test commands* which specify what is to be tested. 4 //! The general syntax is: 5 //! 6 //! <pre> 7 //! test <i><command></i> <i>[options]</i>... 8 //! </pre> 9 //! 10 //! The options are either a single identifier flag, or setting values like `identifier=value`. 11 //! 12 //! The parser does not understand the test commands or which options are valid. It simply parses 13 //! the general format into a `TestCommand` data structure. 14 15 use std::fmt::{self, Display, Formatter}; 16 17 /// A command appearing in a test file. 18 #[derive(Clone, PartialEq, Eq, Debug)] 19 pub struct TestCommand<'a> { 20 /// The command name as a string. 21 pub command: &'a str, 22 /// The options following the command name. 23 pub options: Vec<TestOption<'a>>, 24 } 25 26 /// An option on a test command. 27 #[derive(Clone, PartialEq, Eq, Debug)] 28 pub enum TestOption<'a> { 29 /// Single identifier flag: `foo`. 30 Flag(&'a str), 31 /// A value assigned to an identifier: `foo=bar`. 32 Value(&'a str, &'a str), 33 } 34 35 impl<'a> TestCommand<'a> { 36 /// Create a new TestCommand by parsing `s`. 37 /// The returned command contains references into `s`. 38 pub fn new(s: &'a str) -> Self { 39 let mut parts = s.split_whitespace(); 40 let cmd = parts.next().unwrap_or(""); 41 Self { 42 command: cmd, 43 options: parts 44 .filter(|s| !s.is_empty()) 45 .map(TestOption::new) 46 .collect(), 47 } 48 } 49 } 50 51 impl<'a> Display for TestCommand<'a> { 52 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 53 write!(f, "{}", self.command)?; 54 for opt in &self.options { 55 write!(f, " {opt}")?; 56 } 57 writeln!(f) 58 } 59 } 60 61 impl<'a> TestOption<'a> { 62 /// Create a new TestOption by parsing `s`. 63 /// The returned option contains references into `s`. 64 pub fn new(s: &'a str) -> Self { 65 match s.find('=') { 66 None => TestOption::Flag(s), 67 Some(p) => TestOption::Value(&s[0..p], &s[p + 1..]), 68 } 69 } 70 } 71 72 impl<'a> Display for TestOption<'a> { 73 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 74 match *self { 75 TestOption::Flag(s) => write!(f, "{s}"), 76 TestOption::Value(s, v) => write!(f, "{s}={v}"), 77 } 78 } 79 } 80 81 #[cfg(test)] 82 mod tests { 83 use super::*; 84 85 #[test] 86 fn parse_option() { 87 assert_eq!(TestOption::new(""), TestOption::Flag("")); 88 assert_eq!(TestOption::new("foo"), TestOption::Flag("foo")); 89 assert_eq!(TestOption::new("foo=bar"), TestOption::Value("foo", "bar")); 90 } 91 92 #[test] 93 fn parse_command() { 94 assert_eq!(&TestCommand::new("").to_string(), "\n"); 95 assert_eq!(&TestCommand::new("cat").to_string(), "cat\n"); 96 assert_eq!(&TestCommand::new("cat ").to_string(), "cat\n"); 97 assert_eq!(&TestCommand::new("cat 1 ").to_string(), "cat 1\n"); 98 assert_eq!( 99 &TestCommand::new("cat one=4 two t").to_string(), 100 "cat one=4 two t\n" 101 ); 102 } 103 } 104