1 use clap::{Parser, ValueEnum};
2 
3 /// Command line arguments.
4 ///
5 /// This type represents everything the user can specify via CLI args. The main
6 /// method is [`from_args`][Arguments::from_args] which reads the global
7 /// `std::env::args()` and parses them into this type.
8 ///
9 /// `libtest-mimic` supports a subset of all args/flags supported by the
10 /// official test harness. There are also some other minor CLI differences, but
11 /// the main use cases should work exactly like with the built-in harness.
12 #[derive(Parser, Debug, Clone, Default)]
13 #[command(
14     help_template = "USAGE: [OPTIONS] [FILTER]\n\n{all-args}\n\n\n{after-help}",
15     disable_version_flag = true,
16     after_help = "By default, all tests are run in parallel. This can be altered with the \n\
17         --test-threads flag when running tests (set it to 1).",
18 )]
19 pub struct Arguments {
20     // ============== FLAGS ===================================================
21     /// Run ignored and non-ignored tests.
22     #[arg(long = "include-ignored", help = "Run ignored tests")]
23     pub include_ignored: bool,
24 
25     /// Run only ignored tests.
26     #[arg(long = "ignored", help = "Run ignored tests")]
27     pub ignored: bool,
28 
29     /// Run tests, but not benchmarks.
30     #[arg(
31         long = "test",
32         conflicts_with = "bench",
33         help = "Run tests and not benchmarks",
34     )]
35     pub test: bool,
36 
37     /// Run benchmarks, but not tests.
38     #[arg(long = "bench", help = "Run benchmarks instead of tests")]
39     pub bench: bool,
40 
41     /// Only list all tests and benchmarks.
42     #[arg(long = "list", help = "List all tests and benchmarks")]
43     pub list: bool,
44 
45     /// No-op, ignored (libtest-mimic always runs in no-capture mode)
46     #[arg(long = "nocapture", help = "No-op (libtest-mimic always runs in no-capture mode)")]
47     pub nocapture: bool,
48 
49     /// If set, filters are matched exactly rather than by substring.
50     #[arg(
51         long = "exact",
52         help = "Exactly match filters rather than by substring",
53     )]
54     pub exact: bool,
55 
56     /// If set, display only one character per test instead of one line.
57     /// Especially useful for huge test suites.
58     ///
59     /// This is an alias for `--format=terse`. If this is set, `format` is
60     /// `None`.
61     #[arg(
62         short = 'q',
63         long = "quiet",
64         conflicts_with = "format",
65         help = "Display one character per test instead of one line. Alias to --format=terse",
66     )]
67     pub quiet: bool,
68 
69     // ============== OPTIONS =================================================
70     /// Number of threads used for parallel testing.
71     #[arg(
72         long = "test-threads",
73         help = "Number of threads used for running tests in parallel. If set to 1, \n\
74             all tests are run in the main thread.",
75     )]
76     pub test_threads: Option<usize>,
77 
78     /// Path of the logfile. If specified, everything will be written into the
79     /// file instead of stdout.
80     #[arg(
81         long = "logfile",
82         value_name = "PATH",
83         help = "Write logs to the specified file instead of stdout",
84     )]
85     pub logfile: Option<String>,
86 
87     /// A list of filters. Tests whose names contain parts of any of these
88     /// filters are skipped.
89     #[arg(
90         long = "skip",
91         value_name = "FILTER",
92         num_args = 1,
93         help = "Skip tests whose names contain FILTER (this flag can be used multiple times)",
94     )]
95     pub skip: Vec<String>,
96 
97     /// Specifies whether or not to color the output.
98     #[arg(
99         long = "color",
100         value_enum,
101         value_name = "auto|always|never",
102         help = "Configure coloring of output: \n\
103             - auto = colorize if stdout is a tty and tests are run on serially (default)\n\
104             - always = always colorize output\n\
105             - never = never colorize output\n",
106     )]
107     pub color: Option<ColorSetting>,
108 
109     /// Specifies the format of the output.
110     #[arg(
111         long = "format",
112         value_enum,
113         value_name = "pretty|terse|json",
114         help = "Configure formatting of output: \n\
115             - pretty = Print verbose output\n\
116             - terse = Display one character per test\n",
117     )]
118     pub format: Option<FormatSetting>,
119 
120     // ============== POSITIONAL VALUES =======================================
121     /// Filter string. Only tests which contain this string are run.
122     #[arg(
123         value_name = "FILTER",
124         help = "The FILTER string is tested against the name of all tests, and only those tests \
125                 whose names contain the filter are run.",
126     )]
127     pub filter: Option<String>,
128 }
129 
130 impl Arguments {
131     /// Parses the global CLI arguments given to the application.
132     ///
133     /// If the parsing fails (due to incorrect CLI args), an error is shown and
134     /// the application exits. If help is requested (`-h` or `--help`), a help
135     /// message is shown and the application exits, too.
from_args() -> Self136     pub fn from_args() -> Self {
137         Parser::parse()
138     }
139 
140     /// Like `from_args()`, but operates on an explicit iterator and not the
141     /// global arguments. Note that the first element is the executable name!
from_iter<I>(iter: I) -> Self where Self: Sized, I: IntoIterator, I::Item: Into<std::ffi::OsString> + Clone,142     pub fn from_iter<I>(iter: I) -> Self
143     where
144         Self: Sized,
145         I: IntoIterator,
146         I::Item: Into<std::ffi::OsString> + Clone,
147     {
148         Parser::parse_from(iter)
149     }
150 }
151 
152 /// Possible values for the `--color` option.
153 #[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
154 pub enum ColorSetting {
155     /// Colorize output if stdout is a tty and tests are run on serially
156     /// (default).
157     Auto,
158 
159     /// Always colorize output.
160     Always,
161 
162     /// Never colorize output.
163     Never,
164 }
165 
166 impl Default for ColorSetting {
default() -> Self167     fn default() -> Self {
168         ColorSetting::Auto
169     }
170 }
171 
172 /// Possible values for the `--format` option.
173 #[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
174 pub enum FormatSetting {
175     /// One line per test. Output for humans. (default)
176     Pretty,
177 
178     /// One character per test. Usefull for test suites with many tests.
179     Terse,
180 }
181 
182 impl Default for FormatSetting {
default() -> Self183     fn default() -> Self {
184         FormatSetting::Pretty
185     }
186 }
187 
188 #[cfg(test)]
189 mod tests {
190     use super::*;
191 
192     #[test]
verify_cli()193     fn verify_cli() {
194         use clap::CommandFactory;
195         Arguments::command().debug_assert();
196     }
197 }
198