1 //! Module converting command-line arguments into test configuration.
4 use std
::path
::PathBuf
;
6 use super::helpers
::isatty
;
7 use super::options
::{ColorConfig, Options, OutputFormat, RunIgnored}
;
8 use super::time
::TestTimeOptions
;
13 pub filters
: Vec
<String
>,
14 pub filter_exact
: bool
,
15 pub force_run_in_process
: bool
,
16 pub exclude_should_panic
: bool
,
17 pub run_ignored
: RunIgnored
,
19 pub bench_benchmarks
: bool
,
20 pub logfile
: Option
<PathBuf
>,
22 pub color
: ColorConfig
,
23 pub format
: OutputFormat
,
24 pub test_threads
: Option
<usize>,
25 pub skip
: Vec
<String
>,
26 pub time_options
: Option
<TestTimeOptions
>,
31 pub fn use_color(&self) -> bool
{
33 ColorConfig
::AutoColor
=> !self.nocapture
&& isatty
::stdout_isatty(),
34 ColorConfig
::AlwaysColor
=> true,
35 ColorConfig
::NeverColor
=> false,
40 /// Result of parsing the options.
41 pub type OptRes
= Result
<TestOpts
, String
>;
42 /// Result of parsing the option part.
43 type OptPartRes
<T
> = Result
<T
, String
>;
45 fn optgroups() -> getopts
::Options
{
46 let mut opts
= getopts
::Options
::new();
47 opts
.optflag("", "include-ignored", "Run ignored and not ignored tests")
48 .optflag("", "ignored", "Run only ignored tests")
49 .optflag("", "force-run-in-process", "Forces tests to run in-process when panic=abort")
50 .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic")
51 .optflag("", "test", "Run tests and not benchmarks")
52 .optflag("", "bench", "Run benchmarks instead of tests")
53 .optflag("", "list", "List all tests and benchmarks")
54 .optflag("h", "help", "Display this message")
55 .optopt("", "logfile", "Write logs to the specified file", "PATH")
59 "don't capture stdout/stderr of each \
60 task, allow printing directly",
65 "Number of threads used for running tests \
72 "Skip tests whose names contain FILTER (this flag can \
73 be used multiple times)",
79 "Display one character per test instead of one line. \
80 Alias to --format=terse",
82 .optflag("", "exact", "Exactly match filters rather than by substring")
86 "Configure coloring of output:
87 auto = colorize if stdout is a tty and tests are run on serially (default);
88 always = always colorize output;
89 never = never colorize output;",
95 "Configure formatting of output:
96 pretty = Print verbose output;
97 terse = Display one character per test;
98 json = Output a json document",
101 .optflag("", "show-output", "Show captured stdout of successful tests")
105 "Enable nightly-only flags:
106 unstable-options = Allow use of experimental features",
112 "Show execution time of each test. Available values:
113 plain = do not colorize the execution time (default);
114 colored = colorize output according to the `color` parameter value;
116 Threshold values for colorized output can be configured via
117 `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
118 `RUST_TEST_TIME_DOCTEST` environment variables.
120 Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.
121 Durations must be specified in milliseconds, e.g. `500,2000` means that the warn time
122 is 0.5 seconds, and the critical time is 2 seconds.
124 Not available for --format=terse",
130 "Treat excess of the test execution time limit as error.
132 Threshold values for this option can be configured via
133 `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
134 `RUST_TEST_TIME_DOCTEST` environment variables.
136 Expected format of environment variable is `VARIABLE=WARN_TIME,CRITICAL_TIME`.
138 `CRITICAL_TIME` here means the limit that should not be exceeded by test.
144 fn usage(binary
: &str, options
: &getopts
::Options
) {
145 let message
= format
!("Usage: {} [OPTIONS] [FILTERS...]", binary
);
149 The FILTER string is tested against the name of all tests, and only those
150 tests whose names contain the filter are run. Multiple filter strings may
151 be passed, which will run all tests matching any of the filters.
153 By default, all tests are run in parallel. This can be altered with the
154 --test-threads flag or the RUST_TEST_THREADS environment variable when running
157 All tests have their standard output and standard error captured by default.
158 This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE
159 environment variable to a value other than "0". Logging is not captured by default.
163 `#[test]` - Indicates a function is a test to be run. This function
165 `#[bench]` - Indicates a function is a benchmark to be run. This
166 function takes one argument (test::Bencher).
167 `#[should_panic]` - This function (also labeled with `#[test]`) will only pass if
168 the code causes a panic (an assertion failure or panic!)
169 A message may be provided, which the failure string must
170 contain: #[should_panic(expected = "foo")].
171 `#[ignore]` - When applied to a function which is already attributed as a
172 test, then the test runner will ignore these tests during
173 normal test runs. Running with --ignored or --include-ignored will run
175 usage
= options
.usage(&message
)
179 /// Parses command line arguments into test options.
180 /// Returns `None` if help was requested (since we only show help message and don't run tests),
181 /// returns `Some(Err(..))` if provided arguments are incorrect,
182 /// otherwise creates a `TestOpts` object and returns it.
183 pub fn parse_opts(args
: &[String
]) -> Option
<OptRes
> {
185 let opts
= optgroups();
186 let args
= args
.get(1..).unwrap_or(args
);
187 let matches
= match opts
.parse(args
) {
189 Err(f
) => return Some(Err(f
.to_string())),
192 // Check if help was requested.
193 if matches
.opt_present("h") {
194 // Show help and do nothing more.
195 usage(&args
[0], &opts
);
199 // Actually parse the opts.
200 let opts_result
= parse_opts_impl(matches
);
205 // Gets the option value and checks if unstable features are enabled.
206 macro_rules
! unstable_optflag
{
207 ($matches
:ident
, $allow_unstable
:ident
, $option_name
:literal
) => {{
208 let opt
= $matches
.opt_present($option_name
);
209 if !$allow_unstable
&& opt
{
211 "The \"{}\" flag is only accepted on the nightly compiler with -Z unstable-options",
220 // Implementation of `parse_opts` that doesn't care about help message
221 // and returns a `Result`.
222 fn parse_opts_impl(matches
: getopts
::Matches
) -> OptRes
{
223 let allow_unstable
= get_allow_unstable(&matches
)?
;
226 let force_run_in_process
= unstable_optflag
!(matches
, allow_unstable
, "force-run-in-process");
227 let exclude_should_panic
= unstable_optflag
!(matches
, allow_unstable
, "exclude-should-panic");
228 let time_options
= get_time_options(&matches
, allow_unstable
)?
;
230 let include_ignored
= matches
.opt_present("include-ignored");
231 let quiet
= matches
.opt_present("quiet");
232 let exact
= matches
.opt_present("exact");
233 let list
= matches
.opt_present("list");
234 let skip
= matches
.opt_strs("skip");
236 let bench_benchmarks
= matches
.opt_present("bench");
237 let run_tests
= !bench_benchmarks
|| matches
.opt_present("test");
239 let logfile
= get_log_file(&matches
)?
;
240 let run_ignored
= get_run_ignored(&matches
, include_ignored
)?
;
241 let filters
= matches
.free
.clone();
242 let nocapture
= get_nocapture(&matches
)?
;
243 let test_threads
= get_test_threads(&matches
)?
;
244 let color
= get_color_config(&matches
)?
;
245 let format
= get_format(&matches
, quiet
, allow_unstable
)?
;
247 let options
= Options
::new().display_output(matches
.opt_present("show-output"));
249 let test_opts
= TestOpts
{
253 force_run_in_process
,
254 exclude_should_panic
,
271 // FIXME: Copied from librustc_ast until linkage errors are resolved. Issue #47566
272 fn is_nightly() -> bool
{
273 // Whether this is a feature-staged build, i.e., on the beta or stable channel
274 let disable_unstable_features
= option_env
!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
275 // Whether we should enable unstable features for bootstrapping
276 let bootstrap
= env
::var("RUSTC_BOOTSTRAP").is_ok();
278 bootstrap
|| !disable_unstable_features
281 // Gets the CLI options associated with `report-time` feature.
283 matches
: &getopts
::Matches
,
284 allow_unstable
: bool
,
285 ) -> OptPartRes
<Option
<TestTimeOptions
>> {
286 let report_time
= unstable_optflag
!(matches
, allow_unstable
, "report-time");
287 let colored_opt_str
= matches
.opt_str("report-time");
288 let mut report_time_colored
= report_time
&& colored_opt_str
== Some("colored".into());
289 let ensure_test_time
= unstable_optflag
!(matches
, allow_unstable
, "ensure-time");
291 // If `ensure-test-time` option is provided, time output is enforced,
292 // so user won't be confused if any of tests will silently fail.
293 let options
= if report_time
|| ensure_test_time
{
294 if ensure_test_time
&& !report_time
{
295 report_time_colored
= true;
297 Some(TestTimeOptions
::new_from_env(ensure_test_time
, report_time_colored
))
305 fn get_test_threads(matches
: &getopts
::Matches
) -> OptPartRes
<Option
<usize>> {
306 let test_threads
= match matches
.opt_str("test-threads") {
307 Some(n_str
) => match n_str
.parse
::<usize>() {
308 Ok(0) => return Err("argument for --test-threads must not be 0".to_string()),
312 "argument for --test-threads must be a number > 0 \
325 matches
: &getopts
::Matches
,
327 allow_unstable
: bool
,
328 ) -> OptPartRes
<OutputFormat
> {
329 let format
= match matches
.opt_str("format").as_deref() {
330 None
if quiet
=> OutputFormat
::Terse
,
331 Some("pretty") | None
=> OutputFormat
::Pretty
,
332 Some("terse") => OutputFormat
::Terse
,
335 return Err("The \"json\" format is only accepted on the nightly compiler".into());
342 "argument for --format must be pretty, terse, or json (was \
352 fn get_color_config(matches
: &getopts
::Matches
) -> OptPartRes
<ColorConfig
> {
353 let color
= match matches
.opt_str("color").as_deref() {
354 Some("auto") | None
=> ColorConfig
::AutoColor
,
355 Some("always") => ColorConfig
::AlwaysColor
,
356 Some("never") => ColorConfig
::NeverColor
,
360 "argument for --color must be auto, always, or never (was \
370 fn get_nocapture(matches
: &getopts
::Matches
) -> OptPartRes
<bool
> {
371 let mut nocapture
= matches
.opt_present("nocapture");
373 nocapture
= match env
::var("RUST_TEST_NOCAPTURE") {
374 Ok(val
) => &val
!= "0",
382 fn get_run_ignored(matches
: &getopts
::Matches
, include_ignored
: bool
) -> OptPartRes
<RunIgnored
> {
383 let run_ignored
= match (include_ignored
, matches
.opt_present("ignored")) {
385 return Err("the options --include-ignored and --ignored are mutually exclusive".into());
387 (true, false) => RunIgnored
::Yes
,
388 (false, true) => RunIgnored
::Only
,
389 (false, false) => RunIgnored
::No
,
395 fn get_allow_unstable(matches
: &getopts
::Matches
) -> OptPartRes
<bool
> {
396 let mut allow_unstable
= false;
398 if let Some(opt
) = matches
.opt_str("Z") {
400 return Err("the option `Z` is only accepted on the nightly compiler".into());
404 "unstable-options" => {
405 allow_unstable
= true;
408 return Err("Unrecognized option to `Z`".into());
416 fn get_log_file(matches
: &getopts
::Matches
) -> OptPartRes
<Option
<PathBuf
>> {
417 let logfile
= matches
.opt_str("logfile").map(|s
| PathBuf
::from(&s
));