Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions crates/libtest-lexarg/examples/libtest-cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
fn main() -> lexarg::Result<()> {
use lexarg::prelude::*;

let mut test_opts = libtest_lexarg::TestOptsBuilder::new();

let raw = std::env::args_os().collect::<Vec<_>>();
let mut parser = lexarg::Parser::new(&raw);
let bin = parser
.next_raw()
.expect("first arg, no pending values")
.unwrap_or(std::ffi::OsStr::new("test"));
let mut prev_arg = Value(bin);
while let Some(arg) = parser.next_arg() {
match arg {
Short("h") | Long("help") => {
let bin = bin.to_string_lossy();
let options_help = libtest_lexarg::OPTIONS_HELP.trim();
let after_help = libtest_lexarg::AFTER_HELP.trim();
println!(
"Usage: {bin} [OPTIONS] [FILTER]...

{options_help}

{after_help}"
);
std::process::exit(0);
}
// All values are the same, whether escaped or not, so its a no-op
Escape(_) => {
prev_arg = arg;
continue;
}
Unexpected(_) => {
return Err(lexarg::ErrorContext::msg("unexpected value")
.unexpected(arg)
.within(prev_arg)
.into());
}
_ => {}
}
prev_arg = arg;

let arg = test_opts.parse_next(&mut parser, arg)?;

if let Some(arg) = arg {
return Err(lexarg::ErrorContext::msg("unexpected argument")
.unexpected(arg)
.into());
}
}

let opts = test_opts.finish()?;
println!("{opts:#?}");

Ok(())
}
43 changes: 20 additions & 23 deletions crates/libtest-lexarg/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! libtest-compatible argument parser
//!
//! This does not drive parsing but provides [`TestOptsParseState`] to plug into the parsing,
//! This does not drive parsing but provides [`TestOptsBuilder`] to plug into the parsing,
//! allowing additional parsers to be integrated.
//!
//! ## Example
//!
//! ```no_run
#![doc = include_str!("../examples/libtest-cli.rs")]
//! ```

#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![forbid(unsafe_code)]
Expand All @@ -12,7 +18,7 @@ use lexarg_error::ErrorContext;

/// Parsed command-line options
///
/// To parse, see [`TestOptsParseState`]
/// To parse, see [`TestOptsBuilder`]
#[derive(Debug, Default)]
pub struct TestOpts {
pub list: bool,
Expand All @@ -23,7 +29,6 @@ pub struct TestOpts {
pub run_ignored: RunIgnored,
pub run_tests: bool,
pub bench_benchmarks: bool,
pub logfile: Option<std::path::PathBuf>,
pub nocapture: bool,
pub color: ColorConfig,
pub format: OutputFormat,
Expand All @@ -40,7 +45,7 @@ pub struct TestOpts {
pub allowed_unstable: Vec<String>,
}

/// Whether ignored test should be run or not
/// Whether ignored test should be run or not (see [`TestOpts::run_ignored`])
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum RunIgnored {
Yes,
Expand All @@ -55,7 +60,7 @@ impl Default for RunIgnored {
}
}

/// Whether should console output be colored or not
/// Whether should console output be colored or not (see [`TestOpts::color`])
#[derive(Copy, Clone, Debug)]
pub enum ColorConfig {
AutoColor,
Expand All @@ -69,7 +74,7 @@ impl Default for ColorConfig {
}
}

/// Format of the test results output
/// Format of the test results output (see [`TestOpts::format`])
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OutputFormat {
/// Verbose output
Expand All @@ -88,7 +93,7 @@ impl Default for OutputFormat {
}
}

/// Structure with parameters for calculating test execution time.
/// Structure with parameters for calculating test execution time (see [`TestOpts::time_options`])
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TestTimeOptions {
/// Denotes if the test critical execution time limit excess should be considered
Expand Down Expand Up @@ -119,7 +124,7 @@ impl Default for TestTimeOptions {
}
}

/// Structure denoting time limits for test execution.
/// Structure denoting time limits for test execution (see [`TestTimeOptions`])
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct TimeThreshold {
pub warn: std::time::Duration,
Expand Down Expand Up @@ -172,7 +177,9 @@ impl TimeThreshold {
}
}

/// Options for the test run defined by the caller (instead of CLI arguments).
/// Options for the test run defined by the caller (instead of CLI arguments) (see
/// [`TestOpts::options`])
///
/// In case we want to add other options as well, just add them in this struct.
#[derive(Copy, Clone, Debug, Default)]
pub struct Options {
Expand All @@ -194,7 +201,6 @@ Options:
--test Run tests and not benchmarks
--bench Run benchmarks instead of tests
--list List all tests and benchmarks
--logfile PATH Write logs to the specified file
--nocapture don't capture stdout/stderr of each task, allow
printing directly
--test-threads n_threads
Expand Down Expand Up @@ -284,17 +290,17 @@ Test Attributes:

/// Intermediate CLI parser state for [`TestOpts`]
///
/// See [`TestOptsParseState::parse_next`]
/// See [`TestOptsBuilder::parse_next`]
#[derive(Debug, Default)]
pub struct TestOptsParseState {
pub struct TestOptsBuilder {
opts: TestOpts,
quiet: bool,
format: Option<OutputFormat>,
include_ignored: bool,
ignored: bool,
}

impl TestOptsParseState {
impl TestOptsBuilder {
pub fn new() -> Self {
Default::default()
}
Expand Down Expand Up @@ -327,14 +333,6 @@ impl TestOptsParseState {
Long("list") => {
self.opts.list = true;
}
Long("logfile") => {
let path = parser
.next_flag_value()
.ok_or_missing(Value(std::ffi::OsStr::new("PATH")))
.path()
.within(arg)?;
self.opts.logfile = Some(path.to_owned());
}
Long("nocapture") => {
self.opts.nocapture = true;
}
Expand Down Expand Up @@ -508,8 +506,7 @@ impl TestOptsParseState {
}
if let Some(format) = self.format {
self.opts.format = format;
}
if self.quiet {
} else if self.quiet {
self.opts.format = OutputFormat::Terse;
}

Expand Down
5 changes: 1 addition & 4 deletions crates/libtest2-harness/src/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const ERROR_EXIT_CODE: i32 = 101;
fn parse<'p>(
parser: &mut cli::Parser<'p>,
) -> Result<libtest_lexarg::TestOpts, cli::ErrorContext<'p>> {
let mut test_opts = libtest_lexarg::TestOptsParseState::new();
let mut test_opts = libtest_lexarg::TestOptsBuilder::new();

let bin = parser
.next_raw()
Expand Down Expand Up @@ -235,9 +235,6 @@ fn run(
if opts.options.panic_abort {
todo!("panic-abort is not yet supported");
}
if opts.logfile.is_some() {
todo!("`--logfile` is not yet supported");
}

let threads = opts.test_threads.map(|t| t.get()).unwrap_or(1);

Expand Down