From 6bc505226c3be8fb9cd986644cb53a54e8ae6b5d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 27 Mar 2025 14:02:12 -0500 Subject: [PATCH 1/5] docs(test-lexarg): Add example --- crates/libtest-lexarg/examples/libtest-cli.rs | 56 +++++++++++++++++++ crates/libtest-lexarg/src/lib.rs | 6 ++ 2 files changed, 62 insertions(+) create mode 100644 crates/libtest-lexarg/examples/libtest-cli.rs diff --git a/crates/libtest-lexarg/examples/libtest-cli.rs b/crates/libtest-lexarg/examples/libtest-cli.rs new file mode 100644 index 0000000..6d62773 --- /dev/null +++ b/crates/libtest-lexarg/examples/libtest-cli.rs @@ -0,0 +1,56 @@ +fn main() -> lexarg::Result<()> { + use lexarg::prelude::*; + + let mut test_opts = libtest_lexarg::TestOptsParseState::new(); + + let raw = std::env::args_os().collect::>(); + 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(()) +} diff --git a/crates/libtest-lexarg/src/lib.rs b/crates/libtest-lexarg/src/lib.rs index d31bd56..905a55b 100644 --- a/crates/libtest-lexarg/src/lib.rs +++ b/crates/libtest-lexarg/src/lib.rs @@ -2,6 +2,12 @@ //! //! This does not drive parsing but provides [`TestOptsParseState`] 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)] From fc7f10f7752090c662a765c1c9242c68e7533d9b Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 27 Mar 2025 14:04:05 -0500 Subject: [PATCH 2/5] fix(test-lexarg)!: Remove deprecated `--logfile` --- crates/libtest-lexarg/src/lib.rs | 10 ---------- crates/libtest2-harness/src/harness.rs | 3 --- 2 files changed, 13 deletions(-) diff --git a/crates/libtest-lexarg/src/lib.rs b/crates/libtest-lexarg/src/lib.rs index 905a55b..9669484 100644 --- a/crates/libtest-lexarg/src/lib.rs +++ b/crates/libtest-lexarg/src/lib.rs @@ -29,7 +29,6 @@ pub struct TestOpts { pub run_ignored: RunIgnored, pub run_tests: bool, pub bench_benchmarks: bool, - pub logfile: Option, pub nocapture: bool, pub color: ColorConfig, pub format: OutputFormat, @@ -200,7 +199,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 @@ -333,14 +331,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; } diff --git a/crates/libtest2-harness/src/harness.rs b/crates/libtest2-harness/src/harness.rs index 7b67146..f38d293 100644 --- a/crates/libtest2-harness/src/harness.rs +++ b/crates/libtest2-harness/src/harness.rs @@ -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); From 6dcbec9b6604c11a955698323953cbb5e6e242de Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 27 Mar 2025 14:39:21 -0500 Subject: [PATCH 3/5] fix(text-lexarg): Fix --quiet's behavior with --format --- crates/libtest-lexarg/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/libtest-lexarg/src/lib.rs b/crates/libtest-lexarg/src/lib.rs index 9669484..46f2ed3 100644 --- a/crates/libtest-lexarg/src/lib.rs +++ b/crates/libtest-lexarg/src/lib.rs @@ -504,8 +504,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; } From 08e48aa5850f05bcf84d4a47cf21a5989da29528 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 27 Mar 2025 14:47:44 -0500 Subject: [PATCH 4/5] fix(test-lexarg)!: Clarify struct relationship I was confused when coming back to the code so the naming being more specific like this didn't help. --- crates/libtest-lexarg/examples/libtest-cli.rs | 2 +- crates/libtest-lexarg/src/lib.rs | 10 +++++----- crates/libtest2-harness/src/harness.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/libtest-lexarg/examples/libtest-cli.rs b/crates/libtest-lexarg/examples/libtest-cli.rs index 6d62773..553928d 100644 --- a/crates/libtest-lexarg/examples/libtest-cli.rs +++ b/crates/libtest-lexarg/examples/libtest-cli.rs @@ -1,7 +1,7 @@ fn main() -> lexarg::Result<()> { use lexarg::prelude::*; - let mut test_opts = libtest_lexarg::TestOptsParseState::new(); + let mut test_opts = libtest_lexarg::TestOptsBuilder::new(); let raw = std::env::args_os().collect::>(); let mut parser = lexarg::Parser::new(&raw); diff --git a/crates/libtest-lexarg/src/lib.rs b/crates/libtest-lexarg/src/lib.rs index 46f2ed3..c50a8f5 100644 --- a/crates/libtest-lexarg/src/lib.rs +++ b/crates/libtest-lexarg/src/lib.rs @@ -1,6 +1,6 @@ //! 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 @@ -18,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, @@ -288,9 +288,9 @@ 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, @@ -298,7 +298,7 @@ pub struct TestOptsParseState { ignored: bool, } -impl TestOptsParseState { +impl TestOptsBuilder { pub fn new() -> Self { Default::default() } diff --git a/crates/libtest2-harness/src/harness.rs b/crates/libtest2-harness/src/harness.rs index f38d293..ad795c2 100644 --- a/crates/libtest2-harness/src/harness.rs +++ b/crates/libtest2-harness/src/harness.rs @@ -73,7 +73,7 @@ const ERROR_EXIT_CODE: i32 = 101; fn parse<'p>( parser: &mut cli::Parser<'p>, ) -> Result> { - let mut test_opts = libtest_lexarg::TestOptsParseState::new(); + let mut test_opts = libtest_lexarg::TestOptsBuilder::new(); let bin = parser .next_raw() From 0c5844b1a1ef6c621211bef0067579d02b0360fd Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 27 Mar 2025 14:51:01 -0500 Subject: [PATCH 5/5] docs(test-lexarg): Clarify subordinate types --- crates/libtest-lexarg/src/lib.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/libtest-lexarg/src/lib.rs b/crates/libtest-lexarg/src/lib.rs index c50a8f5..50cac52 100644 --- a/crates/libtest-lexarg/src/lib.rs +++ b/crates/libtest-lexarg/src/lib.rs @@ -45,7 +45,7 @@ pub struct TestOpts { pub allowed_unstable: Vec, } -/// 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, @@ -60,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, @@ -74,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 @@ -93,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 @@ -124,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, @@ -177,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 {