/// Result of parsing the options.
pub type OptRes = Result<TestOpts, String>;
/// Result of parsing the option part.
-type OptPartRes<T> = Result<Option<T>, String>;
+type OptPartRes<T> = Result<T, String>;
fn optgroups() -> getopts::Options {
let mut opts = getopts::Options::new();
);
}
-// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
-fn is_nightly() -> bool {
- // Whether this is a feature-staged build, i.e., on the beta or stable channel
- let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
- // Whether we should enable unstable features for bootstrapping
- let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
+/// Parses command line arguments into test options.
+/// Returns `None` if help was requested (since we only show help message and don't run tests),
+/// returns `Some(Err(..))` if provided arguments are incorrect,
+/// otherwise creates a `TestOpts` object and returns it.
+pub fn parse_opts(args: &[String]) -> Option<OptRes> {
+ // Parse matches.
+ let opts = optgroups();
+ let args = args.get(1..).unwrap_or(args);
+ let matches = match opts.parse(args) {
+ Ok(m) => m,
+ Err(f) => return Some(Err(f.to_string())),
+ };
- bootstrap || !disable_unstable_features
+ // Check if help was requested.
+ if matches.opt_present("h") {
+ // Show help and do nothing more.
+ usage(&args[0], &opts);
+ return None;
+ }
+
+ // Actually parse the opts.
+ let opts_result = parse_opts_impl(matches);
+
+ Some(opts_result)
}
// Gets the option value and checks if unstable features are enabled.
($matches:ident, $allow_unstable:ident, $option_name:literal) => {{
let opt = $matches.opt_present($option_name);
if !$allow_unstable && opt {
- return Some(Err(format!(
+ return Err(format!(
"The \"{}\" flag is only accepted on the nightly compiler",
$option_name
- )));
+ ));
}
opt
}};
}
+// Implementation of `parse_opts` that doesn't care about help message
+// and returns a `Result`.
+fn parse_opts_impl(matches: getopts::Matches) -> OptRes {
+ let allow_unstable = get_allow_unstable(&matches)?;
+
+ // Unstable flags
+ let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic");
+ let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored");
+ let time_options = get_time_options(&matches, allow_unstable)?;
+
+ let quiet = matches.opt_present("quiet");
+ let exact = matches.opt_present("exact");
+ let list = matches.opt_present("list");
+ let skip = matches.opt_strs("skip");
+
+ let bench_benchmarks = matches.opt_present("bench");
+ let run_tests = !bench_benchmarks || matches.opt_present("test");
+
+ let logfile = get_log_file(&matches)?;
+ let run_ignored = get_run_ignored(&matches, include_ignored)?;
+ let filter = get_filter(&matches)?;
+ let nocapture = get_nocapture(&matches)?;
+ let test_threads = get_test_threads(&matches)?;
+ let color = get_color_config(&matches)?;
+ let format = get_format(&matches, quiet, allow_unstable)?;
+
+ let options = Options::new().display_output(matches.opt_present("show-output"));
+
+ let test_opts = TestOpts {
+ list,
+ filter,
+ filter_exact: exact,
+ exclude_should_panic,
+ run_ignored,
+ run_tests,
+ bench_benchmarks,
+ logfile,
+ nocapture,
+ color,
+ format,
+ test_threads,
+ skip,
+ time_options,
+ options,
+ };
+
+ Ok(test_opts)
+}
+
+// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566
+fn is_nightly() -> bool {
+ // Whether this is a feature-staged build, i.e., on the beta or stable channel
+ let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
+ // Whether we should enable unstable features for bootstrapping
+ let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok();
+
+ bootstrap || !disable_unstable_features
+}
+
// Gets the CLI options assotiated with `report-time` feature.
fn get_time_options(
matches: &getopts::Matches,
allow_unstable: bool)
--> Option<OptPartRes<TestTimeOptions>> {
+-> OptPartRes<Option<TestTimeOptions>> {
let report_time = unstable_optflag!(matches, allow_unstable, "report-time");
let colored_opt_str = matches.opt_str("report-time");
let mut report_time_colored = report_time && colored_opt_str == Some("colored".into());
None
};
- Some(Ok(options))
+ Ok(options)
}
-// Parses command line arguments into test options
-pub fn parse_opts(args: &[String]) -> Option<OptRes> {
- let mut allow_unstable = false;
- let opts = optgroups();
- let args = args.get(1..).unwrap_or(args);
- let matches = match opts.parse(args) {
- Ok(m) => m,
- Err(f) => return Some(Err(f.to_string())),
+fn get_test_threads(matches: &getopts::Matches) -> OptPartRes<Option<usize>> {
+ let test_threads = match matches.opt_str("test-threads") {
+ Some(n_str) => match n_str.parse::<usize>() {
+ Ok(0) => return Err("argument for --test-threads must not be 0".to_string()),
+ Ok(n) => Some(n),
+ Err(e) => {
+ return Err(format!(
+ "argument for --test-threads must be a number > 0 \
+ (error: {})",
+ e
+ ));
+ }
+ },
+ None => None,
};
- if let Some(opt) = matches.opt_str("Z") {
- if !is_nightly() {
- return Some(Err(
- "the option `Z` is only accepted on the nightly compiler".into(),
- ));
- }
+ Ok(test_threads)
+}
- match &*opt {
- "unstable-options" => {
- allow_unstable = true;
- }
- _ => {
- return Some(Err("Unrecognized option to `Z`".into()));
+fn get_format(matches: &getopts::Matches, quiet: bool, allow_unstable: bool) -> OptPartRes<OutputFormat> {
+ let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
+ None if quiet => OutputFormat::Terse,
+ Some("pretty") | None => OutputFormat::Pretty,
+ Some("terse") => OutputFormat::Terse,
+ Some("json") => {
+ if !allow_unstable {
+ return Err(
+ "The \"json\" format is only accepted on the nightly compiler".into(),
+ );
}
+ OutputFormat::Json
}
- };
- if matches.opt_present("h") {
- usage(&args[0], &opts);
- return None;
- }
-
- let filter = if !matches.free.is_empty() {
- Some(matches.free[0].clone())
- } else {
- None
+ Some(v) => {
+ return Err(format!(
+ "argument for --format must be pretty, terse, or json (was \
+ {})",
+ v
+ ));
+ }
};
- let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic");
+ Ok(format)
+}
- let include_ignored = unstable_optflag!(matches, allow_unstable, "include-ignored");
+fn get_color_config(matches: &getopts::Matches) -> OptPartRes<ColorConfig> {
+ let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
+ Some("auto") | None => ColorConfig::AutoColor,
+ Some("always") => ColorConfig::AlwaysColor,
+ Some("never") => ColorConfig::NeverColor,
- let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
- (true, true) => {
- return Some(Err(
- "the options --include-ignored and --ignored are mutually exclusive".into(),
+ Some(v) => {
+ return Err(format!(
+ "argument for --color must be auto, always, or never (was \
+ {})",
+ v
));
}
- (true, false) => RunIgnored::Yes,
- (false, true) => RunIgnored::Only,
- (false, false) => RunIgnored::No,
};
- let quiet = matches.opt_present("quiet");
- let exact = matches.opt_present("exact");
- let list = matches.opt_present("list");
- let logfile = matches.opt_str("logfile");
- let logfile = logfile.map(|s| PathBuf::from(&s));
-
- let bench_benchmarks = matches.opt_present("bench");
- let run_tests = !bench_benchmarks || matches.opt_present("test");
+ Ok(color)
+}
+fn get_nocapture(matches: &getopts::Matches) -> OptPartRes<bool> {
let mut nocapture = matches.opt_present("nocapture");
if !nocapture {
nocapture = match env::var("RUST_TEST_NOCAPTURE") {
};
}
- let time_options = match get_time_options(&matches, allow_unstable) {
- Some(Ok(val)) => val,
- Some(Err(e)) => return Some(Err(e)),
- None => panic!("Unexpected output from `get_time_options`"),
- };
+ Ok(nocapture)
+}
- let test_threads = match matches.opt_str("test-threads") {
- Some(n_str) => match n_str.parse::<usize>() {
- Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())),
- Ok(n) => Some(n),
- Err(e) => {
- return Some(Err(format!(
- "argument for --test-threads must be a number > 0 \
- (error: {})",
- e
- )));
- }
- },
- None => None,
+fn get_run_ignored(matches: &getopts::Matches, include_ignored: bool) -> OptPartRes<RunIgnored> {
+ let run_ignored = match (include_ignored, matches.opt_present("ignored")) {
+ (true, true) => {
+ return Err(
+ "the options --include-ignored and --ignored are mutually exclusive".into(),
+ );
+ }
+ (true, false) => RunIgnored::Yes,
+ (false, true) => RunIgnored::Only,
+ (false, false) => RunIgnored::No,
};
- let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
- Some("auto") | None => ColorConfig::AutoColor,
- Some("always") => ColorConfig::AlwaysColor,
- Some("never") => ColorConfig::NeverColor,
+ Ok(run_ignored)
+}
- Some(v) => {
- return Some(Err(format!(
- "argument for --color must be auto, always, or never (was \
- {})",
- v
- )));
- }
+fn get_filter(matches: &getopts::Matches) -> OptPartRes<Option<String>> {
+ let filter = if !matches.free.is_empty() {
+ Some(matches.free[0].clone())
+ } else {
+ None
};
- let format = match matches.opt_str("format").as_ref().map(|s| &**s) {
- None if quiet => OutputFormat::Terse,
- Some("pretty") | None => OutputFormat::Pretty,
- Some("terse") => OutputFormat::Terse,
- Some("json") => {
- if !allow_unstable {
- return Some(Err(
- "The \"json\" format is only accepted on the nightly compiler".into(),
- ));
- }
- OutputFormat::Json
+ Ok(filter)
+}
+
+fn get_allow_unstable(matches: &getopts::Matches) -> OptPartRes<bool> {
+ let mut allow_unstable = false;
+
+ if let Some(opt) = matches.opt_str("Z") {
+ if !is_nightly() {
+ return Err(
+ "the option `Z` is only accepted on the nightly compiler".into(),
+ );
}
- Some(v) => {
- return Some(Err(format!(
- "argument for --format must be pretty, terse, or json (was \
- {})",
- v
- )));
+ match &*opt {
+ "unstable-options" => {
+ allow_unstable = true;
+ }
+ _ => {
+ return Err("Unrecognized option to `Z`".into());
+ }
}
};
- let test_opts = TestOpts {
- list,
- filter,
- filter_exact: exact,
- exclude_should_panic,
- run_ignored,
- run_tests,
- bench_benchmarks,
- logfile,
- nocapture,
- color,
- format,
- test_threads,
- skip: matches.opt_strs("skip"),
- time_options,
- options: Options::new().display_output(matches.opt_present("show-output")),
- };
+ Ok(allow_unstable)
+}
+
+fn get_log_file(matches: &getopts::Matches) -> OptPartRes<Option<PathBuf>> {
+ let logfile = matches.opt_str("logfile").map(|s| PathBuf::from(&s));
- Some(Ok(test_opts))
+ Ok(logfile)
}