From 0a320ea08f02b6f9d34b5b58494c0aed9ccc8850 Mon Sep 17 00:00:00 2001 From: Clara Swanson Date: Tue, 21 Nov 2023 09:34:29 +0100 Subject: [PATCH 1/7] libstdbuf: remove crash macro --- src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs index a29d01b78f3..a0c46523c02 100644 --- a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs +++ b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs @@ -8,7 +8,8 @@ use cpp::cpp; use libc::{c_char, c_int, size_t, FILE, _IOFBF, _IOLBF, _IONBF}; use std::env; use std::ptr; -use uucore::crash; +use uucore::error::USimpleError; +use uucore::show; cpp! {{ #include @@ -38,10 +39,10 @@ fn set_buffer(stream: *mut FILE, value: &str) { "0" => (_IONBF, 0_usize), "L" => (_IOLBF, 0_usize), input => { - let buff_size: usize = match input.parse() { - Ok(num) => num, - Err(e) => crash!(1, "incorrect size of buffer!: {}", e), - }; + let buff_size: usize = input + .parse() + .map_err(|e| format!("incorrect size of buffer!: {}", e)) + .unwrap(); (_IOFBF, buff_size as size_t) } }; @@ -52,7 +53,7 @@ fn set_buffer(stream: *mut FILE, value: &str) { res = libc::setvbuf(stream, buffer, mode, size); } if res != 0 { - crash!(res, "error while calling setvbuf!"); + show!(USimpleError::new(res, "error while calling setvbuf!")); } } From 1761a7de437db04a573dbe2ec738110e1c357ef2 Mon Sep 17 00:00:00 2001 From: Clara Swanson Date: Thu, 23 Nov 2023 07:08:44 +0100 Subject: [PATCH 2/7] libstdbuf: remove uucore macro/struct and use gnu messages --- src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs index a0c46523c02..0d847ec75b6 100644 --- a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs +++ b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs @@ -8,8 +8,6 @@ use cpp::cpp; use libc::{c_char, c_int, size_t, FILE, _IOFBF, _IOLBF, _IONBF}; use std::env; use std::ptr; -use uucore::error::USimpleError; -use uucore::show; cpp! {{ #include @@ -39,10 +37,13 @@ fn set_buffer(stream: *mut FILE, value: &str) { "0" => (_IONBF, 0_usize), "L" => (_IOLBF, 0_usize), input => { - let buff_size: usize = input - .parse() - .map_err(|e| format!("incorrect size of buffer!: {}", e)) - .unwrap(); + let buff_size: usize = match input.parse() { + Ok(num) => num, + Err(_) => { + eprintln!("failed to allocate a {} byte stdio buffer", value); + std::process::exit(1); + } + }; (_IOFBF, buff_size as size_t) } }; @@ -53,7 +54,7 @@ fn set_buffer(stream: *mut FILE, value: &str) { res = libc::setvbuf(stream, buffer, mode, size); } if res != 0 { - show!(USimpleError::new(res, "error while calling setvbuf!")); + eprintln!("could not set buffering of {:?} to mode {}", stream, mode); } } From 28704848274bd834c76b19985a7460ed01293b10 Mon Sep 17 00:00:00 2001 From: Clara Swanson Date: Tue, 21 Nov 2023 09:34:29 +0100 Subject: [PATCH 3/7] libstdbuf: remove crash macro --- src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs index a29d01b78f3..a0c46523c02 100644 --- a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs +++ b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs @@ -8,7 +8,8 @@ use cpp::cpp; use libc::{c_char, c_int, size_t, FILE, _IOFBF, _IOLBF, _IONBF}; use std::env; use std::ptr; -use uucore::crash; +use uucore::error::USimpleError; +use uucore::show; cpp! {{ #include @@ -38,10 +39,10 @@ fn set_buffer(stream: *mut FILE, value: &str) { "0" => (_IONBF, 0_usize), "L" => (_IOLBF, 0_usize), input => { - let buff_size: usize = match input.parse() { - Ok(num) => num, - Err(e) => crash!(1, "incorrect size of buffer!: {}", e), - }; + let buff_size: usize = input + .parse() + .map_err(|e| format!("incorrect size of buffer!: {}", e)) + .unwrap(); (_IOFBF, buff_size as size_t) } }; @@ -52,7 +53,7 @@ fn set_buffer(stream: *mut FILE, value: &str) { res = libc::setvbuf(stream, buffer, mode, size); } if res != 0 { - crash!(res, "error while calling setvbuf!"); + show!(USimpleError::new(res, "error while calling setvbuf!")); } } From 0db8fbbf1d34ca7de06330703bb99b8a0954b353 Mon Sep 17 00:00:00 2001 From: Clara Swanson Date: Thu, 23 Nov 2023 07:08:44 +0100 Subject: [PATCH 4/7] libstdbuf: remove uucore macro/struct and use gnu messages --- src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs index a0c46523c02..0d847ec75b6 100644 --- a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs +++ b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs @@ -8,8 +8,6 @@ use cpp::cpp; use libc::{c_char, c_int, size_t, FILE, _IOFBF, _IOLBF, _IONBF}; use std::env; use std::ptr; -use uucore::error::USimpleError; -use uucore::show; cpp! {{ #include @@ -39,10 +37,13 @@ fn set_buffer(stream: *mut FILE, value: &str) { "0" => (_IONBF, 0_usize), "L" => (_IOLBF, 0_usize), input => { - let buff_size: usize = input - .parse() - .map_err(|e| format!("incorrect size of buffer!: {}", e)) - .unwrap(); + let buff_size: usize = match input.parse() { + Ok(num) => num, + Err(_) => { + eprintln!("failed to allocate a {} byte stdio buffer", value); + std::process::exit(1); + } + }; (_IOFBF, buff_size as size_t) } }; @@ -53,7 +54,7 @@ fn set_buffer(stream: *mut FILE, value: &str) { res = libc::setvbuf(stream, buffer, mode, size); } if res != 0 { - show!(USimpleError::new(res, "error while calling setvbuf!")); + eprintln!("could not set buffering of {:?} to mode {}", stream, mode); } } From be2eab2b6717656af99d689cc2428a4b35a8e6c3 Mon Sep 17 00:00:00 2001 From: Clara Swanson Date: Mon, 27 Nov 2023 18:37:44 +0100 Subject: [PATCH 5/7] libstdbuf: remove :? from print by printing file descriptor instead of file --- src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs index 0d847ec75b6..d744ca4c545 100644 --- a/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs +++ b/src/uu/stdbuf/src/libstdbuf/src/libstdbuf.rs @@ -5,7 +5,7 @@ // spell-checker:ignore (ToDO) IOFBF IOLBF IONBF cstdio setvbuf use cpp::cpp; -use libc::{c_char, c_int, size_t, FILE, _IOFBF, _IOLBF, _IONBF}; +use libc::{c_char, c_int, fileno, size_t, FILE, _IOFBF, _IOLBF, _IONBF}; use std::env; use std::ptr; @@ -54,7 +54,11 @@ fn set_buffer(stream: *mut FILE, value: &str) { res = libc::setvbuf(stream, buffer, mode, size); } if res != 0 { - eprintln!("could not set buffering of {:?} to mode {}", stream, mode); + eprintln!( + "could not set buffering of {} to mode {}", + unsafe { fileno(stream) }, + mode + ); } } From 8823244d4dda33f66e690b3ca2f26f608bb57804 Mon Sep 17 00:00:00 2001 From: Clara Swanson Date: Mon, 27 Nov 2023 18:47:15 +0100 Subject: [PATCH 6/7] merge main into libstdbuf-remove-crash-macro --- .github/workflows/fuzzing.yml | 31 +++-- .../acronyms+names.wordlist.txt | 1 + Cargo.lock | 12 +- Cargo.toml | 2 +- fuzz/Cargo.toml | 7 ++ fuzz/fuzz_targets/fuzz_printf.rs | 110 ++++++++++++++++++ src/uu/expr/src/expr.rs | 6 +- src/uu/expr/src/syntax_tree.rs | 27 ++++- src/uucore/Cargo.toml | 4 +- src/uucore/src/lib/features/fs.rs | 2 + tests/by-util/test_expr.rs | 36 ++++++ 11 files changed, 207 insertions(+), 31 deletions(-) create mode 100644 fuzz/fuzz_targets/fuzz_printf.rs diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index e7a9cb1e329..2274f6905c1 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -37,16 +37,14 @@ jobs: strategy: matrix: test-target: - [ - fuzz_date, - fuzz_test, - fuzz_expr, - fuzz_parse_glob, - fuzz_parse_size, - fuzz_parse_time, - # adding more fuzz tests here. - # e.g. fuzz_test_a, - ] + - { name: fuzz_test, should_pass: true } + # https://github.com/uutils/coreutils/issues/5311 + - { name: fuzz_date, should_pass: false } + - { name: fuzz_expr, should_pass: true } + - { name: fuzz_printf, should_pass: false } + - { name: fuzz_parse_glob, should_pass: true } + - { name: fuzz_parse_size, should_pass: true } + - { name: fuzz_parse_time, should_pass: true } steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@nightly @@ -59,16 +57,17 @@ jobs: - name: Restore Cached Corpus uses: actions/cache/restore@v3 with: - key: corpus-cache-${{ matrix.test-target }} + key: corpus-cache-${{ matrix.test-target.name }} path: | - fuzz/corpus/${{ matrix.test-target }} - - name: Run ${{ matrix.test-target }} for XX seconds + fuzz/corpus/${{ matrix.test-target.name }} + - name: Run ${{ matrix.test-target.name }} for XX seconds shell: bash + continue-on-error: ${{ !matrix.test-target.name.should_pass }} run: | - cargo +nightly fuzz run ${{ matrix.test-target }} -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0 + cargo +nightly fuzz run ${{ matrix.test-target.name }} -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0 - name: Save Corpus Cache uses: actions/cache/save@v3 with: - key: corpus-cache-${{ matrix.test-target }} + key: corpus-cache-${{ matrix.test-target.name }} path: | - fuzz/corpus/${{ matrix.test-target }} + fuzz/corpus/${{ matrix.test-target.name }} diff --git a/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt b/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt index c004ea2f822..4a59ed094bd 100644 --- a/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt +++ b/.vscode/cspell.dictionaries/acronyms+names.wordlist.txt @@ -37,6 +37,7 @@ aarch flac impls lzma +loongarch # * names BusyBox diff --git a/Cargo.lock b/Cargo.lock index c89c87df41c..d7682f839e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,15 +690,15 @@ checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] name = "data-encoding-macro" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c904b33cc60130e1aeea4956ab803d08a3f4a0ca82d64ed757afac3891f2bb99" +checksum = "20c01c06f5f429efdf2bae21eb67c28b3df3cf85b7dd2d8ef09c0838dac5d33e" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -706,9 +706,9 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fdf3fce3ce863539ec1d7fd1b6dcc3c645663376b43ed376bbf887733e4f772" +checksum = "0047d07f2c89b17dd631c80450d69841a6b5d7fb17278cbc43d7e4cfcf2576f3" dependencies = [ "data-encoding", "syn 1.0.109", diff --git a/Cargo.toml b/Cargo.toml index 2f3af2c83d1..ba701b2d5e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -330,7 +330,7 @@ walkdir = "2.4" winapi-util = "0.1.6" windows-sys = { version = "0.48.0", default-features = false } xattr = "1.0.1" -zip = { version = "0.6.6", default_features = false, features = ["deflate"] } +zip = { version = "0.6.6", default-features = false, features = ["deflate"] } hex = "0.4.3" md-5 = "0.10.6" diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 549f9a6b762..630af4650b6 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -16,6 +16,7 @@ uucore = { path = "../src/uucore/" } uu_date = { path = "../src/uu/date/" } uu_test = { path = "../src/uu/test/" } uu_expr = { path = "../src/uu/expr/" } +uu_printf = { path = "../src/uu/printf/" } # Prevent this from interfering with workspaces @@ -28,6 +29,12 @@ path = "fuzz_targets/fuzz_date.rs" test = false doc = false +[[bin]] +name = "fuzz_printf" +path = "fuzz_targets/fuzz_printf.rs" +test = false +doc = false + [[bin]] name = "fuzz_expr" path = "fuzz_targets/fuzz_expr.rs" diff --git a/fuzz/fuzz_targets/fuzz_printf.rs b/fuzz/fuzz_targets/fuzz_printf.rs new file mode 100644 index 00000000000..78bb3e3ce3b --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_printf.rs @@ -0,0 +1,110 @@ +// This file is part of the uutils coreutils package. +// +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. +// spell-checker:ignore parens + +#![no_main] +use libfuzzer_sys::fuzz_target; +use uu_printf::uumain; + +use rand::seq::SliceRandom; +use rand::Rng; +use std::ffi::OsString; + +mod fuzz_common; +use crate::fuzz_common::CommandResult; +use crate::fuzz_common::{ + compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd, +}; + +static CMD_PATH: &str = "printf"; + +fn generate_escape_sequence(rng: &mut impl Rng) -> String { + let escape_sequences = [ + "\\\"", + "\\\\", + "\\a", + "\\b", + "\\c", + "\\e", + "\\f", + "\\n", + "\\r", + "\\t", + "\\v", + "\\000", + "\\x00", + "\\u0000", + "\\U00000000", + "%%", + ]; + escape_sequences.choose(rng).unwrap().to_string() +} + +fn generate_printf() -> String { + let mut rng = rand::thread_rng(); + let format_specifiers = ["%s", "%d", "%f", "%x", "%o", "%c", "%b", "%q"]; + let mut printf_str = String::new(); + // Add a 20% chance of generating an invalid format specifier + if rng.gen_bool(0.2) { + printf_str.push_str("%z"); // Invalid format specifier + } else { + let specifier = *format_specifiers.choose(&mut rng).unwrap(); + printf_str.push_str(specifier); + + // Add a 20% chance of introducing complex format strings + if rng.gen_bool(0.2) { + printf_str.push_str(&format!(" %{}", rng.gen_range(1..=1000))); + } else { + // Add a random string or number after the specifier + if specifier == "%s" { + printf_str.push_str(&format!( + " {}", + generate_random_string(rng.gen_range(1..=10)) + )); + } else { + printf_str.push_str(&format!(" {}", rng.gen_range(1..=1000))); + } + } + } + + // Add a 10% chance of including an escape sequence + if rng.gen_bool(0.1) { + printf_str.push_str(&generate_escape_sequence(&mut rng)); + } + printf_str +} + +fuzz_target!(|_data: &[u8]| { + let printf_input = generate_printf(); + let mut args = vec![OsString::from("printf")]; + args.extend(printf_input.split_whitespace().map(OsString::from)); + let rust_result = generate_and_run_uumain(&args, uumain); + + let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false) { + Ok(result) => result, + Err(error_result) => { + eprintln!("Failed to run GNU command:"); + eprintln!("Stderr: {}", error_result.stderr); + eprintln!("Exit Code: {}", error_result.exit_code); + CommandResult { + stdout: String::new(), + stderr: error_result.stderr, + exit_code: error_result.exit_code, + } + } + }; + + compare_result( + "printf", + &format!("{:?}", &args[1..]), + &rust_result.stdout, + &gnu_result.stdout, + &rust_result.stderr, + &gnu_result.stderr, + rust_result.exit_code, + gnu_result.exit_code, + false, // Set to true if you want to fail on stderr diff + ); +}); diff --git a/src/uu/expr/src/expr.rs b/src/uu/expr/src/expr.rs index ea559090c92..909c4c37653 100644 --- a/src/uu/expr/src/expr.rs +++ b/src/uu/expr/src/expr.rs @@ -5,7 +5,7 @@ use clap::{crate_version, Arg, ArgAction, Command}; use uucore::{ - error::{UResult, USimpleError}, + error::{UResult, USimpleError, UUsageError}, format_usage, help_about, help_section, help_usage, }; @@ -58,6 +58,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .map(|v| v.into_iter().map(|s| s.as_ref()).collect::>()) .unwrap_or_default(); + if token_strings.is_empty() { + return Err(UUsageError::new(2, "missing operand")); + } + match process_expr(&token_strings[..]) { Ok(expr_result) => print_expr_ok(&expr_result), Err(expr_error) => Err(USimpleError::new(2, &expr_error)), diff --git a/src/uu/expr/src/syntax_tree.rs b/src/uu/expr/src/syntax_tree.rs index c55fb0bdc6a..2260b2e2186 100644 --- a/src/uu/expr/src/syntax_tree.rs +++ b/src/uu/expr/src/syntax_tree.rs @@ -13,6 +13,7 @@ use num_bigint::BigInt; use num_traits::Zero; use onig::{Regex, RegexOptions, Syntax}; +use uucore::display::Quotable; use crate::tokens::Token; @@ -256,7 +257,6 @@ fn maybe_dump_rpn(rpn: &TokenStack) { fn ast_from_rpn(rpn: &mut TokenStack) -> Result, String> { match rpn.pop() { None => Err("syntax error (premature end of expression)".to_owned()), - Some((token_idx, Token::Value { value })) => Ok(AstNode::new_leaf(token_idx, &value)), Some((token_idx, Token::InfixOp { value, .. })) => { @@ -331,9 +331,25 @@ fn push_token_to_either_stack( } } - Token::PrefixOp { .. } | Token::ParOpen => { - op_stack.push((token_idx, token.clone())); - Ok(()) + Token::ParOpen => { + if out_stack.is_empty() { + op_stack.push((token_idx, token.clone())); + Ok(()) + } else { + Err("syntax error: unexpected argument '('".to_string()) + } + } + + Token::PrefixOp { value, .. } => { + if out_stack.is_empty() { + op_stack.push((token_idx, token.clone())); + Ok(()) + } else { + Err(format!( + "syntax error: unexpected argument {}", + value.quote() + )) + } } Token::ParClose => move_till_match_paren(out_stack, op_stack), @@ -482,7 +498,8 @@ fn infix_operator_and(values: &[String]) -> String { fn operator_match(values: &[String]) -> Result { assert!(values.len() == 2); - let re = Regex::with_options(&values[1], RegexOptions::REGEX_OPTION_NONE, Syntax::grep()) + let re_string = format!("^{}", &values[1]); + let re = Regex::with_options(&re_string, RegexOptions::REGEX_OPTION_NONE, Syntax::grep()) .map_err(|err| err.description().to_string())?; Ok(if re.captures_len() > 0 { re.captures(&values[0]) diff --git a/src/uucore/Cargo.toml b/src/uucore/Cargo.toml index 370c8a3864c..fabf068bb4d 100644 --- a/src/uucore/Cargo.toml +++ b/src/uucore/Cargo.toml @@ -33,8 +33,8 @@ time = { workspace = true, optional = true, features = [ "macros", ] } # * "problem" dependencies (pinned) -data-encoding = { version = "2.4", optional = true } -data-encoding-macro = { version = "0.1.13", optional = true } +data-encoding = { version = "2.5", optional = true } +data-encoding-macro = { version = "0.1.14", optional = true } z85 = { version = "3.0.5", optional = true } libc = { workspace = true, optional = true } once_cell = { workspace = true } diff --git a/src/uucore/src/lib/features/fs.rs b/src/uucore/src/lib/features/fs.rs index f8593dfede5..de4c0b08dbe 100644 --- a/src/uucore/src/lib/features/fs.rs +++ b/src/uucore/src/lib/features/fs.rs @@ -119,6 +119,7 @@ impl FileInformation { not(target_os = "solaris"), not(target_arch = "aarch64"), not(target_arch = "riscv64"), + not(target_arch = "loongarch64"), target_pointer_width = "64" ))] return self.0.st_nlink; @@ -133,6 +134,7 @@ impl FileInformation { target_os = "solaris", target_arch = "aarch64", target_arch = "riscv64", + target_arch = "loongarch64", not(target_pointer_width = "64") ) ))] diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index 28cfcf0ec90..ebc2c832feb 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -6,6 +6,14 @@ use crate::common::util::TestScenario; +#[test] +fn test_no_arguments() { + new_ucmd!() + .fails() + .code_is(2) + .usage_error("missing operand"); +} + #[test] fn test_simple_values() { // null or 0 => EXIT_VALUE == 1 @@ -100,6 +108,12 @@ fn test_parenthesis() { .args(&["(", "1", "+", "1", ")", "*", "2"]) .succeeds() .stdout_only("4\n"); + + new_ucmd!() + .args(&["1", "(", ")"]) + .fails() + .code_is(2) + .stderr_only("expr: syntax error: unexpected argument '('\n"); } #[test] @@ -221,6 +235,12 @@ fn test_index() { .args(&["index", "αbcdef_f", "f"]) .succeeds() .stdout_only("6\n"); + + new_ucmd!() + .args(&["αbcdef", "index", "α"]) + .fails() + .code_is(2) + .stderr_only("expr: syntax error: unexpected argument 'index'\n"); } #[test] @@ -234,6 +254,12 @@ fn test_length() { .args(&["length", "abcdef"]) .succeeds() .stdout_only("6\n"); + + new_ucmd!() + .args(&["abcdef", "length"]) + .fails() + .code_is(2) + .stderr_only("expr: syntax error: unexpected argument 'length'\n"); } #[test] @@ -263,6 +289,10 @@ fn test_regex() { .args(&["-5", ":", "-\\{0,1\\}[0-9]*$"]) .succeeds() .stdout_only("2\n"); + new_ucmd!() + .args(&["abc", ":", "bc"]) + .fails() + .stdout_only("0\n"); } #[test] @@ -271,6 +301,12 @@ fn test_substr() { .args(&["substr", "abc", "1", "1"]) .succeeds() .stdout_only("a\n"); + + new_ucmd!() + .args(&["abc", "substr", "1", "1"]) + .fails() + .code_is(2) + .stderr_only("expr: syntax error: unexpected argument 'substr'\n"); } #[test] From 05c30b104a5bd422344010991bca1b52712ff1b5 Mon Sep 17 00:00:00 2001 From: Clara Swanson Date: Tue, 28 Nov 2023 13:34:58 +0100 Subject: [PATCH 7/7] libstdbuf: remove uucore from dependencies --- Cargo.lock | 1 - src/uu/stdbuf/src/libstdbuf/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7682f839e4..c6de350c9bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2952,7 +2952,6 @@ dependencies = [ "cpp", "cpp_build", "libc", - "uucore", ] [[package]] diff --git a/src/uu/stdbuf/src/libstdbuf/Cargo.toml b/src/uu/stdbuf/src/libstdbuf/Cargo.toml index be97c47aeaf..eaa82e6e73d 100644 --- a/src/uu/stdbuf/src/libstdbuf/Cargo.toml +++ b/src/uu/stdbuf/src/libstdbuf/Cargo.toml @@ -22,7 +22,6 @@ crate-type = [ [dependencies] cpp = "0.5" libc = { workspace = true } -uucore = { version = ">=0.0.19", package = "uucore", path = "../../../../uucore" } [build-dependencies] cpp_build = "0.5"