From 985ac3b38175b6979bf3761c3d1d4a6f0a24ce2c Mon Sep 17 00:00:00 2001 From: Dorian Peron Date: Tue, 25 Feb 2025 01:14:31 +0100 Subject: [PATCH 1/2] test(expr): Add GNU tests to rust testsuite --- tests/by-util/test_expr.rs | 878 +++++++++++++++++++++++++++++++++++++ 1 file changed, 878 insertions(+) diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index a7f4b0cd9..aff5596da 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -3,6 +3,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore αbcdef ; (people) kkos +// spell-checker:ignore aabcccd aabcd aabd abbbd abbcabc abbcac abbcbbbd abbcbd +// spell-checker:ignore abbccd abcac acabc andand bigcmp bignum emptysub +// spell-checker:ignore orempty oror use crate::common::util::TestScenario; @@ -364,3 +367,878 @@ fn test_eager_evaluation() { .fails() .stderr_contains("division by zero"); } + +/// Regroup the testcases of the GNU test expr.pl +mod gnu_expr { + use crate::common::util::TestScenario; + + #[test] + fn test_a() { + new_ucmd!() + .args(&["5", "+", "6"]) + .succeeds() + .stdout_only("11\n"); + } + + #[test] + fn test_b() { + new_ucmd!() + .args(&["5", "-", "6"]) + .succeeds() + .stdout_only("-1\n"); + } + + #[test] + fn test_c() { + new_ucmd!() + .args(&["5", "*", "6"]) + .succeeds() + .stdout_only("30\n"); + } + + #[test] + fn test_d() { + new_ucmd!() + .args(&["100", "/", "6"]) + .succeeds() + .stdout_only("16\n"); + } + + #[test] + fn test_e() { + new_ucmd!() + .args(&["100", "%", "6"]) + .succeeds() + .stdout_only("4\n"); + } + + #[test] + fn test_f() { + new_ucmd!() + .args(&["3", "+", "-2"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_g() { + new_ucmd!() + .args(&["-2", "+", "-2"]) + .succeeds() + .stdout_only("-4\n"); + } + + #[test] + fn test_opt1() { + new_ucmd!() + .args(&["--", "-11", "+", "12"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_opt2() { + new_ucmd!() + .args(&["-11", "+", "12"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_opt3() { + new_ucmd!() + .args(&["--", "-1", "+", "2"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_opt4() { + new_ucmd!() + .args(&["-1", "+", "2"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_opt5() { + new_ucmd!() + .args(&["--", "2", "+", "2"]) + .succeeds() + .stdout_only("4\n"); + } + + #[test] + fn test_paren1() { + new_ucmd!() + .args(&["(", "100", "%", "6", ")"]) + .succeeds() + .stdout_only("4\n"); + } + + #[test] + fn test_paren2() { + new_ucmd!() + .args(&["(", "100", "%", "6", ")", "-", "8"]) + .succeeds() + .stdout_only("-4\n"); + } + + #[test] + fn test_paren3() { + new_ucmd!() + .args(&["9", "/", "(", "100", "%", "6", ")", "-", "8"]) + .succeeds() + .stdout_only("-6\n"); + } + + #[test] + fn test_paren4() { + new_ucmd!() + .args(&["9", "/", "(", "(", "100", "%", "6", ")", "-", "8", ")"]) + .succeeds() + .stdout_only("-2\n"); + } + + #[test] + fn test_paren5() { + new_ucmd!() + .args(&["9", "+", "(", "100", "%", "6", ")"]) + .succeeds() + .stdout_only("13\n"); + } + + #[test] + fn test_0bang() { + new_ucmd!() + .args(&["00", "<", "0!"]) + .fails() + .code_is(1) + .stdout_only("0\n"); + } + + #[test] + fn test_00() { + new_ucmd!() + .args(&["00"]) + .fails() + .code_is(1) + .stdout_only("00\n"); + } + + #[test] + fn test_minus0() { + new_ucmd!() + .args(&["-0"]) + .fails() + .code_is(1) + .stdout_only("-0\n"); + } + + #[test] + fn test_andand() { + new_ucmd!() + .args(&["0", "&", "1", "/", "0"]) + .fails() + .code_is(1) + .stdout_only("0\n"); + } + + #[test] + fn test_oror() { + new_ucmd!() + .args(&["1", "|", "1", "/", "0"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_orempty() { + new_ucmd!() + .args(&["", "|", ""]) + .fails() + .code_is(1) + .stdout_only("0\n"); + } + + #[test] + fn test_fail_a() { + new_ucmd!() + .args(&["3", "+", "-"]) + .fails() + .code_is(2) + .no_stdout() + .stderr_contains("non-integer argument"); + } + + #[test] + fn test_bigcmp() { + new_ucmd!() + .args(&[ + "--", + "-2417851639229258349412352", + "<", + "2417851639229258349412352", + ]) + .succeeds() + .stdout_only("1\n"); + } + + #[ignore] + #[test] + fn test_anchor() { + new_ucmd!() + .args(&["a\nb", ":", "a$"]) + .fails() + .code_is(1) + .stdout_only("0\n"); + } + + #[test] + fn test_emptysub() { + new_ucmd!() + .args(&["a", ":", "\\(b\\)*"]) + .fails() + .code_is(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre1() { + new_ucmd!() + .args(&["abc", ":", "a\\(b\\)c"]) + .succeeds() + .stdout_only("b\n"); + } + + #[test] + fn test_bre2() { + new_ucmd!() + .args(&["a(", ":", "a("]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre3() { + new_ucmd!() + .args(&["_", ":", "a\\("]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Unmatched ( or \\("); + } + + #[test] + fn test_bre4() { + new_ucmd!() + .args(&["_", ":", "a\\(b"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Unmatched ( or \\("); + } + + #[test] + fn test_bre5() { + new_ucmd!() + .args(&["a(b", ":", "a(b"]) + .succeeds() + .stdout_only("3\n"); + } + + #[test] + fn test_bre6() { + new_ucmd!() + .args(&["a)", ":", "a)"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre7() { + new_ucmd!() + .args(&["_", ":", "a\\)"]) + .fails_with_code(2) + .stderr_contains("Unmatched ) or \\)"); + } + + #[test] + fn test_bre8() { + new_ucmd!() + .args(&["_", ":", "\\)"]) + .fails_with_code(2) + .stderr_contains("Unmatched ) or \\)"); + } + + #[test] + fn test_bre9() { + new_ucmd!() + .args(&["ab", ":", "a\\(\\)b"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[ignore] + #[test] + fn test_bre10() { + new_ucmd!() + .args(&["a^b", ":", "a^b"]) + .succeeds() + .stdout_only("3\n"); + } + + #[ignore] + #[test] + fn test_bre11() { + new_ucmd!() + .args(&["a$b", ":", "a$b"]) + .succeeds() + .stdout_only("3\n"); + } + + #[test] + fn test_bre12() { + new_ucmd!() + .args(&["", ":", "\\($\\)\\(^\\)"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre13() { + new_ucmd!() + .args(&["b", ":", "a*\\(b$\\)c*"]) + .succeeds() + .stdout_only("b\n"); + } + + #[test] + fn test_bre14() { + new_ucmd!() + .args(&["X|", ":", "X\\(|\\)", ":", "(", "X|", ":", "X\\(|\\)", ")"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_bre15() { + new_ucmd!() + .args(&["X*", ":", "X\\(*\\)", ":", "(", "X*", ":", "X\\(*\\)", ")"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_bre16() { + new_ucmd!() + .args(&["abc", ":", "\\(\\)"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[ignore] + #[test] + fn test_bre17() { + new_ucmd!() + .args(&["{1}a", ":", "\\(\\{1\\}a\\)"]) + .succeeds() + .stdout_only("{1}a\n"); + } + + #[ignore] + #[test] + fn test_bre18() { + new_ucmd!() + .args(&["X*", ":", "X\\(*\\)", ":", "^*"]) + .succeeds() + .stdout_only("1\n"); + } + + #[ignore] + #[test] + fn test_bre19() { + new_ucmd!() + .args(&["{1}", ":", "\\{1\\}"]) + .succeeds() + .stdout_only("3\n"); + } + + #[test] + fn test_bre20() { + new_ucmd!() + .args(&["{", ":", "{"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_bre21() { + new_ucmd!() + .args(&["abbcbd", ":", "a\\(b*\\)c\\1d"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre22() { + new_ucmd!() + .args(&["abbcbbbd", ":", "a\\(b*\\)c\\1d"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre23() { + new_ucmd!() + .args(&["abc", ":", "\\(.\\)\\1"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre24() { + new_ucmd!() + .args(&["abbccd", ":", "a\\(\\([bc]\\)\\2\\)*d"]) + .succeeds() + .stdout_only("cc\n"); + } + + #[test] + fn test_bre25() { + new_ucmd!() + .args(&["abbcbd", ":", "a\\(\\([bc]\\)\\2\\)*d"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre26() { + new_ucmd!() + .args(&["abbbd", ":", "a\\(\\(b\\)*\\2\\)*d"]) + .succeeds() + .stdout_only("bbb\n"); + } + + #[test] + fn test_bre27() { + new_ucmd!() + .args(&["aabcd", ":", "\\(a\\)\\1bcd"]) + .succeeds() + .stdout_only("a\n"); + } + + #[test] + fn test_bre28() { + new_ucmd!() + .args(&["aabcd", ":", "\\(a\\)\\1bc*d"]) + .succeeds() + .stdout_only("a\n"); + } + + #[test] + fn test_bre29() { + new_ucmd!() + .args(&["aabd", ":", "\\(a\\)\\1bc*d"]) + .succeeds() + .stdout_only("a\n"); + } + + #[test] + fn test_bre30() { + new_ucmd!() + .args(&["aabcccd", ":", "\\(a\\)\\1bc*d"]) + .succeeds() + .stdout_only("a\n"); + } + + #[test] + fn test_bre31() { + new_ucmd!() + .args(&["aabcccd", ":", "\\(a\\)\\1bc*[ce]d"]) + .succeeds() + .stdout_only("a\n"); + } + + #[test] + fn test_bre32() { + new_ucmd!() + .args(&["aabcccd", ":", "\\(a\\)\\1b\\(c\\)*cd"]) + .succeeds() + .stdout_only("a\n"); + } + + #[test] + fn test_bre33() { + new_ucmd!() + .args(&["a*b", ":", "a\\(*\\)b"]) + .succeeds() + .stdout_only("*\n"); + } + + #[test] + fn test_bre34() { + new_ucmd!() + .args(&["ab", ":", "a\\(**\\)b"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre35() { + new_ucmd!() + .args(&["ab", ":", "a\\(***\\)b"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre36() { + new_ucmd!() + .args(&["*a", ":", "*a"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre37() { + new_ucmd!() + .args(&["a", ":", "**a"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_bre38() { + new_ucmd!() + .args(&["a", ":", "***a"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_bre39() { + new_ucmd!() + .args(&["ab", ":", "a\\{1\\}b"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre40() { + new_ucmd!() + .args(&["ab", ":", "a\\{1,\\}b"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre41() { + new_ucmd!() + .args(&["aab", ":", "a\\{1,2\\}b"]) + .succeeds() + .stdout_only("3\n"); + } + + #[test] + fn test_bre42() { + new_ucmd!() + .args(&["_", ":", "a\\{1"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Unmatched \\{"); + } + + #[test] + fn test_bre43() { + new_ucmd!() + .args(&["_", ":", "a\\{1a"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Unmatched \\{"); + } + + #[test] + fn test_bre44() { + new_ucmd!() + .args(&["_", ":", "a\\{1a\\}"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Invalid content of \\{\\}"); + } + + #[ignore] + #[test] + fn test_bre45() { + new_ucmd!() + .args(&["a", ":", "a\\{,2\\}"]) + .succeeds() + .stdout_only("1\n"); + } + + #[ignore] + #[test] + fn test_bre46() { + new_ucmd!() + .args(&["a", ":", "a\\{,\\}"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_bre47() { + new_ucmd!() + .args(&["_", ":", "a\\{1,x\\}"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Invalid content of \\{\\}"); + } + + #[test] + fn test_bre48() { + new_ucmd!() + .args(&["_", ":", "a\\{1,x"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Unmatched \\{"); + } + + #[test] + fn test_bre49() { + new_ucmd!() + .args(&["_", ":", "a\\{32768\\}"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Invalid content of \\{\\}"); + } + + #[test] + fn test_bre50() { + new_ucmd!() + .args(&["_", ":", "a\\{1,0\\}"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("Invalid content of \\{\\}"); + } + + #[test] + fn test_bre51() { + new_ucmd!() + .args(&["acabc", ":", ".*ab\\{0,0\\}c"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre52() { + new_ucmd!() + .args(&["abcac", ":", "ab\\{0,1\\}c"]) + .succeeds() + .stdout_only("3\n"); + } + + #[test] + fn test_bre53() { + new_ucmd!() + .args(&["abbcac", ":", "ab\\{0,3\\}c"]) + .succeeds() + .stdout_only("4\n"); + } + + #[test] + fn test_bre54() { + new_ucmd!() + .args(&["abcac", ":", ".*ab\\{1,1\\}c"]) + .succeeds() + .stdout_only("3\n"); + } + + #[test] + fn test_bre55() { + new_ucmd!() + .args(&["abcac", ":", ".*ab\\{1,3\\}c"]) + .succeeds() + .stdout_only("3\n"); + } + + #[test] + fn test_bre56() { + new_ucmd!() + .args(&["abbcabc", ":", ".*ab\\{2,2\\}c"]) + .succeeds() + .stdout_only("4\n"); + } + + #[test] + fn test_bre57() { + new_ucmd!() + .args(&["abbcabc", ":", ".*ab\\{2,4\\}c"]) + .succeeds() + .stdout_only("4\n"); + } + + #[test] + fn test_bre58() { + new_ucmd!() + .args(&["aa", ":", "a\\{1\\}\\{1\\}"]) + .succeeds() + .stdout_only("1\n"); + } + + #[test] + fn test_bre59() { + new_ucmd!() + .args(&["aa", ":", "a*\\{1\\}"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre60() { + new_ucmd!() + .args(&["aa", ":", "a\\{1\\}*"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_bre61() { + new_ucmd!() + .args(&["acd", ":", "a\\(b\\)?c\\1d"]) + .fails_with_code(1) + .stdout_only("\n"); + } + + #[test] + fn test_bre62() { + new_ucmd!() + .args(&["--", "-5", ":", "-\\{0,1\\}[0-9]*$"]) + .succeeds() + .stdout_only("2\n"); + } + + #[test] + fn test_fail_c() { + new_ucmd!() + .args::<&str>(&[]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("missing operand") + .stderr_contains("Try") + .stderr_contains("for more information"); + } + + const BIG: &str = "98782897298723498732987928734"; + const BIG_P1: &str = "98782897298723498732987928735"; + const BIG_SUM: &str = "197565794597446997465975857469"; + const BIG_PROD: &str = "9758060798730154302876482828124348356960410232492450771490"; + + #[test] + fn test_bignum_add() { + new_ucmd!() + .args(&[BIG, "+", "1"]) + .succeeds() + .stdout_only(format!("{BIG_P1}\n")); + } + + #[test] + fn test_bignum_add1() { + new_ucmd!() + .args(&[BIG, "+", BIG_P1]) + .succeeds() + .stdout_only(format!("{BIG_SUM}\n")); + } + + #[test] + fn test_bignum_sub() { + new_ucmd!() + .args(&[BIG_P1, "-", "1"]) + .succeeds() + .stdout_only(format!("{BIG}\n")); + } + + #[test] + fn test_bignum_sub1() { + new_ucmd!() + .args(&[BIG_SUM, "-", BIG]) + .succeeds() + .stdout_only(format!("{BIG_P1}\n")); + } + + #[test] + fn test_bignum_mul() { + new_ucmd!() + .args(&[BIG_P1, "*", BIG]) + .succeeds() + .stdout_only(format!("{BIG_PROD}\n")); + } + + #[test] + fn test_bignum_div() { + new_ucmd!() + .args(&[BIG_PROD, "/", BIG]) + .succeeds() + .stdout_only(format!("{BIG_P1}\n")); + } + + #[test] + fn test_se0() { + new_ucmd!() + .args(&["9", "9"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("syntax error: unexpected argument '9'"); + } + + #[test] + fn test_se1() { + new_ucmd!() + .args(&["2", "a"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("syntax error: unexpected argument 'a'"); + } + + #[test] + fn test_se2() { + new_ucmd!() + .args(&["2", "+"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("syntax error: missing argument after '+'"); + } + + #[test] + fn test_se3() { + new_ucmd!() + .args(&["2", ":"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("syntax error: missing argument after ':'"); + } + + #[test] + fn test_se4() { + new_ucmd!() + .args(&["length"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("syntax error: missing argument after 'length'"); + } + + #[test] + fn test_se5() { + new_ucmd!() + .args(&["(", "2"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("syntax error: expecting ')' after '2'"); + } + + #[test] + fn test_se6() { + new_ucmd!() + .args(&["(", "2", "a"]) + .fails_with_code(2) + .no_stdout() + .stderr_contains("syntax error: expecting ')' instead of 'a'"); + } +} From a9d8eed217b463abf18c32570b621b09acec4286 Mon Sep 17 00:00:00 2001 From: Dorian Peron Date: Tue, 25 Feb 2025 01:23:28 +0100 Subject: [PATCH 2/2] expr: Remove useless arg in enum variant --- src/uu/expr/src/expr.rs | 4 ++-- src/uu/expr/src/syntax_tree.rs | 18 +++++++++--------- tests/by-util/test_expr.rs | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/uu/expr/src/expr.rs b/src/uu/expr/src/expr.rs index 99ae27e4a..bfa647902 100644 --- a/src/uu/expr/src/expr.rs +++ b/src/uu/expr/src/expr.rs @@ -48,8 +48,8 @@ pub enum ExprError { UnmatchedOpeningBrace, #[error("Unmatched ) or \\}}")] UnmatchedClosingBrace, - #[error("Invalid content of {0}")] - InvalidContent(String), + #[error("Invalid content of \\{{\\}}")] + InvalidBracketContent, } impl UError for ExprError { diff --git a/src/uu/expr/src/syntax_tree.rs b/src/uu/expr/src/syntax_tree.rs index 149f24bb2..d7ac02ca3 100644 --- a/src/uu/expr/src/syntax_tree.rs +++ b/src/uu/expr/src/syntax_tree.rs @@ -264,7 +264,7 @@ fn check_posix_regex_errors(pattern: &str) -> ExprResult<()> { (true, true, false) => Ok(()), (_, false, _) => Err(ExprError::UnmatchedOpeningBrace), (false, _, _) => Err(ExprError::UnmatchedOpeningParenthesis), - (true, true, true) => Err(ExprError::InvalidContent(r"\{\}".to_string())), + (true, true, true) => Err(ExprError::InvalidBracketContent), } } @@ -601,7 +601,7 @@ pub fn is_truthy(s: &NumOrStr) -> bool { #[cfg(test)] mod test { use crate::ExprError; - use crate::ExprError::InvalidContent; + use crate::ExprError::InvalidBracketContent; use super::{check_posix_regex_errors, AstNode, BinOp, NumericOp, RelationOp, StringOp}; @@ -795,7 +795,7 @@ mod test { fn check_regex_empty_repeating_pattern() { assert_eq!( check_posix_regex_errors("ab\\{\\}"), - Err(InvalidContent(r"\{\}".to_string())) + Err(InvalidBracketContent) ) } @@ -804,27 +804,27 @@ mod test { assert_eq!( // out of order check_posix_regex_errors("ab\\{1,0\\}"), - Err(InvalidContent(r"\{\}".to_string())) + Err(InvalidBracketContent) ); assert_eq!( check_posix_regex_errors("ab\\{1,a\\}"), - Err(InvalidContent(r"\{\}".to_string())) + Err(InvalidBracketContent) ); assert_eq!( check_posix_regex_errors("ab\\{a,3\\}"), - Err(InvalidContent(r"\{\}".to_string())) + Err(InvalidBracketContent) ); assert_eq!( check_posix_regex_errors("ab\\{a,b\\}"), - Err(InvalidContent(r"\{\}".to_string())) + Err(InvalidBracketContent) ); assert_eq!( check_posix_regex_errors("ab\\{a,\\}"), - Err(InvalidContent(r"\{\}".to_string())) + Err(InvalidBracketContent) ); assert_eq!( check_posix_regex_errors("ab\\{,b\\}"), - Err(InvalidContent(r"\{\}".to_string())) + Err(InvalidBracketContent) ); } } diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index aff5596da..ced4c3bbb 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -677,7 +677,7 @@ mod gnu_expr { .stdout_only("\n"); } - #[ignore] + #[ignore = "rust-onig bug, see https://github.com/rust-onig/rust-onig/issues/188"] #[test] fn test_bre10() { new_ucmd!()