From d77b2ef7c19b20014198cfab17d13428646cb0c9 Mon Sep 17 00:00:00 2001 From: Michael Debertol Date: Tue, 29 Jun 2021 20:49:02 +0200 Subject: [PATCH] [: add support for --help and --version I copied the help text verbatim from GNU, I hope that's ok. --- src/uu/test/src/test.rs | 82 +++++++++++++++++++++++++++++++++++++- tests/by-util/test_test.rs | 18 +++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index df5f1fd3e1e..6847a1fb685 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -10,12 +10,81 @@ mod parser; -use clap::{App, AppSettings}; +use clap::{crate_version, App, AppSettings}; use parser::{parse, Symbol}; use std::ffi::{OsStr, OsString}; use std::path::Path; use uucore::executable; +const USAGE: &str = "test EXPRESSION +or: test +or: [ EXPRESSION ] +or: [ ] +or: [ OPTION"; + +const AFTER_HELP: &str = " +Exit with the status determined by EXPRESSION. + +An omitted EXPRESSION defaults to false. Otherwise, +EXPRESSION is true or false and sets exit status. It is one of: + + ( EXPRESSION ) EXPRESSION is true + ! EXPRESSION EXPRESSION is false + EXPRESSION1 -a EXPRESSION2 both EXPRESSION1 and EXPRESSION2 are true + EXPRESSION1 -o EXPRESSION2 either EXPRESSION1 or EXPRESSION2 is true + + -n STRING the length of STRING is nonzero + STRING equivalent to -n STRING + -z STRING the length of STRING is zero + STRING1 = STRING2 the strings are equal + STRING1 != STRING2 the strings are not equal + + INTEGER1 -eq INTEGER2 INTEGER1 is equal to INTEGER2 + INTEGER1 -ge INTEGER2 INTEGER1 is greater than or equal to INTEGER2 + INTEGER1 -gt INTEGER2 INTEGER1 is greater than INTEGER2 + INTEGER1 -le INTEGER2 INTEGER1 is less than or equal to INTEGER2 + INTEGER1 -lt INTEGER2 INTEGER1 is less than INTEGER2 + INTEGER1 -ne INTEGER2 INTEGER1 is not equal to INTEGER2 + + FILE1 -ef FILE2 FILE1 and FILE2 have the same device and inode numbers + FILE1 -nt FILE2 FILE1 is newer (modification date) than FILE2 + FILE1 -ot FILE2 FILE1 is older than FILE2 + + -b FILE FILE exists and is block special + -c FILE FILE exists and is character special + -d FILE FILE exists and is a directory + -e FILE FILE exists + -f FILE FILE exists and is a regular file + -g FILE FILE exists and is set-group-ID + -G FILE FILE exists and is owned by the effective group ID + -h FILE FILE exists and is a symbolic link (same as -L) + -k FILE FILE exists and has its sticky bit set + -L FILE FILE exists and is a symbolic link (same as -h) + -N FILE FILE exists and has been modified since it was last read + -O FILE FILE exists and is owned by the effective user ID + -p FILE FILE exists and is a named pipe + -r FILE FILE exists and read permission is granted + -s FILE FILE exists and has a size greater than zero + -S FILE FILE exists and is a socket + -t FD file descriptor FD is opened on a terminal + -u FILE FILE exists and its set-user-ID bit is set + -w FILE FILE exists and write permission is granted + -x FILE FILE exists and execute (or search) permission is granted + +Except for -h and -L, all FILE-related tests dereference symbolic links. +Beware that parentheses need to be escaped (e.g., by backslashes) for shells. +INTEGER may also be -l STRING, which evaluates to the length of STRING. + +NOTE: Binary -a and -o are inherently ambiguous. Use 'test EXPR1 && test +EXPR2' or 'test EXPR1 || test EXPR2' instead. + +NOTE: [ honors the --help and --version options, but test does not. +test treats each of those as it treats any other nonempty STRING. + +NOTE: your shell may have its own version of test and/or [, which usually supersedes +the version described here. Please refer to your shell's documentation +for details about the options it supports."; + pub fn uu_app() -> App<'static, 'static> { App::new(executable!()) .setting(AppSettings::DisableHelpFlags) @@ -32,6 +101,17 @@ pub fn uumain(mut args: impl uucore::Args) -> i32 { // If invoked via name '[', matching ']' must be in the last arg if binary_name.ends_with('[') { + if args.len() == 1 && (args[0] == "--help" || args[0] == "--version") { + // Let clap pretty-print help and version + App::new(binary_name) + .version(crate_version!()) + .usage(USAGE) + .after_help(AFTER_HELP) + .setting(AppSettings::NeedsLongHelp) + .setting(AppSettings::NeedsLongVersion) + .get_matches_from(std::iter::once(program).chain(args.into_iter())); + return 0; + } let last = args.pop(); if last != Some(OsString::from("]")) { eprintln!("[: missing ']'"); diff --git a/tests/by-util/test_test.rs b/tests/by-util/test_test.rs index 1867927daa9..79c24651a88 100644 --- a/tests/by-util/test_test.rs +++ b/tests/by-util/test_test.rs @@ -718,3 +718,21 @@ fn test_bracket_syntax_missing_right_bracket() { .status_code(2) .stderr_is("[: missing ']'"); } + +#[test] +fn test_bracket_syntax_help() { + let scenario = TestScenario::new("["); + let mut ucmd = scenario.ucmd(); + + ucmd.arg("--help").succeeds().stdout_contains("USAGE:"); +} + +#[test] +fn test_bracket_syntax_version() { + let scenario = TestScenario::new("["); + let mut ucmd = scenario.ucmd(); + + ucmd.arg("--version") + .succeeds() + .stdout_matches(&r"\[ \d+\.\d+\.\d+".parse().unwrap()); +}