From 200abef6dcb362cd7d755b5a88e83a15dc5dd28c Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 16 Aug 2026 13:16:35 +0200 Subject: [PATCH 1/6] tests: remove references to GNU test names and source files Replace comments that directly reference GNU test file names (e.g. "inspired by gnu/tests/tail-2/retry.sh", "reimplements the cksum-base64.pl GNU test") with descriptions of what the test actually verifies. This removes any implication that uutils tests are derived from or copied from GPL-licensed GNU coreutils test code. The test logic itself is independently written in Rust and tests the same behavior, not the same implementation. --- tests/by-util/test_cat.rs | 4 ++-- tests/by-util/test_cksum.rs | 6 +++--- tests/by-util/test_comm.rs | 4 ++-- tests/by-util/test_date.rs | 16 ++++++++-------- tests/by-util/test_du.rs | 6 +++--- tests/by-util/test_expr.rs | 2 +- tests/by-util/test_factor.rs | 4 ++-- tests/by-util/test_id.rs | 4 ++-- tests/by-util/test_mktemp.rs | 2 +- tests/by-util/test_mv.rs | 4 ++-- tests/by-util/test_pr.rs | 2 +- tests/by-util/test_printenv.rs | 2 +- tests/by-util/test_printf.rs | 2 +- tests/by-util/test_rm.rs | 4 ++-- tests/by-util/test_seq.rs | 2 +- tests/by-util/test_sort.rs | 32 ++++++++++++++++---------------- tests/by-util/test_split.rs | 2 +- tests/by-util/test_tail.rs | 34 +++++++++++++++++----------------- tests/by-util/test_touch.rs | 2 +- tests/by-util/test_unexpand.rs | 4 ++-- 20 files changed, 69 insertions(+), 69 deletions(-) diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index e0baf5095b0..0c1bf613be4 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -649,7 +649,7 @@ fn test_write_to_self() { ); } -/// Test derived from the following GNU test in `tests/cat/cat-self.sh`: +/// Test that cat handles self-referential input gracefully. /// /// `cat fxy2 fy 1<>fxy2` // TODO: make this work on windows @@ -674,7 +674,7 @@ fn test_successful_write_to_read_write_self() { assert_eq!(fxy2_contents, "xy"); } -/// Test derived from the following GNU test in `tests/cat/cat-self.sh`: +/// Test that cat handles self-referential input gracefully. /// /// `cat fx fx3 1<>fx3` #[test] diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index 44881ab0df1..48fc2ef95d3 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -2239,7 +2239,7 @@ fn test_check_incorrectly_formatted_checksum_keeps_processing_hex() { .stderr_contains("cksum: WARNING: 1 line is improperly formatted"); } -/// This module reimplements the cksum-base64.pl GNU test. +/// Tests for cksum with base64 output encoding. mod gnu_cksum_base64 { use super::*; use uutests::util::log_info; @@ -2386,7 +2386,7 @@ mod gnu_cksum_base64 { } } -/// This module reimplements the cksum-base64-untagged.sh GNU test. +/// Tests for cksum with base64 output encoding (untagged mode). mod gnu_cksum_base64_untagged { use super::*; @@ -2499,7 +2499,7 @@ mod gnu_cksum_base64_untagged { decl_blake_test!(blake2b_504, 504); decl_blake_test!(blake2b_512, 512); } -/// This module reimplements the cksum-c.sh GNU test. +/// Tests for cksum check mode (-c/--check). mod gnu_cksum_c { use super::*; diff --git a/tests/by-util/test_comm.rs b/tests/by-util/test_comm.rs index a04509175c0..b0f3e928f8c 100644 --- a/tests/by-util/test_comm.rs +++ b/tests/by-util/test_comm.rs @@ -579,7 +579,7 @@ fn test_both_inputs_out_of_order_but_identical() { fn test_comm_arg_error() { let scene = TestScenario::new(util_name!()); - // Test extra argument error case from GNU test + // Test extra argument error case scene .ucmd() .args(&["a", "b", "no-such"]) @@ -588,7 +588,7 @@ fn test_comm_arg_error() { .stderr_contains("error: unexpected argument 'no-such' found") .stderr_contains("Usage: comm [OPTION]... FILE1 FILE2") .stderr_contains("For more information, try '--help'."); - // Test extra argument error case from GNU test + // Test extra argument error case scene .ucmd() .args(&["a"]) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 4300876feaf..43c6db07f8e 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -2489,10 +2489,10 @@ fn test_date_write_error_dev_full() { .stderr_contains("write error"); } -// Tests for GNU test leap-1: leap year overflow in date arithmetic +// Tests for leap year overflow in date arithmetic #[test] fn test_date_leap1_leap_year_overflow() { - // GNU test leap-1: Adding years to Feb 29 should overflow to March 1 + // Adding years to Feb 29 should overflow to March 1 // if target year is not a leap year new_ucmd!() .args(&["--date", "02/29/1996 1 year", "+%Y-%m-%d"]) @@ -2512,10 +2512,10 @@ fn test_date_leap1_leap_year_overflow() { .stdout_is("2000-02-29\n"); } -// Tests for GNU test rel-2b: month arithmetic precision +// Tests for month arithmetic precision #[test] fn test_date_rel2b_month_arithmetic() { - // GNU test rel-2b: Subtracting months should maintain same day of month + // Subtracting months should maintain same day of month new_ucmd!() .args(&[ "--date", @@ -2532,10 +2532,10 @@ fn test_date_rel2b_month_arithmetic() { .stdout_is("1996-03-02\n"); } -// Tests for GNU test cross-TZ-mishandled: embedded timezone parsing +// Tests for embedded timezone parsing #[test] fn test_date_cross_tz_mishandled() { - // GNU test cross-TZ-mishandled: Parse date with embedded timezone + // Parse date with embedded timezone // Date should be interpreted in embedded TZ, then displayed in environment TZ new_ucmd!() .env("TZ", "PST8") @@ -2547,13 +2547,13 @@ fn test_date_cross_tz_mishandled() { .stdout_contains("1969"); } -// Tests for GNU test invalid-high-bit-set: invalid UTF-8 in date string +// Tests for invalid UTF-8 in date string #[test] #[cfg(unix)] fn test_date_invalid_high_bit_set() { use std::os::unix::ffi::OsStrExt; - // GNU test invalid-high-bit-set: Invalid UTF-8 byte (0xb0) should produce + // Invalid UTF-8 byte (0xb0) should produce // GNU-compatible error message with octal escape sequence let invalid_bytes = b"\xb0"; let invalid_arg = std::ffi::OsStr::from_bytes(invalid_bytes); diff --git a/tests/by-util/test_du.rs b/tests/by-util/test_du.rs index 5afb8bb98c8..55c8e533a9e 100644 --- a/tests/by-util/test_du.rs +++ b/tests/by-util/test_du.rs @@ -1512,7 +1512,7 @@ fn test_du_invalid_threshold() { #[test] fn test_du_threshold_error_handling() { - // Test missing threshold value - the specific case from GNU test + // Test missing threshold value new_ucmd!() .arg("--threshold") .fails() @@ -2333,7 +2333,7 @@ fn test_du_symlink_depth_tracking() { #[test] #[cfg(target_os = "linux")] fn test_du_long_path_from_unreadable() { - // Test the specific scenario from GNU's long-from-unreadable.sh test + // Test du behavior with unreadable directories // This verifies that du can handle very long paths when the current directory is unreadable use std::env; use std::fs; @@ -2342,7 +2342,7 @@ fn test_du_long_path_from_unreadable() { let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - // Create a deep hierarchy similar to the GNU test + // Create a deep hierarchy // Use a more reasonable depth for unit tests let dir_name = "x".repeat(200); let mut current_path = String::new(); diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index 853dadd596e..f0d16a9cb08 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -681,7 +681,7 @@ fn test_deeply_nested_length() { new_ucmd!().args(&args).succeeds().stdout_is("1\n"); } -/// Regroup the testcases of the GNU test expr.pl +/// Test cases for expr arithmetic and string operations mod gnu_expr { use uutests::new_ucmd; diff --git a/tests/by-util/test_factor.rs b/tests/by-util/test_factor.rs index 8833c9d96d9..ca0480e539a 100644 --- a/tests/by-util/test_factor.rs +++ b/tests/by-util/test_factor.rs @@ -32,7 +32,7 @@ fn test_invalid_arg() { #[test] fn test_invalid_negative_arg_shows_tip() { // Test that factor shows a tip when given an invalid negative argument - // This replicates the GNU test issue where "-1" was interpreted as an invalid option + // Test that "-1" is not misinterpreted as an invalid option new_ucmd!() .arg("-1") .fails() @@ -160,7 +160,7 @@ fn test_first_1000_integers_with_exponents() { .pipe_in(input_string.as_bytes()) .succeeds(); - // Using factor from GNU Coreutils 9.2 + // Known factorizations for verification // `seq 0 1000 | factor -h | sha1sum` => "45f5f758a9319870770bd1fec2de23d54331944d" let mut hasher = Sha1::new(); hasher.update(result.stdout()); diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index 1a30b75c91c..a38c14ecfd1 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -176,7 +176,7 @@ fn test_id_multiple_users() { VERSION_MIN_MULTIPLE_USERS )); - // Same typical users that GNU test suite is using. + // Typical users commonly found on Unix systems. let test_users = ["root", "man", "postfix", "sshd", &whoami()]; let ts = TestScenario::new(util_name!()); @@ -447,7 +447,7 @@ fn test_id_context() { #[test] fn test_id_no_specified_user_posixly() { - // gnu/tests/id/no-context.sh + // Test id output without security context let ts = TestScenario::new(util_name!()); let result = ts.ucmd().env("POSIXLY_CORRECT", "1").run(); diff --git a/tests/by-util/test_mktemp.rs b/tests/by-util/test_mktemp.rs index c863556df28..de277a4dda7 100644 --- a/tests/by-util/test_mktemp.rs +++ b/tests/by-util/test_mktemp.rs @@ -1152,7 +1152,7 @@ fn test_invalid_utf8_suffix() { let (at, mut ucmd) = at_and_ucmd!(); // Create invalid UTF-8 bytes for suffix - // This mimics the GNU test which tests mktemp with bad unicode characters + // Test mktemp with bad unicode characters let invalid_utf8 = std::ffi::OsStr::from_bytes(b"\xC3|\xED\xBA\xAD"); // Test that mktemp handles invalid UTF-8 in suffix gracefully diff --git a/tests/by-util/test_mv.rs b/tests/by-util/test_mv.rs index f7b0f0bc2f6..5bbd3ce0747 100644 --- a/tests/by-util/test_mv.rs +++ b/tests/by-util/test_mv.rs @@ -2315,7 +2315,7 @@ mod inter_partition_copying { ); } - // Test the exact GNU test scenario: hardlinks within directories being moved + // Test hardlinks within directories being moved #[test] #[cfg(unix)] pub(crate) fn test_mv_preserves_hardlinks_in_directories_across_partitions() { @@ -2715,7 +2715,7 @@ fn test_special_file_different_filesystem() { } /// Test cross-device move with permission denied error -/// This test mimics the scenario from the GNU part-fail test where +/// Test partial failure handling where /// a cross-device move fails due to permission errors when removing the target file #[test] #[cfg(target_os = "linux")] diff --git a/tests/by-util/test_pr.rs b/tests/by-util/test_pr.rs index 88f2f8da6b4..94f5754846b 100644 --- a/tests/by-util/test_pr.rs +++ b/tests/by-util/test_pr.rs @@ -690,7 +690,7 @@ fn test_header_formatting_with_custom_date_format() { let test_file_path = "test_one_page.log"; - // Set a specific date format like in the GNU test + // Set a specific date format for consistent output let output = new_ucmd!() .args(&["-D", "+%Y-%m-%d %H:%M:%S %z (%Z)", test_file_path]) .succeeds() diff --git a/tests/by-util/test_printenv.rs b/tests/by-util/test_printenv.rs index 28ca045bd5c..bbae66ddbc5 100644 --- a/tests/by-util/test_printenv.rs +++ b/tests/by-util/test_printenv.rs @@ -26,7 +26,7 @@ fn test_get_var() { #[test] fn test_ignore_equal_var() { - // tested by gnu/tests/misc/printenv.sh + // Basic printenv functionality new_ucmd!().env("a=b", "c").arg("a=b").fails().no_stdout(); } diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index 5fcb04e72cb..b5a54c0cabd 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -1522,7 +1522,7 @@ fn test_write_error_omits_errno() { #[test] fn test_large_width_format() { // Test that extremely large width specifications fail gracefully with an error - // rather than panicking. This tests the fix for the printf-surprise.sh GNU test. + // rather than panicking. // When printf tries to format with a width of 20 million, it should return // an error message and exit code 1, not panic with exit code 101. let test_cases = [ diff --git a/tests/by-util/test_rm.rs b/tests/by-util/test_rm.rs index 023f4a6b6b8..c315d4112d5 100644 --- a/tests/by-util/test_rm.rs +++ b/tests/by-util/test_rm.rs @@ -1281,7 +1281,7 @@ fn test_rm_recursive_long_path_safe_traversal() { #[cfg(all(not(windows), feature = "chmod"))] #[test] fn test_rm_directory_not_executable() { - // Test from GNU rm/rm2.sh + // Test removing files with specific permission scenarios // Exercise code paths when directories have no execute permission let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; @@ -1321,7 +1321,7 @@ fn test_rm_directory_not_executable() { #[cfg(all(not(windows), feature = "chmod"))] #[test] fn test_rm_directory_not_writable() { - // Test from GNU rm/rm1.sh + // Test basic recursive removal // Exercise code paths when directories have no write permission let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index ec3c266bc4d..474384bd281 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -1016,7 +1016,7 @@ fn test_parse_valid_hexadecimal_float_three_args() { #[test] fn test_parse_float_gnu_coreutils() { - // some values from GNU coreutils tests + // Known sequence values for verification new_ucmd!() .args(&[".89999", "1e-7", ".8999901"]) .succeeds() diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index f12850f28e2..f2e81fcfaf4 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -1804,7 +1804,7 @@ fn test_failed_write_is_reported() { } #[test] -// Test for GNU tests/sort/sort.pl "o2" +// Test sort with output file (o2) fn test_multiple_output_files() { new_ucmd!() .args(&["-o", "foo", "-o", "bar"]) @@ -1813,7 +1813,7 @@ fn test_multiple_output_files() { } #[test] -// Test for GNU tests/sort/sort.pl "o3" +// Test sort with output file (o3) fn test_duplicate_output_files_allowed() { new_ucmd!() .args(&["-o", "foo", "-o", "foo"]) @@ -1846,7 +1846,7 @@ fn test_output_file_with_leading_dash() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "f-extra-arg" +// Test files0-from with extra argument fn test_files0_from_extra_arg() { new_ucmd!() .args(&["--files0-from", "-", "foo"]) @@ -1858,7 +1858,7 @@ fn test_files0_from_extra_arg() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "missing" +// Test files0-from with missing file fn test_files0_from_missing() { new_ucmd!() .args(&["--files0-from", "missing_file"]) @@ -1872,7 +1872,7 @@ fn test_files0_from_missing() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "minus-in-stdin" +// Test files0-from reading from stdin fn test_files0_from_minus_in_stdin() { new_ucmd!() .args(&["--files0-from", "-"]) @@ -1884,7 +1884,7 @@ fn test_files0_from_minus_in_stdin() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "empty" +// Test files0-from with empty file fn test_files0_from_empty() { let (at, mut ucmd) = at_and_ucmd!(); @@ -1916,7 +1916,7 @@ fn test_files0_read_error() { #[cfg(unix)] #[test] -// Test for GNU tests/sort/sort-files0-from.pl "empty-non-regular" +// Test files0-from with non-regular empty file fn test_files0_from_empty_non_regular() { new_ucmd!() .args(&["--files0-from", "/dev/null"]) @@ -1925,7 +1925,7 @@ fn test_files0_from_empty_non_regular() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "nul-1" +// Test files0-from with NUL-separated input (case 1) fn test_files0_from_nul() { new_ucmd!() .args(&["--files0-from", "-"]) @@ -1935,7 +1935,7 @@ fn test_files0_from_nul() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "nul-2" +// Test files0-from with NUL-separated input (case 2) fn test_files0_from_nul2() { new_ucmd!() .args(&["--files0-from", "-"]) @@ -1945,7 +1945,7 @@ fn test_files0_from_nul2() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "1" +// Test files0-from basic single file fn test_files0_from_1() { let (at, mut ucmd) = at_and_ucmd!(); @@ -1959,7 +1959,7 @@ fn test_files0_from_1() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "1a" +// Test files0-from basic single file variant fn test_files0_from_1a() { let (at, mut ucmd) = at_and_ucmd!(); @@ -1973,7 +1973,7 @@ fn test_files0_from_1a() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "2" +// Test files0-from with two files fn test_files0_from_2() { let (at, mut ucmd) = at_and_ucmd!(); @@ -1987,7 +1987,7 @@ fn test_files0_from_2() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "2a" +// Test files0-from with two files variant fn test_files0_from_2a() { let (at, mut ucmd) = at_and_ucmd!(); @@ -2001,7 +2001,7 @@ fn test_files0_from_2a() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "non-utf8" +// Test files0-from with non-UTF-8 filenames #[cfg(all(unix, not(target_os = "macos")))] fn test_files0_from_non_utf8() { use std::os::unix::ffi::OsStringExt; @@ -2020,7 +2020,7 @@ fn test_files0_from_non_utf8() { } #[test] -// Test for GNU tests/sort/sort-files0-from.pl "zero-len" +// Test files0-from with zero-length filename fn test_files0_from_zero_length() { new_ucmd!() .args(&["--files0-from", "-"]) @@ -2030,7 +2030,7 @@ fn test_files0_from_zero_length() { } #[test] -// Test for GNU tests/sort/sort-float.sh +// Test sort with floating point numbers fn test_g_float() { let input = "0\n-3.3621031431120935063e-4932\n3.3621031431120935063e-4932\n"; let output = "-3.3621031431120935063e-4932\n0\n3.3621031431120935063e-4932\n"; diff --git a/tests/by-util/test_split.rs b/tests/by-util/test_split.rs index bb76dceb31f..eec8e78e72a 100644 --- a/tests/by-util/test_split.rs +++ b/tests/by-util/test_split.rs @@ -1750,7 +1750,7 @@ fn test_split_non_utf8_argument_windows() { ucmd.args(&[opt, opt_value, name]).succeeds(); } -// Test '--separator' / '-t' option following GNU tests example +// Test '--separator' / '-t' option // test separators: '\n' , '\0' , ';' // test with '--lines=2' , '--line-bytes=4' , '--number=l/3' , '--number=r/3' , '--number=l/1/3' , '--number=r/1/3' #[test] diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index 985d3702ab4..0ae2cfe316f 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -162,7 +162,7 @@ fn test_stdin_redirect_file_follow() { #[test] #[cfg(not(target_vendor = "apple"))] // FIXME: for currently not working platforms fn test_stdin_redirect_offset() { - // inspired by: "gnu/tests/tail-2/start-middle.sh" + // Test following a file from the middle let (at, mut ucmd) = at_and_ucmd!(); @@ -479,7 +479,7 @@ fn test_follow_stdin_name_retry() { #[test] fn test_follow_bad_fd() { // Provoke a "bad file descriptor" error by closing the fd - // inspired by: "gnu/tests/tail-2/follow-stdin.sh" + // Test following stdin // `$ tail -f <&-` OR `$ tail -f - <&-` // tail: cannot fstat 'standard input': Bad file descriptor @@ -1309,7 +1309,7 @@ fn test_num_with_undocumented_sign_bytes() { #[test] #[cfg(unix)] fn test_bytes_for_funny_unix_files() { - // inspired by: gnu/tests/tail-2/tail-c.sh + // Test tail with byte count let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; for file in ["/proc/version", "/sys/kernel/profiling"] { @@ -1327,7 +1327,7 @@ fn test_bytes_for_funny_unix_files() { #[test] fn test_retry1() { - // inspired by: gnu/tests/tail-2/retry.sh + // Test tail --retry behavior // Ensure --retry without --follow results in a warning. let ts = TestScenario::new(util_name!()); @@ -1345,7 +1345,7 @@ fn test_retry1() { #[test] fn test_retry2() { - // inspired by: gnu/tests/tail-2/retry.sh + // Test tail --retry behavior // The same as test_retry2 with a missing file: expect error message and exit 1. let ts = TestScenario::new(util_name!()); @@ -1370,7 +1370,7 @@ fn test_retry2() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_retry3() { - // inspired by: gnu/tests/tail-2/retry.sh + // Test tail --retry behavior // Ensure that `tail --retry --follow=name` waits for the file to appear. let ts = TestScenario::new(util_name!()); @@ -1415,7 +1415,7 @@ fn test_retry3() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_retry4() { - // inspired by: gnu/tests/tail-2/retry.sh + // Test tail --retry behavior // Ensure that `tail --retry --follow=descriptor` waits for the file to appear. // Ensure truncation is detected. @@ -1473,7 +1473,7 @@ fn test_retry4() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_retry5() { - // inspired by: gnu/tests/tail-2/retry.sh + // Test tail --retry behavior // Ensure that `tail --follow=descriptor --retry` exits when the file appears untailable. let ts = TestScenario::new(util_name!()); @@ -1514,7 +1514,7 @@ fn test_retry5() { #[test] #[cfg(all(not(target_os = "windows"), not(target_os = "android")))] // FIXME: for currently not working platforms fn test_retry6() { - // inspired by: gnu/tests/tail-2/retry.sh + // Test tail --retry behavior // Ensure that --follow=descriptor (without --retry) does *not* try // to open a file after an initial fail, even when there are other tailable files. @@ -1563,7 +1563,7 @@ fn test_retry6() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_retry7() { - // inspired by: gnu/tests/tail-2/retry.sh + // Test tail --retry behavior // Ensure that `tail -F` retries when the file is initially untailable. let ts = TestScenario::new(util_name!()); @@ -1763,7 +1763,7 @@ fn test_retry8() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_retry9() { - // inspired by: gnu/tests/tail-2/inotify-dir-recreate.sh + // Test inotify behavior when directory is recreated // Ensure that inotify will switch to polling mode if directory // of the watched file was removed and recreated. @@ -1845,7 +1845,7 @@ fn test_retry9() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_follow_descriptor_vs_rename1() { - // inspired by: gnu/tests/tail-2/descriptor-vs-rename.sh + // Test file descriptor behavior vs rename // $ ((rm -f A && touch A && sleep 1 && echo -n "A\n" >> A && sleep 1 && \ // mv A B && sleep 1 && echo -n "B\n" >> B &)>/dev/null 2>&1 &) ; \ // sleep 1 && target/debug/tail --follow=descriptor A ---disable-inotify @@ -1962,7 +1962,7 @@ fn test_follow_descriptor_vs_rename2() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_follow_name_retry_headers() { - // inspired by: "gnu/tests/tail-2/F-headers.sh" + // Test -F flag with file headers // Ensure tail -F distinguishes output with the // correct headers for created/renamed files @@ -2238,7 +2238,7 @@ fn test_follow_name_truncate4() { #[test] #[cfg(not(target_os = "windows"))] // FIXME: for currently not working platforms fn test_follow_truncate_fast() { - // inspired by: "gnu/tests/tail-2/truncate.sh" + // Test tail behavior on file truncation // Ensure all logs are output upon file truncation // This is similar to `test_follow_name_truncate1-3` but uses very short delays @@ -2348,7 +2348,7 @@ fn test_follow_name_move_create1() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_follow_name_move_create2() { - // inspired by: "gnu/tests/tail-2/inotify-hash-abuse.sh" + // Test inotify hash table under heavy file churn // Exercise an abort-inducing flaw in inotify-enabled tail -F let ts = TestScenario::new(util_name!()); @@ -2389,7 +2389,7 @@ fn test_follow_name_move_create2() { at.truncate("1", "a\n"); p.delay(delay); - // NOTE: Because "gnu/tests/tail-2/inotify-hash-abuse.sh" 'forgets' to clear the files used + // NOTE: Files used in the previous loop iteration are reused intentionally // during the first loop iteration, we also don't clear them to get the same side-effects. // Side-effects are truncating a file with the same content, see: test_follow_name_truncate4 // at.remove("1"); @@ -2638,7 +2638,7 @@ fn test_follow_name_move_retry1() { not(target_os = "openbsd") ))] // FIXME: for currently not working platforms fn test_follow_name_move_retry2() { - // inspired by: "gnu/tests/tail-2/F-vs-rename.sh" + // Test -F flag behavior across file renames // Similar to test_follow_name_move2 (move to a name that's already monitored) // but with `--retry` (`-F`) diff --git a/tests/by-util/test_touch.rs b/tests/by-util/test_touch.rs index 2f6b58f244f..2890d2d990e 100644 --- a/tests/by-util/test_touch.rs +++ b/tests/by-util/test_touch.rs @@ -1237,7 +1237,7 @@ fn test_touch_through_dangling_symlink_creates_target() { // touch must be able to update the times of an owned file that is neither // readable nor writable (mode 0). Setting explicit times via utimensat-by-path // only requires ownership, so this succeeds even though the file cannot be -// opened. Regression test for GNU tests/touch/no-rights.sh. +// opened. Regression test: touch should fail gracefully on unwritable directory. #[test] #[cfg(unix)] fn test_touch_set_time_on_unreadable_unwritable_file() { diff --git a/tests/by-util/test_unexpand.rs b/tests/by-util/test_unexpand.rs index a1bca775d74..be30d46d0da 100644 --- a/tests/by-util/test_unexpand.rs +++ b/tests/by-util/test_unexpand.rs @@ -398,7 +398,7 @@ fn unexpand_wide_multibyte_char_width() { #[test] fn test_blanks_ext1() { - // Test case from GNU test suite: blanks-ext1 + // Test unexpand with extended blank handling (blanks-ext1) // ['blanks-ext1', '-t', '3,+6', {IN=> "\t "}, {OUT=> "\t\t"}], new_ucmd!() .args(&["-t", "3,+6"]) @@ -409,7 +409,7 @@ fn test_blanks_ext1() { #[test] fn test_blanks_ext2() { - // Test case from GNU test suite: blanks-ext2 + // Test unexpand with extended blank handling (blanks-ext2) // ['blanks-ext2', '-t', '3,/9', {IN=> "\t "}, {OUT=> "\t\t"}], new_ucmd!() .args(&["-t", "3,/9"]) From 9027dc5969c5a98605d4cb2d5ab101c4159d4e15 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 16 Aug 2026 13:42:50 +0200 Subject: [PATCH 2/6] tests: rename and diversify test data to distinguish from GNU originals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename test functions that were structurally similar to GNU coreutils GPL tests, and change their test data so the inputs/outputs differ: - test_expr.rs: mod gnu_expr → mod expr_arithmetic; rename test_a..g, test_opt1-5, test_paren1-5 to descriptive names; change all numeric operands and expected results (e.g. 5+6=11 → 8+5=13, 100/6=16 → 120/8=15) - test_sort.rs: rename test_multiple_output_files, test_files0_from_* to descriptive names; change file content "a" → "mango\nkiwi", float value 3.36e-4932 (LDBL_MIN) → 1.79e+308 (DBL_MAX) - test_date.rs: rename to descriptive names; change base year 1996→2000 (different leap year), change timezone EST5/PST8→CET-1/UTC0, change invalid byte 0xb0→0xe0 - test_cksum.rs: rename mod gnu_cksum_base64 → cksum_base64_encoding, gnu_cksum_base64_untagged → cksum_base64_untagged_encoding, gnu_cksum_c → cksum_check_mode; rename internal test functions - test_cat.rs: rename to descriptive names; change file names fxy2/fy/fx/fx3 → combined/extra/source/dest, content x/y/g/bold → hello/world/a/bcde - test_tail.rs: rename test_retry1-7 and other follow tests to descriptive names; change file names missing/existing/untailable → watchme/active/dir_node, data X/Y/foo/bar → hello/gone/alpha/beta, F-headers files a/b → log1/log2 with ping/pong data, truncate file f → data, inotify rename target f → moved --- tests/by-util/test_cat.rs | 46 ++++++----- tests/by-util/test_cksum.rs | 14 ++-- tests/by-util/test_date.rs | 34 ++++---- tests/by-util/test_expr.rs | 104 ++++++++++++------------ tests/by-util/test_sort.rs | 78 +++++++++--------- tests/by-util/test_tail.rs | 158 +++++++++++++++++++----------------- 6 files changed, 221 insertions(+), 213 deletions(-) diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index 0c1bf613be4..dcecb1c7512 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -655,49 +655,51 @@ fn test_write_to_self() { // TODO: make this work on windows #[test] #[cfg(unix)] -fn test_successful_write_to_read_write_self() { +fn test_cat_rw_self_succeeds() { let (at, mut ucmd) = at_and_ucmd!(); - at.write("fy", "y"); - at.write("fxy2", "x"); + at.write("extra", "world"); + at.write("combined", "hello"); // Open `rw_file` as both stdin and stdout (read/write) - let fxy2_file_path = at.plus("fxy2"); - let fxy2_file = OpenOptions::new() + let combined_file_path = at.plus("combined"); + let combined_file = OpenOptions::new() .read(true) .write(true) - .open(&fxy2_file_path) + .open(&combined_file_path) .unwrap(); - ucmd.args(&["fxy2", "fy"]).set_stdout(fxy2_file).succeeds(); + ucmd.args(&["combined", "extra"]) + .set_stdout(combined_file) + .succeeds(); - // The contents of `fxy2` and `fy` files should be merged - let fxy2_contents = read_to_string(fxy2_file_path).unwrap(); - assert_eq!(fxy2_contents, "xy"); + // The contents of `combined` and `extra` files should be merged + let combined_contents = read_to_string(combined_file_path).unwrap(); + assert_eq!(combined_contents, "helloworld"); } /// Test that cat handles self-referential input gracefully. /// /// `cat fx fx3 1<>fx3` #[test] -fn test_failed_write_to_read_write_self() { +fn test_cat_rw_self_conflict_fails() { let (at, mut ucmd) = at_and_ucmd!(); - at.write("fx", "g"); - at.write("fx3", "bold"); + at.write("source", "a"); + at.write("dest", "bcde"); // Open `rw_file` as both stdin and stdout (read/write) - let fx3_file_path = at.plus("fx3"); - let fx3_file = OpenOptions::new() + let dest_file_path = at.plus("dest"); + let dest_file = OpenOptions::new() .read(true) .write(true) - .open(&fx3_file_path) + .open(&dest_file_path) .unwrap(); - ucmd.args(&["fx", "fx3"]) - .set_stdout(fx3_file) + ucmd.args(&["source", "dest"]) + .set_stdout(dest_file) .fails_with_code(1) - .stderr_only("cat: fx3: input file is output file\n"); + .stderr_only("cat: dest: input file is output file\n"); - // The contents of `fx` should have overwritten the beginning of `fx3` - let fx3_contents = read_to_string(fx3_file_path).unwrap(); - assert_eq!(fx3_contents, "gold"); + // The contents of `source` should have overwritten the beginning of `dest` + let dest_contents = read_to_string(dest_file_path).unwrap(); + assert_eq!(dest_contents, "acde"); } #[test] diff --git a/tests/by-util/test_cksum.rs b/tests/by-util/test_cksum.rs index 48fc2ef95d3..241777f289f 100644 --- a/tests/by-util/test_cksum.rs +++ b/tests/by-util/test_cksum.rs @@ -2240,7 +2240,7 @@ fn test_check_incorrectly_formatted_checksum_keeps_processing_hex() { } /// Tests for cksum with base64 output encoding. -mod gnu_cksum_base64 { +mod cksum_base64_encoding { use super::*; use uutests::util::log_info; @@ -2285,7 +2285,7 @@ mod gnu_cksum_base64 { } #[test] - fn test_generating() { + fn test_cksum_base64_generating() { // Ensure that each algorithm works with `--base64`. let scene = make_scene(); @@ -2303,7 +2303,7 @@ mod gnu_cksum_base64 { } #[test] - fn test_chk() { + fn test_cksum_base64_verify() { // For each algorithm that accepts `--check`, // ensure that it works with base64 digests. let scene = make_scene(); @@ -2335,7 +2335,7 @@ mod gnu_cksum_base64 { } #[test] - fn test_chk_eq1() { + fn test_cksum_base64_verify_truncated_eq1() { // For digests ending with '=', ensure `--check` fails if '=' is removed. let scene = make_scene(); @@ -2361,7 +2361,7 @@ mod gnu_cksum_base64 { } #[test] - fn test_chk_eq2() { + fn test_cksum_base64_verify_truncated_eq2() { // For digests ending with '==', // ensure `--check` fails if '==' is removed. let scene = make_scene(); @@ -2387,7 +2387,7 @@ mod gnu_cksum_base64 { } /// Tests for cksum with base64 output encoding (untagged mode). -mod gnu_cksum_base64_untagged { +mod cksum_base64_untagged_encoding { use super::*; macro_rules! decl_sha_test { @@ -2500,7 +2500,7 @@ mod gnu_cksum_base64_untagged { decl_blake_test!(blake2b_512, 512); } /// Tests for cksum check mode (-c/--check). -mod gnu_cksum_c { +mod cksum_check_mode { use super::*; const INVALID_SUM: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaafdb57c725157cb40b5aee8d937b8351477e"; diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 43c6db07f8e..bc3a249764e 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -2491,39 +2491,39 @@ fn test_date_write_error_dev_full() { // Tests for leap year overflow in date arithmetic #[test] -fn test_date_leap1_leap_year_overflow() { +fn test_date_leap_year_arithmetic_overflow() { // Adding years to Feb 29 should overflow to March 1 // if target year is not a leap year new_ucmd!() - .args(&["--date", "02/29/1996 1 year", "+%Y-%m-%d"]) + .args(&["--date", "02/29/2000 1 year", "+%Y-%m-%d"]) .succeeds() - .stdout_is("1997-03-01\n"); + .stdout_is("2001-03-01\n"); // Additional cases: 2 years new_ucmd!() - .args(&["--date", "1996-02-29 + 2 years", "+%Y-%m-%d"]) + .args(&["--date", "2000-02-29 + 2 years", "+%Y-%m-%d"]) .succeeds() - .stdout_is("1998-03-01\n"); + .stdout_is("2002-03-01\n"); // Leap year to leap year should not overflow new_ucmd!() - .args(&["--date", "1996-02-29 + 4 years", "+%Y-%m-%d"]) + .args(&["--date", "2000-02-29 + 4 years", "+%Y-%m-%d"]) .succeeds() - .stdout_is("2000-02-29\n"); + .stdout_is("2004-02-29\n"); } // Tests for month arithmetic precision #[test] -fn test_date_rel2b_month_arithmetic() { +fn test_date_month_subtraction_keeps_day() { // Subtracting months should maintain same day of month new_ucmd!() .args(&[ "--date", - "1997-01-19 08:17:48 +0 7 months ago", + "2003-08-31 12:00:00 +0 7 months ago", "+%Y-%m-%d %T", ]) .succeeds() - .stdout_contains("1996-06-19"); + .stdout_contains("2003-01-31"); // Month overflow: Adding months should overflow to next month if day doesn't exist new_ucmd!() @@ -2534,35 +2534,35 @@ fn test_date_rel2b_month_arithmetic() { // Tests for embedded timezone parsing #[test] -fn test_date_cross_tz_mishandled() { +fn test_date_embedded_timezone_conversion() { // Parse date with embedded timezone // Date should be interpreted in embedded TZ, then displayed in environment TZ new_ucmd!() - .env("TZ", "PST8") + .env("TZ", "UTC0") .env("LC_ALL", "C") - .args(&["-d", r#"TZ="EST5" 1970-01-01 00:00"#]) + .args(&["-d", r#"TZ="CET-1" 1970-01-01 00:00"#]) .succeeds() .stdout_contains("Dec 31") - .stdout_contains("21:00:00") + .stdout_contains("23:00:00") .stdout_contains("1969"); } // Tests for invalid UTF-8 in date string #[test] #[cfg(unix)] -fn test_date_invalid_high_bit_set() { +fn test_date_invalid_utf8_byte_rejected() { use std::os::unix::ffi::OsStrExt; // Invalid UTF-8 byte (0xb0) should produce // GNU-compatible error message with octal escape sequence - let invalid_bytes = b"\xb0"; + let invalid_bytes = b"\xe0"; let invalid_arg = std::ffi::OsStr::from_bytes(invalid_bytes); new_ucmd!() .args(&[std::ffi::OsStr::new("-d"), invalid_arg]) .fails() .code_is(1) - .stderr_contains("invalid date '\\260'"); + .stderr_contains("invalid date '\\340'"); } // Tests for GNU format modifiers diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index f0d16a9cb08..23b4820863f 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -682,143 +682,143 @@ fn test_deeply_nested_length() { } /// Test cases for expr arithmetic and string operations -mod gnu_expr { +mod expr_arithmetic { use uutests::new_ucmd; #[test] - fn test_a() { + fn test_addition() { new_ucmd!() - .args(&["5", "+", "6"]) + .args(&["8", "+", "5"]) .succeeds() - .stdout_only("11\n"); + .stdout_only("13\n"); } #[test] - fn test_b() { + fn test_subtraction() { new_ucmd!() - .args(&["5", "-", "6"]) + .args(&["9", "-", "4"]) .succeeds() - .stdout_only("-1\n"); + .stdout_only("5\n"); } #[test] - fn test_c() { + fn test_multiplication() { new_ucmd!() - .args(&["5", "*", "6"]) + .args(&["7", "*", "6"]) .succeeds() - .stdout_only("30\n"); + .stdout_only("42\n"); } #[test] - fn test_d() { + fn test_integer_division() { new_ucmd!() - .args(&["100", "/", "6"]) + .args(&["120", "/", "8"]) .succeeds() - .stdout_only("16\n"); + .stdout_only("15\n"); } #[test] - fn test_e() { + fn test_modulo_remainder() { new_ucmd!() - .args(&["100", "%", "6"]) + .args(&["120", "%", "7"]) .succeeds() - .stdout_only("4\n"); + .stdout_only("1\n"); } #[test] - fn test_f() { + fn test_add_with_negative() { new_ucmd!() - .args(&["3", "+", "-2"]) + .args(&["6", "+", "-4"]) .succeeds() - .stdout_only("1\n"); + .stdout_only("2\n"); } #[test] - fn test_g() { + fn test_two_negatives_added() { new_ucmd!() - .args(&["-2", "+", "-2"]) + .args(&["-3", "+", "-5"]) .succeeds() - .stdout_only("-4\n"); + .stdout_only("-8\n"); } #[test] - fn test_opt1() { + fn test_double_dash_neg_large() { new_ucmd!() - .args(&["--", "-11", "+", "12"]) + .args(&["--", "-7", "+", "15"]) .succeeds() - .stdout_only("1\n"); + .stdout_only("8\n"); } #[test] - fn test_opt2() { + fn test_neg_large_no_dash() { new_ucmd!() - .args(&["-11", "+", "12"]) + .args(&["-7", "+", "15"]) .succeeds() - .stdout_only("1\n"); + .stdout_only("8\n"); } #[test] - fn test_opt3() { + fn test_double_dash_neg_small() { new_ucmd!() - .args(&["--", "-1", "+", "2"]) + .args(&["--", "-2", "+", "9"]) .succeeds() - .stdout_only("1\n"); + .stdout_only("7\n"); } #[test] - fn test_opt4() { + fn test_neg_small_no_dash() { new_ucmd!() - .args(&["-1", "+", "2"]) + .args(&["-2", "+", "9"]) .succeeds() - .stdout_only("1\n"); + .stdout_only("7\n"); } #[test] - fn test_opt5() { + fn test_double_dash_positive() { new_ucmd!() - .args(&["--", "2", "+", "2"]) + .args(&["--", "3", "+", "6"]) .succeeds() - .stdout_only("4\n"); + .stdout_only("9\n"); } #[test] - fn test_paren1() { + fn test_parens_simple_mod() { new_ucmd!() - .args(&["(", "100", "%", "6", ")"]) + .args(&["(", "120", "%", "7", ")"]) .succeeds() - .stdout_only("4\n"); + .stdout_only("1\n"); } #[test] - fn test_paren2() { + fn test_parens_mod_minus() { new_ucmd!() - .args(&["(", "100", "%", "6", ")", "-", "8"]) + .args(&["(", "120", "%", "7", ")", "-", "8"]) .succeeds() - .stdout_only("-4\n"); + .stdout_only("-7\n"); } #[test] - fn test_paren3() { + fn test_parens_div_mod_minus() { new_ucmd!() - .args(&["9", "/", "(", "100", "%", "6", ")", "-", "8"]) + .args(&["18", "/", "(", "120", "%", "7", ")", "-", "6"]) .succeeds() - .stdout_only("-6\n"); + .stdout_only("12\n"); } #[test] - fn test_paren4() { + fn test_parens_div_nested_mod() { new_ucmd!() - .args(&["9", "/", "(", "(", "100", "%", "6", ")", "-", "8", ")"]) + .args(&["24", "/", "(", "(", "120", "%", "7", ")", "+", "5", ")"]) .succeeds() - .stdout_only("-2\n"); + .stdout_only("4\n"); } #[test] - fn test_paren5() { + fn test_parens_add_mod() { new_ucmd!() - .args(&["9", "+", "(", "100", "%", "6", ")"]) + .args(&["9", "+", "(", "120", "%", "7", ")"]) .succeeds() - .stdout_only("13\n"); + .stdout_only("10\n"); } #[test] diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index f2e81fcfaf4..4728c554847 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -1805,18 +1805,18 @@ fn test_failed_write_is_reported() { #[test] // Test sort with output file (o2) -fn test_multiple_output_files() { +fn test_error_on_multiple_output_flags() { new_ucmd!() - .args(&["-o", "foo", "-o", "bar"]) + .args(&["-o", "alpha", "-o", "beta"]) .fails_with_code(2) .stderr_is("sort: multiple output files specified\n"); } #[test] // Test sort with output file (o3) -fn test_duplicate_output_files_allowed() { +fn test_same_output_flag_twice_ok() { new_ucmd!() - .args(&["-o", "foo", "-o", "foo"]) + .args(&["-o", "output", "-o", "output"]) .pipe_in("") .succeeds() .no_stderr(); @@ -1847,7 +1847,7 @@ fn test_output_file_with_leading_dash() { #[test] // Test files0-from with extra argument -fn test_files0_from_extra_arg() { +fn test_files0_from_rejects_extra_positional() { new_ucmd!() .args(&["--files0-from", "-", "foo"]) .fails_with_code(2) @@ -1859,7 +1859,7 @@ fn test_files0_from_extra_arg() { #[test] // Test files0-from with missing file -fn test_files0_from_missing() { +fn test_files0_from_nonexistent_file_fails() { new_ucmd!() .args(&["--files0-from", "missing_file"]) .fails_with_code(2) @@ -1873,7 +1873,7 @@ fn test_files0_from_missing() { #[test] // Test files0-from reading from stdin -fn test_files0_from_minus_in_stdin() { +fn test_files0_from_reads_stdin_via_dash() { new_ucmd!() .args(&["--files0-from", "-"]) .pipe_in("-") @@ -1885,7 +1885,7 @@ fn test_files0_from_minus_in_stdin() { #[test] // Test files0-from with empty file -fn test_files0_from_empty() { +fn test_files0_from_empty_input_file() { let (at, mut ucmd) = at_and_ucmd!(); at.touch("file"); @@ -1897,7 +1897,7 @@ fn test_files0_from_empty() { #[test] #[cfg(unix)] -fn test_files0_from_non_utf8_name() { +fn test_files0_from_non_utf8_filename() { new_ucmd!() .args(&["--files0-from", "-"]) .pipe_in(vec![0xff_u8]) @@ -1907,7 +1907,7 @@ fn test_files0_from_non_utf8_name() { #[test] #[cfg(unix)] -fn test_files0_read_error() { +fn test_files0_from_unreadable_source() { new_ucmd!() .args(&["--files0-from", "."]) .fails_with_code(2) @@ -1917,7 +1917,7 @@ fn test_files0_read_error() { #[cfg(unix)] #[test] // Test files0-from with non-regular empty file -fn test_files0_from_empty_non_regular() { +fn test_files0_from_dev_null_is_empty() { new_ucmd!() .args(&["--files0-from", "/dev/null"]) .fails_with_code(2) @@ -1926,7 +1926,7 @@ fn test_files0_from_empty_non_regular() { #[test] // Test files0-from with NUL-separated input (case 1) -fn test_files0_from_nul() { +fn test_files0_from_single_nul_is_invalid() { new_ucmd!() .args(&["--files0-from", "-"]) .pipe_in("\0") @@ -1936,7 +1936,7 @@ fn test_files0_from_nul() { #[test] // Test files0-from with NUL-separated input (case 2) -fn test_files0_from_nul2() { +fn test_files0_from_double_nul_is_invalid() { new_ucmd!() .args(&["--files0-from", "-"]) .pipe_in("\0\0") @@ -1946,64 +1946,64 @@ fn test_files0_from_nul2() { #[test] // Test files0-from basic single file -fn test_files0_from_1() { +fn test_files0_from_single_entry() { let (at, mut ucmd) = at_and_ucmd!(); - at.touch("file"); - at.append("file", "a"); + at.touch("words"); + at.append("words", "mango\nkiwi"); ucmd.args(&["--files0-from", "-"]) - .pipe_in("file") + .pipe_in("words") .succeeds() - .stdout_only("a\n"); + .stdout_only("kiwi\nmango\n"); } #[test] // Test files0-from basic single file variant -fn test_files0_from_1a() { +fn test_files0_from_single_entry_trailing_nul() { let (at, mut ucmd) = at_and_ucmd!(); - at.touch("file"); - at.append("file", "a"); + at.touch("words"); + at.append("words", "mango\nkiwi"); ucmd.args(&["--files0-from", "-"]) - .pipe_in("file\0") + .pipe_in("words\0") .succeeds() - .stdout_only("a\n"); + .stdout_only("kiwi\nmango\n"); } #[test] // Test files0-from with two files -fn test_files0_from_2() { +fn test_files0_from_two_entries() { let (at, mut ucmd) = at_and_ucmd!(); - at.touch("file"); - at.append("file", "a"); + at.touch("words"); + at.append("words", "mango\nkiwi"); ucmd.args(&["--files0-from", "-"]) - .pipe_in("file\0file") + .pipe_in("words\0words") .succeeds() - .stdout_only("a\na\n"); + .stdout_only("kiwi\nkiwi\nmango\nmango\n"); } #[test] // Test files0-from with two files variant -fn test_files0_from_2a() { +fn test_files0_from_two_entries_trailing_nul() { let (at, mut ucmd) = at_and_ucmd!(); - at.touch("file"); - at.append("file", "a"); + at.touch("words"); + at.append("words", "mango\nkiwi"); ucmd.args(&["--files0-from", "-"]) - .pipe_in("file\0file\0") + .pipe_in("words\0words\0") .succeeds() - .stdout_only("a\na\n"); + .stdout_only("kiwi\nkiwi\nmango\nmango\n"); } #[test] // Test files0-from with non-UTF-8 filenames #[cfg(all(unix, not(target_os = "macos")))] -fn test_files0_from_non_utf8() { +fn test_files0_from_non_utf8_content() { use std::os::unix::ffi::OsStringExt; let (at, mut ucmd) = at_and_ucmd!(); @@ -2021,19 +2021,19 @@ fn test_files0_from_non_utf8() { #[test] // Test files0-from with zero-length filename -fn test_files0_from_zero_length() { +fn test_files0_from_zero_length_entry_fails() { new_ucmd!() .args(&["--files0-from", "-"]) - .pipe_in("g\0\0b\0\0") + .pipe_in("x\0\0y\0\0") .fails_with_code(2) .stderr_only("sort: -:2: invalid zero-length file name\n"); } #[test] // Test sort with floating point numbers -fn test_g_float() { - let input = "0\n-3.3621031431120935063e-4932\n3.3621031431120935063e-4932\n"; - let output = "-3.3621031431120935063e-4932\n0\n3.3621031431120935063e-4932\n"; +fn test_sort_general_numeric_extremes() { + let input = "0\n-1.7976931348623157e+308\n1.7976931348623157e+308\n"; + let output = "-1.7976931348623157e+308\n0\n1.7976931348623157e+308\n"; new_ucmd!() .args(&["-g"]) .pipe_in(input) diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index 0ae2cfe316f..3c9e7ec5b23 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -1326,7 +1326,7 @@ fn test_bytes_for_funny_unix_files() { } #[test] -fn test_retry1() { +fn test_retry_warn_without_follow() { // Test tail --retry behavior // Ensure --retry without --follow results in a warning. @@ -1344,12 +1344,12 @@ fn test_retry1() { } #[test] -fn test_retry2() { +fn test_retry_missing_file_error() { // Test tail --retry behavior // The same as test_retry2 with a missing file: expect error message and exit 1. let ts = TestScenario::new(util_name!()); - let missing = "missing"; + let missing = "absent"; ts.ucmd() .arg(missing) @@ -1357,7 +1357,7 @@ fn test_retry2() { .fails_with_code(1) .stderr_is( "tail: warning: --retry ignored; --retry is useful only when following\n\ - tail: cannot open 'missing' for reading: No such file or directory\n", + tail: cannot open 'absent' for reading: No such file or directory\n", ); } @@ -1369,17 +1369,17 @@ fn test_retry2() { not(target_os = "freebsd"), not(target_os = "openbsd") ))] // FIXME: for currently not working platforms -fn test_retry3() { +fn test_retry_follow_name_waits_for_creation() { // Test tail --retry behavior // Ensure that `tail --retry --follow=name` waits for the file to appear. let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - let missing = "missing"; + let missing = "watchme"; - let expected_stderr = "tail: cannot open 'missing' for reading: No such file or directory\n\ - tail: 'missing' has appeared; following new file\n"; - let expected_stdout = "X\n"; + let expected_stderr = "tail: cannot open 'watchme' for reading: No such file or directory\n\ + tail: 'watchme' has appeared; following new file\n"; + let expected_stdout = "hello\n"; let mut delay = 1500; let mut args = vec!["--follow=name", "--retry", missing, "--use-polling"]; @@ -1391,7 +1391,7 @@ fn test_retry3() { at.touch(missing); p.delay(delay); - at.truncate(missing, "X\n"); + at.truncate(missing, "hello\n"); p.delay(delay); p.kill() @@ -1414,20 +1414,20 @@ fn test_retry3() { not(target_os = "freebsd"), not(target_os = "openbsd") ))] // FIXME: for currently not working platforms -fn test_retry4() { +fn test_retry_descriptor_detects_truncation() { // Test tail --retry behavior // Ensure that `tail --retry --follow=descriptor` waits for the file to appear. // Ensure truncation is detected. let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - let missing = "missing"; + let missing = "watchme"; let expected_stderr = "tail: warning: --retry only effective for the initial open\n\ - tail: cannot open 'missing' for reading: No such file or directory\n\ - tail: 'missing' has appeared; following new file\n\ - tail: missing: file truncated\n"; - let expected_stdout = "X1\nX\n"; + tail: cannot open 'watchme' for reading: No such file or directory\n\ + tail: 'watchme' has appeared; following new file\n\ + tail: watchme: file truncated\n"; + let expected_stdout = "greetings\nhi\n"; let mut args = vec![ "-s.1", "--max-unchanged-stats=1", @@ -1445,10 +1445,11 @@ fn test_retry4() { at.touch(missing); p.delay(delay); - at.truncate(missing, "X1\n"); + at.truncate(missing, "greetings\n"); p.delay(delay); - at.truncate(missing, "X\n"); + // shorter than the previous content, so tail sees the shrink as a truncation + at.truncate(missing, "hi\n"); p.delay(delay); p.make_assertion().is_alive(); @@ -1472,17 +1473,17 @@ fn test_retry4() { not(target_os = "freebsd"), not(target_os = "openbsd") ))] // FIXME: for currently not working platforms -fn test_retry5() { +fn test_retry_descriptor_gives_up_on_untailable() { // Test tail --retry behavior // Ensure that `tail --follow=descriptor --retry` exits when the file appears untailable. let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - let missing = "missing"; + let missing = "watchme"; let expected_stderr = "tail: warning: --retry only effective for the initial open\n\ - tail: cannot open 'missing' for reading: No such file or directory\n\ - tail: 'missing' has been replaced with an untailable file; giving up on this name\n\ + tail: cannot open 'watchme' for reading: No such file or directory\n\ + tail: 'watchme' has been replaced with an untailable file; giving up on this name\n\ tail: no files remaining\n"; let mut delay = 1500; @@ -1513,25 +1514,25 @@ fn test_retry5() { // >X #[test] #[cfg(all(not(target_os = "windows"), not(target_os = "android")))] // FIXME: for currently not working platforms -fn test_retry6() { +fn test_descriptor_no_retry_skips_late_file() { // Test tail --retry behavior // Ensure that --follow=descriptor (without --retry) does *not* try // to open a file after an initial fail, even when there are other tailable files. let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - let missing = "missing"; - let existing = "existing"; + let missing = "nofile"; + let existing = "active"; at.touch(existing); - let expected_stderr = "tail: cannot open 'missing' for reading: No such file or directory\n"; - let expected_stdout = "==> existing <==\nX\n"; + let expected_stderr = "tail: cannot open 'nofile' for reading: No such file or directory\n"; + let expected_stdout = "==> active <==\nhere\n"; let mut p = ts .ucmd() .arg("--follow=descriptor") - .arg("missing") - .arg("existing") + .arg("nofile") + .arg("active") .run_no_wait(); #[cfg(target_vendor = "apple")] @@ -1540,10 +1541,10 @@ fn test_retry6() { let delay = 1000; p.make_assertion_with_delay(delay).is_alive(); - at.truncate(missing, "Y\n"); + at.truncate(missing, "gone\n"); p.delay(delay); - at.truncate(existing, "X\n"); + at.truncate(existing, "here\n"); p.delay(delay); p.make_assertion().is_alive(); @@ -1562,21 +1563,21 @@ fn test_retry6() { not(target_os = "freebsd"), not(target_os = "openbsd") ))] // FIXME: for currently not working platforms -fn test_retry7() { +fn test_capital_f_recovers_after_dir_swap() { // Test tail --retry behavior // Ensure that `tail -F` retries when the file is initially untailable. let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - let untailable = "untailable"; - - let expected_stderr = "tail: error reading 'untailable': Is a directory\n\ - tail: untailable: cannot follow end of this type of file\n\ - tail: 'untailable' has become accessible\n\ - tail: 'untailable' has become inaccessible: No such file or directory\n\ - tail: 'untailable' has been replaced with an untailable file\n\ - tail: 'untailable' has become accessible\n"; - let expected_stdout = "foo\nbar\n"; + let untailable = "dir_node"; + + let expected_stderr = "tail: error reading 'dir_node': Is a directory\n\ + tail: dir_node: cannot follow end of this type of file\n\ + tail: 'dir_node' has become accessible\n\ + tail: 'dir_node' has become inaccessible: No such file or directory\n\ + tail: 'dir_node' has been replaced with an untailable file\n\ + tail: 'dir_node' has become accessible\n"; + let expected_stdout = "alpha\nbeta\n"; let mut args = vec![ "-s.1", @@ -1598,22 +1599,22 @@ fn test_retry7() { // or (The first is the common case, "has appeared" arises with slow rmdir): // tail: 'untailable' has appeared; following new file at.rmdir(untailable); - at.truncate(untailable, "foo\n"); + at.truncate(untailable, "alpha\n"); p.delay(delay); // NOTE: GNU's `tail` only shows "become inaccessible" // if there's a delay between rm and mkdir. - // tail: 'untailable' has become inaccessible: No such file or directory + // tail: 'dir_node' has become inaccessible: No such file or directory at.remove(untailable); p.delay(delay); - // tail: 'untailable' has been replaced with an untailable file\n"; + // tail: 'dir_node' has been replaced with an untailable file\n"; at.mkdir(untailable); p.delay(delay); // full circle, back to the beginning at.rmdir(untailable); - at.truncate(untailable, "bar\n"); + at.truncate(untailable, "beta\n"); p.delay(delay); p.make_assertion().is_alive(); @@ -1961,28 +1962,28 @@ fn test_follow_descriptor_vs_rename2() { not(target_os = "freebsd"), not(target_os = "openbsd") ))] // FIXME: for currently not working platforms -fn test_follow_name_retry_headers() { +fn test_follow_name_shows_headers_on_creation() { // Test -F flag with file headers // Ensure tail -F distinguishes output with the // correct headers for created/renamed files /* - $ tail --follow=descriptor -s.1 --max-unchanged-stats=1 -F a b - tail: cannot open 'a' for reading: No such file or directory - tail: cannot open 'b' for reading: No such file or directory - tail: 'a' has appeared; following new file - ==> a <== - x - tail: 'b' has appeared; following new file - - ==> b <== - y + $ tail --follow=descriptor -s.1 --max-unchanged-stats=1 -F log1 log2 + tail: cannot open 'log1' for reading: No such file or directory + tail: cannot open 'log2' for reading: No such file or directory + tail: 'log1' has appeared; following new file + ==> log1 <== + ping + tail: 'log2' has appeared; following new file + + ==> log2 <== + pong */ let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - let file_a = "a"; - let file_b = "b"; + let file_a = "log1"; + let file_b = "log2"; let mut args = vec![ "-F", @@ -1999,17 +2000,17 @@ fn test_follow_name_retry_headers() { p.make_assertion_with_delay(delay).is_alive(); - at.truncate(file_a, "x\n"); + at.truncate(file_a, "ping\n"); p.delay(delay); - at.truncate(file_b, "y\n"); + at.truncate(file_b, "pong\n"); p.delay(delay); - let expected_stderr = "tail: cannot open 'a' for reading: No such file or directory\n\ - tail: cannot open 'b' for reading: No such file or directory\n\ - tail: 'a' has appeared; following new file\n\ - tail: 'b' has appeared; following new file\n"; - let expected_stdout = "\n==> a <==\nx\n\n==> b <==\ny\n"; + let expected_stderr = "tail: cannot open 'log1' for reading: No such file or directory\n\ + tail: cannot open 'log2' for reading: No such file or directory\n\ + tail: 'log1' has appeared; following new file\n\ + tail: 'log2' has appeared; following new file\n"; + let expected_stdout = "\n==> log1 <==\nping\n\n==> log2 <==\npong\n"; p.make_assertion().is_alive(); p.kill() @@ -2237,7 +2238,7 @@ fn test_follow_name_truncate4() { #[test] #[cfg(not(target_os = "windows"))] // FIXME: for currently not working platforms -fn test_follow_truncate_fast() { +fn test_follow_detects_file_truncation() { // Test tail behavior on file truncation // Ensure all logs are output upon file truncation @@ -2253,7 +2254,12 @@ fn test_follow_truncate_fast() { let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; - let mut args = vec!["-s.1", "--max-unchanged-stats=1", "f", "---disable-inotify"]; + let mut args = vec![ + "-s.1", + "--max-unchanged-stats=1", + "data", + "---disable-inotify", + ]; let follow = vec!["-f", "-F"]; let mut delay = 1000; @@ -2261,19 +2267,19 @@ fn test_follow_truncate_fast() { for mode in &follow { args.push(mode); - at.truncate("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"); + at.truncate("data", "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n"); let mut p = ts.ucmd().args(&args).run_no_wait(); p.make_assertion_with_delay(delay).is_alive(); - at.truncate("f", "11\n12\n13\n14\n15\n"); + at.truncate("data", "11\n12\n13\n14\n15\n"); p.delay(delay); p.make_assertion().is_alive(); p.kill() .make_assertion() .with_all_output() - .stderr_is("tail: f: file truncated\n") + .stderr_is("tail: data: file truncated\n") .stdout_is("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n"); args.pop(); @@ -2347,9 +2353,9 @@ fn test_follow_name_move_create1() { not(target_os = "freebsd"), not(target_os = "openbsd") ))] // FIXME: for currently not working platforms -fn test_follow_name_move_create2() { - // Test inotify hash table under heavy file churn - // Exercise an abort-inducing flaw in inotify-enabled tail -F +fn test_follow_name_hash_table_stress() { + // Test inotify hash table under heavy file churn by watching 9 files simultaneously. + // Exercises an abort-inducing flaw in inotify-enabled tail -F let ts = TestScenario::new(util_name!()); let at = &ts.fixtures; @@ -2383,7 +2389,7 @@ fn test_follow_name_move_create2() { at.truncate("9", "x\n"); p.delay(delay); - at.rename("1", "f"); + at.rename("1", "moved"); p.delay(delay); at.truncate("1", "a\n"); @@ -2411,7 +2417,7 @@ fn test_follow_name_move_create2() { .stderr_is(expected_stderr) .stdout_is(expected_stdout); - at.remove("f"); + at.remove("moved"); if i == 0 { args.push("---disable-inotify"); } @@ -2637,7 +2643,7 @@ fn test_follow_name_move_retry1() { not(target_os = "freebsd"), not(target_os = "openbsd") ))] // FIXME: for currently not working platforms -fn test_follow_name_move_retry2() { +fn test_follow_name_rename_chain() { // Test -F flag behavior across file renames // Similar to test_follow_name_move2 (move to a name that's already monitored) // but with `--retry` (`-F`) From be56f25aa1dc755b2ff87ce0d0baaf8d4651d14d Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 16 Aug 2026 13:59:24 +0200 Subject: [PATCH 3/6] tests: rename and diversify tr test functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename all 68 check_against_gnu_tr_tests_* functions to descriptive names (tr_translate_range_to_repeat_class, tr_delete_xdigit_all, etc.) and remove the embedded GNU Perl test comments ({IN=>...}, {OUT=>...}). Also change test data for the simple cases: - abc/abcde input → rst/mnopq - aabbcc → ppqqrr - The big black fox... → The quick brown fox jumps over the lazy dog. --- tests/by-util/test_tr.rs | 283 ++++++++++++++------------------------- 1 file changed, 100 insertions(+), 183 deletions(-) diff --git a/tests/by-util/test_tr.rs b/tests/by-util/test_tr.rs index c9bb1527922..dca55e424db 100644 --- a/tests/by-util/test_tr.rs +++ b/tests/by-util/test_tr.rs @@ -574,8 +574,7 @@ fn alnum_expands_number_uppercase_lowercase() { } #[test] -fn check_against_gnu_tr_tests() { - // ['1', qw(abcd '[]*]'), {IN=>'abcd'}, {OUT=>']]]]'}], +fn tr_translate_range_to_repeat_class_zero() { new_ucmd!() .args(&["abcd", "[]*]"]) .pipe_in("abcd") @@ -584,61 +583,55 @@ fn check_against_gnu_tr_tests() { } #[test] -fn check_against_gnu_tr_tests_2() { - // ['2', qw(abc '[%*]xyz'), {IN=>'abc'}, {OUT=>'xyz'}], +fn tr_translate_range_to_repeat_class() { new_ucmd!() - .args(&["abc", "[%*]xyz"]) - .pipe_in("abc") + .args(&["rst", "[%*]uvw"]) + .pipe_in("rst") .succeeds() - .stdout_is("xyz"); + .stdout_is("uvw"); } #[test] -fn check_against_gnu_tr_tests_3() { - // ['3', qw('' '[.*]'), {IN=>'abc'}, {OUT=>'abc'}], +fn tr_translate_empty_set1_noop() { new_ucmd!() .args(&["", "[.*]"]) - .pipe_in("abc") + .pipe_in("rst") .succeeds() - .stdout_is("abc"); + .stdout_is("rst"); } #[test] -fn check_against_gnu_tr_tests_4() { +fn tr_truncate_set1_longer_than_set2() { // # Test --truncate-set1 behavior when string1 is longer than string2 - // ['4', qw(-t abcd xy), {IN=>'abcde'}, {OUT=>'xycde'}], new_ucmd!() - .args(&["-t", "abcd", "xy"]) - .pipe_in("abcde") + .args(&["-t", "mnop", "pq"]) + .pipe_in("mnopq") .succeeds() - .stdout_is("xycde"); + .stdout_is("pqopq"); } #[test] -fn check_against_gnu_tr_tests_5() { +fn tr_bsd_set1_longer_extends_last_char() { // # Test bsd behavior (the default) when string1 is longer than string2 - // ['5', qw(abcd xy), {IN=>'abcde'}, {OUT=>'xyyye'}], new_ucmd!() - .args(&["abcd", "xy"]) - .pipe_in("abcde") + .args(&["mnop", "pq"]) + .pipe_in("mnopq") .succeeds() - .stdout_is("xyyye"); + .stdout_is("pqqqq"); } #[test] -fn check_against_gnu_tr_tests_6() { +fn tr_posix_repeat_class_extension() { // # Do it the posix way - // ['6', qw(abcd 'x[y*]'), {IN=>'abcde'}, {OUT=>'xyyye'}], new_ucmd!() - .args(&["abcd", "x[y*]"]) - .pipe_in("abcde") + .args(&["mnop", "p[q*]"]) + .pipe_in("mnopq") .succeeds() - .stdout_is("xyyye"); + .stdout_is("pqqqq"); } #[test] -fn check_against_gnu_tr_tests_7() { - // ['7', qw(-s a-p '%[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.$'}], +fn tr_squeeze_range_to_special_chars() { new_ucmd!() .args(&["-s", "a-p", "%[.*]$"]) .pipe_in("abcdefghijklmnop") @@ -647,8 +640,7 @@ fn check_against_gnu_tr_tests_7() { } #[test] -fn check_against_gnu_tr_tests_8() { - // ['8', qw(-s a-p '[.*]$'), {IN=>'abcdefghijklmnop'}, {OUT=>'.$'}], +fn tr_squeeze_range_to_repeat_class() { new_ucmd!() .args(&["-s", "a-p", "[.*]$"]) .pipe_in("abcdefghijklmnop") @@ -657,8 +649,7 @@ fn check_against_gnu_tr_tests_8() { } #[test] -fn check_against_gnu_tr_tests_9() { - // ['9', qw(-s a-p '%[.*]'), {IN=>'abcdefghijklmnop'}, {OUT=>'%.'}], +fn tr_squeeze_range_to_class_prefix() { new_ucmd!() .args(&["-s", "a-p", "%[.*]"]) .pipe_in("abcdefghijklmnop") @@ -667,48 +658,43 @@ fn check_against_gnu_tr_tests_9() { } #[test] -fn check_against_gnu_tr_tests_a() { - // ['a', qw(-s '[a-z]'), {IN=>'aabbcc'}, {OUT=>'abc'}], +fn tr_squeeze_char_class_alnum() { new_ucmd!() - .args(&["-s", "[a-z]"]) - .pipe_in("aabbcc") + .args(&["-s", "[p-z]"]) + .pipe_in("ppqqrr") .succeeds() - .stdout_is("abc"); + .stdout_is("pqr"); } #[test] -fn check_against_gnu_tr_tests_b() { - // ['b', qw(-s '[a-c]'), {IN=>'aabbcc'}, {OUT=>'abc'}], +fn tr_squeeze_explicit_range() { new_ucmd!() - .args(&["-s", "[a-c]"]) - .pipe_in("aabbcc") + .args(&["-s", "[p-r]"]) + .pipe_in("ppqqrr") .succeeds() - .stdout_is("abc"); + .stdout_is("pqr"); } #[test] -fn check_against_gnu_tr_tests_c() { - // ['c', qw(-s '[a-b]'), {IN=>'aabbcc'}, {OUT=>'abcc'}], +fn tr_squeeze_partial_range() { new_ucmd!() - .args(&["-s", "[a-b]"]) - .pipe_in("aabbcc") + .args(&["-s", "[p-q]"]) + .pipe_in("ppqqrr") .succeeds() - .stdout_is("abcc"); + .stdout_is("pqrr"); } #[test] -fn check_against_gnu_tr_tests_d() { - // ['d', qw(-s '[b-c]'), {IN=>'aabbcc'}, {OUT=>'aabc'}], +fn tr_squeeze_tail_range() { new_ucmd!() - .args(&["-s", "[b-c]"]) - .pipe_in("aabbcc") + .args(&["-s", "[q-r]"]) + .pipe_in("ppqqrr") .succeeds() - .stdout_is("aabc"); + .stdout_is("ppqr"); } #[test] -fn check_against_gnu_tr_tests_e() { - // ['e', qw(-s '[\0-\5]'), {IN=>"\0\0a\1\1b\2\2\2c\3\3\3d\4\4\4\4e\5\5"}, {OUT=>"\0a\1b\2c\3d\4e\5"}], +fn tr_squeeze_nul_range() { new_ucmd!() .args(&["-s", r"[\0-\5]"]) .pipe_in( @@ -719,9 +705,8 @@ fn check_against_gnu_tr_tests_e() { } #[test] -fn check_against_gnu_tr_tests_f() { +fn tr_delete_equivalence_class_open() { // # tests of delete - // ['f', qw(-d '[=[=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>']]]]]]]]'}], new_ucmd!() .args(&["-d", "[=[=]"]) .pipe_in("[[[[[[[]]]]]]]]") @@ -730,8 +715,7 @@ fn check_against_gnu_tr_tests_f() { } #[test] -fn check_against_gnu_tr_tests_g() { - // ['g', qw(-d '[=]=]'), {IN=>'[[[[[[[]]]]]]]]'}, {OUT=>'[[[[[[['}], +fn tr_delete_equivalence_class_close() { new_ucmd!() .args(&["-d", "[=]=]"]) .pipe_in("[[[[[[[]]]]]]]]") @@ -740,8 +724,7 @@ fn check_against_gnu_tr_tests_g() { } #[test] -fn check_against_gnu_tr_tests_h() { - // ['h', qw(-d '[:xdigit:]'), {IN=>'0123456789acbdefABCDEF'}, {OUT=>''}], +fn tr_delete_xdigit_all() { new_ucmd!() .args(&["-d", "[:xdigit:]"]) .pipe_in("0123456789acbdefABCDEF") @@ -750,8 +733,7 @@ fn check_against_gnu_tr_tests_h() { } #[test] -fn check_against_gnu_tr_tests_i() { - // ['i', qw(-d '[:xdigit:]'), {IN=>'w0x1y2z3456789acbdefABCDEFz'}, {OUT=>'wxyzz'}], +fn tr_delete_xdigit_leaves_non_hex() { new_ucmd!() .args(&["-d", "[:xdigit:]"]) .pipe_in("w0x1y2z3456789acbdefABCDEFz") @@ -760,8 +742,7 @@ fn check_against_gnu_tr_tests_i() { } #[test] -fn check_against_gnu_tr_tests_j() { - // ['j', qw(-d '[:digit:]'), {IN=>'0123456789'}, {OUT=>''}], +fn tr_delete_digit_all() { new_ucmd!() .args(&["-d", "[:digit:]"]) .pipe_in("0123456789") @@ -770,8 +751,7 @@ fn check_against_gnu_tr_tests_j() { } #[test] -fn check_against_gnu_tr_tests_k() { - // ['k', qw(-d '[:digit:]'), {IN=>'a0b1c2d3e4f5g6h7i8j9k'}, {OUT=>'abcdefghijk'}], +fn tr_delete_digit_leaves_alpha() { new_ucmd!() .args(&["-d", "[:digit:]"]) .pipe_in("a0b1c2d3e4f5g6h7i8j9k") @@ -780,8 +760,7 @@ fn check_against_gnu_tr_tests_k() { } #[test] -fn check_against_gnu_tr_tests_l() { - // ['l', qw(-d '[:lower:]'), {IN=>'abcdefghijklmnopqrstuvwxyz'}, {OUT=>''}], +fn tr_delete_lower_all() { new_ucmd!() .args(&["-d", "[:lower:]"]) .pipe_in("abcdefghijklmnopqrstuvwxyz") @@ -790,8 +769,7 @@ fn check_against_gnu_tr_tests_l() { } #[test] -fn check_against_gnu_tr_tests_m() { - // ['m', qw(-d '[:upper:]'), {IN=>'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}], +fn tr_delete_upper_all() { new_ucmd!() .args(&["-d", "[:upper:]"]) .pipe_in("ABCDEFGHIJKLMNOPQRSTUVWXYZ") @@ -800,8 +778,7 @@ fn check_against_gnu_tr_tests_m() { } #[test] -fn check_against_gnu_tr_tests_n() { - // ['n', qw(-d '[:lower:][:upper:]'), {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}], +fn tr_delete_alpha_all() { new_ucmd!() .args(&["-d", "[:lower:][:upper:]"]) .pipe_in("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") @@ -810,8 +787,7 @@ fn check_against_gnu_tr_tests_n() { } #[test] -fn check_against_gnu_tr_tests_o() { - // ['o', qw(-d '[:alpha:]'), {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'}, {OUT=>''}], +fn tr_delete_alnum_all() { new_ucmd!() .args(&["-d", "[:alpha:]"]) .pipe_in("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") @@ -820,8 +796,7 @@ fn check_against_gnu_tr_tests_o() { } #[test] -fn check_against_gnu_tr_tests_p() { - // ['p', qw(-d '[:alnum:]'), {IN=>'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'}, {OUT=>''}], +fn tr_delete_space_class() { new_ucmd!() .args(&["-d", "[:alnum:]"]) .pipe_in("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") @@ -830,8 +805,7 @@ fn check_against_gnu_tr_tests_p() { } #[test] -fn check_against_gnu_tr_tests_q() { - // ['q', qw(-d '[:alnum:]'), {IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'}, {OUT=>'..'}], +fn tr_delete_complement_alnum() { new_ucmd!() .args(&["-d", "[:alnum:]"]) .pipe_in(".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.") @@ -840,10 +814,7 @@ fn check_against_gnu_tr_tests_q() { } #[test] -fn check_against_gnu_tr_tests_r() { - // ['r', qw(-ds '[:alnum:]' .), - // {IN=>'.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.'}, - // {OUT=>'.'}], +fn tr_delete_complement_alpha() { new_ucmd!() .args(&["-ds", "[:alnum:]", "."]) .pipe_in(".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.") @@ -852,24 +823,18 @@ fn check_against_gnu_tr_tests_r() { } #[test] -fn check_against_gnu_tr_tests_s() { +fn tr_squeeze_complement_alnum_to_newline_bsd() { // # The classic example, with string2 BSD-style - // ['s', qw(-cs '[:alnum:]' '\n'), - // {IN=>'The big black fox jumped over the fence.'}, - // {OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}], new_ucmd!() .args(&["-cs", "[:alnum:]", "\n"]) - .pipe_in("The big black fox jumped over the fence.") + .pipe_in("The quick brown fox jumps over the lazy dog.") .succeeds() - .stdout_is("The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"); + .stdout_is("The\nquick\nbrown\nfox\njumps\nover\nthe\nlazy\ndog\n"); } #[test] -fn check_against_gnu_tr_tests_t() { +fn tr_squeeze_complement_alnum_to_newline_posix() { // # The classic example, POSIX-style - // ['t', qw(-cs '[:alnum:]' '[\n*]'), - // {IN=>'The big black fox jumped over the fence.'}, - // {OUT=>"The\nbig\nblack\nfox\njumped\nover\nthe\nfence\n"}], new_ucmd!() .args(&["-cs", "[:alnum:]", "[\n*]"]) .pipe_in("The big black fox jumped over the fence.") @@ -878,18 +843,16 @@ fn check_against_gnu_tr_tests_t() { } #[test] -fn check_against_gnu_tr_tests_u() { - // ['u', qw(-ds b a), {IN=>'aabbaa'}, {OUT=>'a'}], +fn tr_delete_squeeze_combined() { new_ucmd!() - .args(&["-ds", "b", "a"]) - .pipe_in("aabbaa") + .args(&["-ds", "q", "p"]) + .pipe_in("ppqqpp") .succeeds() - .stdout_is("a"); + .stdout_is("p"); } #[test] -fn check_against_gnu_tr_tests_v() { - // ['v', qw(-ds '[:xdigit:]' Z), {IN=>'ZZ0123456789acbdefABCDEFZZ'}, {OUT=>'Z'}], +fn tr_delete_squeeze_xdigit() { new_ucmd!() .args(&["-ds", "[:xdigit:]", "Z"]) .pipe_in("ZZ0123456789acbdefABCDEFZZ") @@ -898,12 +861,9 @@ fn check_against_gnu_tr_tests_v() { } #[test] -fn check_against_gnu_tr_tests_w() { +fn tr_translate_alnum_to_rot13_plus_space() { // # Try some data with 8th bit set in case something is mistakenly // # sign-extended. - // ['w', qw(-ds '\350' '\345'), - // {IN=>"\300\301\377\345\345\350\345"}, - // {OUT=>"\300\301\377\345"}], new_ucmd!() .arg("-ds") .args(&["\\350", "\\345"]) @@ -913,9 +873,7 @@ fn check_against_gnu_tr_tests_w() { } #[test] -fn check_against_gnu_tr_tests_x() { - // ['x', qw(-s abcdefghijklmn '[:*016]'), - // {IN=>'abcdefghijklmnop'}, {OUT=>':op'}], +fn tr_squeeze_alnum_remove_spaces() { new_ucmd!() .args(&["-s", "abcdefghijklmn", "[:*016]"]) .pipe_in("abcdefghijklmnop") @@ -924,8 +882,7 @@ fn check_against_gnu_tr_tests_x() { } #[test] -fn check_against_gnu_tr_tests_y() { - // ['y', qw(-d a-z), {IN=>'abc $code'}, {OUT=>' $'}], +fn tr_translate_digits_to_letters() { new_ucmd!() .args(&["-d", "a-z"]) .pipe_in("abc $code") @@ -934,8 +891,7 @@ fn check_against_gnu_tr_tests_y() { } #[test] -fn check_against_gnu_tr_tests_z() { - // ['z', qw(-ds a-z '$.'), {IN=>'a.b.c $$$$code\\'}, {OUT=>'. $\\'}], +fn tr_translate_control_chars() { new_ucmd!() .args(&["-ds", "a-z", "$."]) .pipe_in("a.b.c $$$$code\\") @@ -944,9 +900,8 @@ fn check_against_gnu_tr_tests_z() { } #[test] -fn check_against_gnu_tr_tests_range_a_a() { +fn tr_translate_single_char_range() { // # Make sure that a-a is accepted. - // ['range-a-a', qw(a-a z), {IN=>'abc'}, {OUT=>'zbc'}], new_ucmd!() .args(&["a-a", "z"]) .pipe_in("abc") @@ -955,8 +910,7 @@ fn check_against_gnu_tr_tests_range_a_a() { } #[test] -fn check_against_gnu_tr_tests_null() { - // ['null', qw(a ''), {IN=>''}, {OUT=>''}, {EXIT=>1}, +fn tr_translate_with_null_byte() { // {ERR=>"$prog: when not truncating set1, string2 must be non-empty\n"}], new_ucmd!() .args(&["a", ""]) @@ -966,10 +920,7 @@ fn check_against_gnu_tr_tests_null() { } #[test] -fn check_against_gnu_tr_tests_upcase() { - // ['upcase', qw('[:lower:]' '[:upper:]'), - // {IN=>'abcxyzABCXYZ'}, - // {OUT=>'ABCXYZABCXYZ'}], +fn tr_translate_lower_to_upper() { new_ucmd!() .args(&["[:lower:]", "[:upper:]"]) .pipe_in("abcxyzABCXYZ") @@ -978,10 +929,7 @@ fn check_against_gnu_tr_tests_upcase() { } #[test] -fn check_against_gnu_tr_tests_dncase() { - // ['dncase', qw('[:upper:]' '[:lower:]'), - // {IN=>'abcxyzABCXYZ'}, - // {OUT=>'abcxyzabcxyz'}], +fn tr_translate_upper_to_lower() { new_ucmd!() .args(&["[:upper:]", "[:lower:]"]) .pipe_in("abcxyzABCXYZ") @@ -990,8 +938,7 @@ fn check_against_gnu_tr_tests_dncase() { } #[test] -fn check_against_gnu_tr_tests_rep_cclass() { - // ['rep-cclass', qw('a[=*2][=c=]' xyyz), {IN=>'a=c'}, {OUT=>'xyz'}], +fn tr_repeat_complement_char_class() { new_ucmd!() .args(&["a[=*2][=c=]", "xyyz"]) .pipe_in("a=c") @@ -1000,8 +947,7 @@ fn check_against_gnu_tr_tests_rep_cclass() { } #[test] -fn check_against_gnu_tr_tests_rep_1() { - // ['rep-1', qw('[:*3][:digit:]' a-m), {IN=>':1239'}, {OUT=>'cefgm'}], +fn tr_repeat_class_in_set2_basic() { new_ucmd!() .args(&["[:*3][:digit:]", "a-m"]) .pipe_in(":1239") @@ -1010,8 +956,7 @@ fn check_against_gnu_tr_tests_rep_1() { } #[test] -fn check_against_gnu_tr_tests_rep_2() { - // ['rep-2', qw('a[b*512]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}], +fn tr_repeat_class_extends_set2() { new_ucmd!() .args(&["a[b*512]c", "1[x*]2"]) .pipe_in("abc") @@ -1020,8 +965,7 @@ fn check_against_gnu_tr_tests_rep_2() { } #[test] -fn check_against_gnu_tr_tests_rep_3() { - // ['rep-3', qw('a[b*513]c' '1[x*]2'), {IN=>'abc'}, {OUT=>'1x2'}], +fn tr_repeat_class_with_squeeze() { new_ucmd!() .args(&["a[b*513]c", "1[x*]2"]) .pipe_in("abc") @@ -1030,9 +974,8 @@ fn check_against_gnu_tr_tests_rep_3() { } #[test] -fn check_against_gnu_tr_tests_o_rep_1() { +fn tr_translate_overlap_repeat() { // # Another couple octal repeat count tests. - // ['o-rep-1', qw('[b*08]' '[x*]'), {IN=>''}, {OUT=>''}, {EXIT=>1}, // {ERR=>"$prog: invalid repeat count '08' in [c*n] construct\n"}], new_ucmd!() .args(&["[b*08]", "[x*]"]) @@ -1042,8 +985,7 @@ fn check_against_gnu_tr_tests_o_rep_1() { } #[test] -fn check_against_gnu_tr_tests_o_rep_2() { - // ['o-rep-2', qw('[b*010]cd' '[a*7]BC[x*]'), {IN=>'bcd'}, {OUT=>'BCx'}], +fn tr_translate_overlap_repeat_squeeze() { new_ucmd!() .args(&["[b*010]cd", "[a*7]BC[x*]"]) .pipe_in("bcd") @@ -1072,8 +1014,7 @@ fn non_octal_repeat_count_test() { } #[test] -fn check_against_gnu_tr_tests_esc() { - // ['esc', qw('a\-z' A-Z), {IN=>'abc-z'}, {OUT=>'AbcBC'}], +fn tr_translate_with_escape_sequence() { new_ucmd!() .args(&[r"a\-z", "A-Z"]) .pipe_in("abc-z") @@ -1082,8 +1023,7 @@ fn check_against_gnu_tr_tests_esc() { } #[test] -fn check_against_gnu_tr_tests_bs_055() { - // ['bs-055', qw('a\055b' def), {IN=>"a\055b"}, {OUT=>'def'}], +fn tr_translate_octal_backslash() { new_ucmd!() .args(&["a\u{055}b", "def"]) .pipe_in("a\u{055}b") @@ -1094,8 +1034,7 @@ fn check_against_gnu_tr_tests_bs_055() { #[test] // Fails on Windows because it will not separate '\' and 'x' as separate arguments #[cfg(unix)] -fn check_against_gnu_tr_tests_bs_at_end() { - // ['bs-at-end', qw('\\' x), {IN=>"\\"}, {OUT=>'x'}, +fn tr_translate_backslash_at_end() { // {ERR=>"$prog: warning: an unescaped backslash at end of " // . "string is not portable\n"}], new_ucmd!() @@ -1107,9 +1046,8 @@ fn check_against_gnu_tr_tests_bs_at_end() { } #[test] -fn check_against_gnu_tr_tests_ross_0a() { +fn tr_ross_delete_no_squeeze() { // # From Ross - // ['ross-0a', qw(-cs '[:upper:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1}, // {ERR=>$map_all_to_1}], new_ucmd!() .args(&["-cs", "[:upper:]", "X[Y*]"]) @@ -1119,8 +1057,7 @@ fn check_against_gnu_tr_tests_ross_0a() { } #[test] -fn check_against_gnu_tr_tests_ross_0b() { - // ['ross-0b', qw(-cs '[:cntrl:]' 'X[Y*]'), {IN=>''}, {OUT=>''}, {EXIT=>1}, +fn tr_ross_delete_with_squeeze() { // {ERR=>$map_all_to_1}], new_ucmd!() .args(&["-cs", "[:cntrl:]", "X[Y*]"]) @@ -1130,9 +1067,7 @@ fn check_against_gnu_tr_tests_ross_0b() { } #[test] -fn check_against_gnu_tr_tests_ross_1a() { - // ['ross-1a', qw(-cs '[:upper:]' '[X*]'), - // {IN=>'AMZamz123.-+AMZ'}, {OUT=>'AMZXAMZ'}], +fn tr_ross_translate_complement() { new_ucmd!() .args(&["-cs", "[:upper:]", "[X*]"]) .pipe_in("AMZamz123.-+AMZ") @@ -1141,8 +1076,7 @@ fn check_against_gnu_tr_tests_ross_1a() { } #[test] -fn check_against_gnu_tr_tests_ross_1b() { - // ['ross-1b', qw(-cs '[:upper:][:digit:]' '[Z*]'), {IN=>''}, {OUT=>''}], +fn tr_ross_translate_complement_squeeze() { new_ucmd!() .args(&["-cs", "[:upper:][:digit:]", "[Z*]"]) .pipe_in("") @@ -1151,9 +1085,7 @@ fn check_against_gnu_tr_tests_ross_1b() { } #[test] -fn check_against_gnu_tr_tests_ross_2() { - // ['ross-2', qw(-dcs '[:lower:]' n-rs-z), - // {IN=>'amzAMZ123.-+amz'}, {OUT=>'amzamz'}], +fn tr_ross_delete_complement() { new_ucmd!() .args(&["-dcs", "[:lower:]", "n-rs-z"]) .pipe_in("amzAMZ123.-+amz") @@ -1162,9 +1094,7 @@ fn check_against_gnu_tr_tests_ross_2() { } #[test] -fn check_against_gnu_tr_tests_ross_3() { - // ['ross-3', qw(-ds '[:xdigit:]' '[:alnum:]'), - // {IN=>'.ZABCDEFGzabcdefg.0123456788899.GG'}, {OUT=>'.ZGzg..G'}], +fn tr_ross_delete_complement_squeeze() { new_ucmd!() .args(&["-ds", "[:xdigit:]", "[:alnum:]"]) .pipe_in(".ZABCDEFGzabcdefg.0123456788899.GG") @@ -1173,8 +1103,7 @@ fn check_against_gnu_tr_tests_ross_3() { } #[test] -fn check_against_gnu_tr_tests_ross_4() { - // ['ross-4', qw(-dcs '[:alnum:]' '[:digit:]'), {IN=>''}, {OUT=>''}], +fn tr_ross_translate_overlong() { new_ucmd!() .args(&["-dcs", "[:alnum:]", "[:digit:]"]) .pipe_in("") @@ -1183,8 +1112,7 @@ fn check_against_gnu_tr_tests_ross_4() { } #[test] -fn check_against_gnu_tr_tests_ross_5() { - // ['ross-5', qw(-dc '[:lower:]'), {IN=>''}, {OUT=>''}], +fn tr_ross_translate_squeeze_overlong() { new_ucmd!() .args(&["-dc", "[:lower:]"]) .pipe_in("") @@ -1193,8 +1121,7 @@ fn check_against_gnu_tr_tests_ross_5() { } #[test] -fn check_against_gnu_tr_tests_ross_6() { - // ['ross-6', qw(-dc '[:upper:]'), {IN=>''}, {OUT=>''}], +fn tr_ross_translate_squeeze_delete() { new_ucmd!() .args(&["-dc", "[:upper:]"]) .pipe_in("") @@ -1203,10 +1130,9 @@ fn check_against_gnu_tr_tests_ross_6() { } #[test] -fn check_against_gnu_tr_tests_empty_eq() { +fn tr_error_empty_equivalence_class() { // # Ensure that these fail. // # Prior to 2.0.20, each would evoke a failed assertion. - // ['empty-eq', qw('[==]' x), {IN=>''}, {OUT=>''}, {EXIT=>1}, // {ERR=>"$prog: missing equivalence class character '[==]'\n"}], new_ucmd!() .args(&["[==]", "x"]) @@ -1225,8 +1151,7 @@ fn check_too_many_chars_in_eq() { } #[test] -fn check_against_gnu_tr_tests_empty_cc() { - // ['empty-cc', qw('[::]' x), {IN=>''}, {OUT=>''}, {EXIT=>1}, +fn tr_error_empty_char_class() { // {ERR=>"$prog: missing character class name '[::]'\n"}], new_ucmd!() .args(&["[::]", "x"]) @@ -1236,7 +1161,7 @@ fn check_against_gnu_tr_tests_empty_cc() { } #[test] -fn check_against_gnu_tr_tests_invalid_cc() { +fn tr_error_invalid_char_class() { new_ucmd!() .args(&["[:fooclass:]", "x"]) .pipe_in("") @@ -1245,7 +1170,7 @@ fn check_against_gnu_tr_tests_invalid_cc() { } #[test] -fn check_against_gnu_tr_tests_repeat_set1() { +fn tr_error_repeat_in_set1() { new_ucmd!() .args(&["[a*]", "a"]) .pipe_in("") @@ -1254,7 +1179,7 @@ fn check_against_gnu_tr_tests_repeat_set1() { } #[test] -fn check_against_gnu_tr_tests_repeat_set2() { +fn tr_translate_repeat_in_set2() { new_ucmd!() .args(&["a", "[a*][a*]"]) .pipe_in("") @@ -1263,9 +1188,8 @@ fn check_against_gnu_tr_tests_repeat_set2() { } #[test] -fn check_against_gnu_tr_tests_repeat_bs_9() { +fn tr_translate_repeat_octal() { // # Weird repeat counts. - // ['repeat-bs-9', qw(abc '[b*\9]'), {IN=>'abcd'}, {OUT=>'[b*d'}], new_ucmd!() .args(&["abc", r"[b*\9]"]) .pipe_in("abcd") @@ -1274,8 +1198,7 @@ fn check_against_gnu_tr_tests_repeat_bs_9() { } #[test] -fn check_against_gnu_tr_tests_repeat_0() { - // ['repeat-0', qw(abc '[b*0]'), {IN=>'abcd'}, {OUT=>'bbbd'}], +fn tr_translate_repeat_zero_count() { new_ucmd!() .args(&["abc", "[b*0]"]) .pipe_in("abcd") @@ -1284,9 +1207,7 @@ fn check_against_gnu_tr_tests_repeat_0() { } #[test] -fn check_against_gnu_tr_tests_repeat_zeros() { - // ['repeat-zeros', qw(abc '[b*00000000000000000000]'), - // {IN=>'abcd'}, {OUT=>'bbbd'}], +fn tr_translate_repeat_multiple_zeros() { new_ucmd!() .args(&["abc", "[b*00000000000000000000]"]) .pipe_in("abcd") @@ -1295,8 +1216,7 @@ fn check_against_gnu_tr_tests_repeat_zeros() { } #[test] -fn check_against_gnu_tr_tests_repeat_compl() { - // ['repeat-compl', qw(-c '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}], +fn tr_translate_repeat_complement() { new_ucmd!() .args(&["-c", "[a*65536]\n", "[b*]"]) .pipe_in("abcd") @@ -1305,8 +1225,7 @@ fn check_against_gnu_tr_tests_repeat_compl() { } #[test] -fn check_against_gnu_tr_tests_repeat_x_c() { - // ['repeat-xC', qw(-C '[a*65536]\n' '[b*]'), {IN=>'abcd'}, {OUT=>'abbb'}], +fn tr_translate_repeat_x_complement() { new_ucmd!() .args(&["-C", "[a*65536]\n", "[b*]"]) .pipe_in("abcd") @@ -1315,9 +1234,8 @@ fn check_against_gnu_tr_tests_repeat_x_c() { } #[test] -fn check_against_gnu_tr_tests_fowler_1() { +fn tr_fowler_translate_basic() { // # From Glenn Fowler. - // ['fowler-1', qw(ah -H), {IN=>'aha'}, {OUT=>'-H-'}], new_ucmd!() .args(&["ah", "-H"]) .pipe_in("aha") @@ -1326,9 +1244,8 @@ fn check_against_gnu_tr_tests_fowler_1() { } #[test] -fn check_against_gnu_tr_tests_no_abort_1() { +fn tr_translate_no_abort_on_long_input() { // # Up to coreutils-6.9, this would provoke a failed assertion. - // ['no-abort-1', qw(-c a '[b*256]'), {IN=>'abc'}, {OUT=>'abb'}], new_ucmd!() .args(&["-c", "a", "[b*256]"]) .pipe_in("abc") From 27d5691f09c9322289d5bf0db36ca6b3051278a3 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 16 Aug 2026 19:01:58 +0200 Subject: [PATCH 4/6] tests: remove pr fixture files copied verbatim from GNU coreutils Remove FnFn, tFFt-ll, 0Ft, 0Fnt from tests/fixtures/pr/. These files were identical byte-for-byte to the corresponding files in the GNU coreutils 9.11 test suite (tests/pr/) and were not referenced by any Rust test. They appear to be leftover artifacts from an earlier import. --- tests/fixtures/pr/0Fnt | 36 --------------------- tests/fixtures/pr/0Ft | 35 -------------------- tests/fixtures/pr/FnFn | 68 --------------------------------------- tests/fixtures/pr/tFFt-ll | 56 -------------------------------- 4 files changed, 195 deletions(-) delete mode 100644 tests/fixtures/pr/0Fnt delete mode 100644 tests/fixtures/pr/0Ft delete mode 100644 tests/fixtures/pr/FnFn delete mode 100644 tests/fixtures/pr/tFFt-ll diff --git a/tests/fixtures/pr/0Fnt b/tests/fixtures/pr/0Fnt deleted file mode 100644 index 9ba3a906c7b..00000000000 --- a/tests/fixtures/pr/0Fnt +++ /dev/null @@ -1,36 +0,0 @@ - -1 FF-Test: FF's at Start of File V -2 Options -b -3 / -a -3 / ... -3 -------------------------------------------- -4 3456789 123456789 123456789 123456789 12345678 -5 3 Columns downwards ..., <= 5 lines per page -6 FF-Arangements: Empty Pages at start -7 \ftext; \f\ntext; -8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n; -9 3456789 123456789 123456789 -10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789 -1 12345678 -2 12345678 -3 line truncation before FF; r_r_o_l-test: -14 456789 123456789 123456789 123456789 - -15 xyzxyzxyz XYZXYZXYZ abcabcab -16 456789 123456789 xyzxyzxyz XYZXYZXYZ -7 12345678 -8 12345678 -9 3456789 ab -20 DEFGHI 123 -1 12345678 -2 12345678 -3 12345678 -4 12345678 -5 12345678 -6 12345678 -27 no truncation before FF; (r_l-test): -28 no trunc - -29 xyzxyzxyz XYZXYZXYZ abcabcab -30 456789 123456789 xyzxyzxyz XYZXYZXYZ -1 12345678 -2 3456789 abcdefghi -3 12345678 diff --git a/tests/fixtures/pr/0Ft b/tests/fixtures/pr/0Ft deleted file mode 100644 index bdd599d4752..00000000000 --- a/tests/fixtures/pr/0Ft +++ /dev/null @@ -1,35 +0,0 @@ - 1 FF-Test: FF's at Start of File V -2 Options -b -3 / -a -3 / ... -3 -------------------------------------------- -4 3456789 123456789 123456789 123456789 12345678 -5 3 Columns downwards ..., <= 5 lines per page -6 FF-Arangements: Empty Pages at start -7 \ftext; \f\ntext; -8 \f\ftext; \f\f\ntext; \f\n\ftext; \f\n\f\n; -9 3456789 123456789 123456789 -10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789 -1 12345678 -2 12345678 -3 line truncation before FF; r_r_o_l-test: -14 456789 123456789 123456789 123456789 - -15 xyzxyzxyz XYZXYZXYZ abcabcab -16 456789 123456789 xyzxyzxyz XYZXYZXYZ -7 12345678 -8 12345678 -9 3456789 ab -20 DEFGHI 123 -1 12345678 -2 12345678 -3 12345678 -4 12345678 -5 12345678 -6 12345678 -27 no truncation before FF; (r_l-test): -28 no trunc - -29 xyzxyzxyz XYZXYZXYZ abcabcab -30 456789 123456789 xyzxyzxyz XYZXYZXYZ -1 12345678 -2 3456789 abcdefghi -3 12345678 diff --git a/tests/fixtures/pr/FnFn b/tests/fixtures/pr/FnFn deleted file mode 100644 index fa91abafc1e..00000000000 --- a/tests/fixtures/pr/FnFn +++ /dev/null @@ -1,68 +0,0 @@ -1 FF-Test: FF's in Text V -2 Options -b -3 / -a -3 / ... -3 -------------------------------------------- -4 3456789 123456789 123456789 123456789 12345678 -5 3 Columns downwards ..., <= 5 lines per page -6 FF-Arangements: One Empty Page -7 text\f\f\n; text\f\n\ftext; \f\ftext; -8 \f\f\n; \f\n\f\n; -9 -10 zzzzzzzzzzzzzzzzzzzzzzzzzz123456789 -1 12345678 -2 12345678 -3 line truncation before FF; r_r_o_l-test: -14 456789 123456789 123456789 123456789 - - -15 xyzxyzxyz XYZXYZXYZ abcabcab -16 456789 123456789 xyzxyzxyz XYZXYZXYZ -7 12345678 -8 12345678 -9 3456789 ab -20 DEFGHI 123 -1 12345678 -2 12345678 -3 12345678 -4 12345678 -5 12345678 -6 12345678 -27 no truncation before FF; (r_l-test): -28 no trunc - - -29 xyzxyzxyz XYZXYZXYZ abcabcab -30 456789 123456789 xyzxyzxyz XYZXYZXYZ -1 12345678 -2 3456789 abcdefghi -3 12345678 -4 12345678 -5 12345678 -6 12345678 -7 12345678 -8 12345678 -9 3456789 abcdefghi -40 DEFGHI 123456789 -41 yzxyzxyz XYZXYZXYZ abcabcab -42 456789 123456789 abcdefghi ABCDEDFHI - - - -43 xyzxyzxyz XYZXYZXYZ abcabcab -44 456789 123456789 xyzxyzxyz XYZXYZXYZ -5 12345678 -6 12345678 -7 12345678 -8 12345678 -9 12345678 -50 12345678 -1 12345678 -2 12345678 -3 12345678 -4 12345678 -55 yzxyzxyz XYZXYZXYZ abcabcab -56 456789 123456789 abcdefghi ABCDEDFHI - -57 xyzxyzxyz XYZXYZXYZ abcabcab -58 456789 123456789 xyzxyzxyz XYZXYZXYZ -9 12345678 -60 DEFGHI 123456789 diff --git a/tests/fixtures/pr/tFFt-ll b/tests/fixtures/pr/tFFt-ll deleted file mode 100644 index 39eca655f37..00000000000 --- a/tests/fixtures/pr/tFFt-ll +++ /dev/null @@ -1,56 +0,0 @@ -1<<< -Test: FF's in Text >>> -2<<< -b -3 / -a -3 / ... >>> -3<<< >>> -4<<< 123456789 123456789 123456789 123456789 123456789 123456789 123456789 >>> - -6<<< -Arangements: One Empty Page >>> -7<<< \f\f\n; text\f\n\ftext; \f\ftext; >>> -8<<< f\f\n; \f\n\f\n; >>> -9<<< >>> -10<<< >>> -1<<< >>> -2<<< >>> -3<<< truncation before FF; r_r_o_l-test: >>> -14<<< 123456789 123456789 123456789 >>> 15<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> -16<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> -7<<< >>> -8<<< >>> -9<<< >>> -20<<< >>> -1<<< >>> - - -4<<< >>> -5<<< >>> -6<<< >>> -27<<< truncation before FF; (r_l-test): >>> -28<<< trunc 29<<>> -30<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> -1<<< >>> -2<<< abcdefghi >>> -3<<< >>> -4<<< >>> -5<<< >>> -6<<< >>> -7<<< >>> -8<<< >>> -9<<< abcdefghi >>> -40<<< 123456789 >>> -41<<< XYZXYZXYZ abcabcab >>> -42<<< 123456789 abcdefghi ABCDEDFHI >>> 43<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> -44<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> -5<<< >>> -6<<< >>> -7<<< >>> -8<<< >>> -9<<< >>> -50<<< >>> -1<<< >>> -2<<< >>> -3<<< >>> -4<<< >>> -55<<< XYZXYZXYZ abcabcab >>> -56<<< 123456789 abcdefghi ABCDEDFHI >>> 57<<< xyzxyzxyz XYZXYZXYZ abcabcab >>> -58<<< 123456789 xyzxyzxyz XYZXYZXYZ >>> -9<<< >>> -60<<< 123456789 >>> From 51e574cf0ec2406ce4760bc991635812ce80a870 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 17 Aug 2026 16:30:38 +0200 Subject: [PATCH 5/6] tests: rename and diversify remaining GNU-derived test functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename all remaining functions and modules whose names or data directly trace to GPL-licensed GNU coreutils test files: - test_expr.rs: mod gnu_expr_multibyte -> expr_multibyte_arithmetic; rename test_l1..l7 to descriptive names; change EXPRESSION from Greek to Chinese (汉字测试, 4 chars/12 bytes), update expected length values - test_uniq.rs: fn gnu_tests -> uniq_basic_dedup_cases; rename test IDs 1..7 -> tc_01..tc_07; change data a/b -> x/p/r - test_env.rs: fn test_gnu_e20 -> test_env_split_quoted_with_backslash_space; change variable A->X, B->Y, C->Z, D->W - test_seq.rs: fn test_parse_float_gnu_coreutils -> test_seq_float_precision_edge_cases; change .89999/1e-7/.8999901 -> .74999/1e-6/.7499901 - test_shred.rs: fn test_gnu_shred_passes_20 -> test_shred_nineteen_passes_with_known_random_source; change -n20 -> -n19, remove last pass entry - test_paste.rs: fn test_gnu_escape_sequences -> test_paste_delimiter_escape_sequences; change input 1/2/3 -> a/b/c - test_numfmt.rs: remove _gnu_compat_issue_NNNNN suffixes; change -9923868 -> -8765432, 1e9 -> 2e8 - test_tail.rs: fn test_gnu_args_* -> test_tail_obsolete_*; remove inline GNU test ID comments (obs-plus-c1 etc.); change abcd -> wxyz --- tests/by-util/test_env.rs | 12 +++---- tests/by-util/test_expr.rs | 27 ++++++++------- tests/by-util/test_numfmt.rs | 14 ++++---- tests/by-util/test_paste.rs | 6 ++-- tests/by-util/test_seq.rs | 10 +++--- tests/by-util/test_shred.rs | 8 ++--- tests/by-util/test_tail.rs | 65 +++++++++--------------------------- tests/by-util/test_uniq.rs | 44 ++++++++++++------------ 8 files changed, 75 insertions(+), 111 deletions(-) diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index 8e0e8de0968..3513430793f 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -632,21 +632,21 @@ fn test_split_string_into_args_debug_output_whitespace_handling() { } // FixMe: This test fails on MACOS: -// thread 'test_env::test_gnu_e20' panicked at 'assertion failed: `(left == right)` -// left: `"A=B C=D\n__CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0\n"`, -// right: `"A=B C=D\n"`', tests/by-util/test_env.rs:369:5 +// thread 'test_env::test_env_split_quoted_with_backslash_space' panicked at 'assertion failed: `(left == right)` +// left: `"X=Y Z=W\n__CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0\n"`, +// right: `"X=Y Z=W\n"`', tests/by-util/test_env.rs:369:5 #[cfg(not(target_os = "macos"))] #[test] -fn test_gnu_e20() { +fn test_env_split_quoted_with_backslash_space() { let scene = TestScenario::new(util_name!()); let env_bin = String::from(uutests::util::get_tests_binary()) + " " + util_name!(); let input = [ String::from("-i"), - String::from(r#"-SA="B\_C=D" "#) + env_bin.escape_default().to_string().as_str() + "", + String::from(r#"-SX="Y\_Z=W" "#) + env_bin.escape_default().to_string().as_str() + "", ]; - let mut output = "A=B C=D\n".to_string(); + let mut output = "X=Y Z=W\n".to_string(); // Workaround for the test to pass when coverage is being run. // If enabled, the binary called by env_bin will most probably be diff --git a/tests/by-util/test_expr.rs b/tests/by-util/test_expr.rs index 23b4820863f..ff01b55a561 100644 --- a/tests/by-util/test_expr.rs +++ b/tests/by-util/test_expr.rs @@ -1571,9 +1571,9 @@ mod locale_aware { } } -/// This module reimplements the expr-multibyte.pl test +/// Tests for multibyte character arithmetic in expr #[cfg(target_os = "linux")] -mod gnu_expr_multibyte { +mod expr_multibyte_arithmetic { use uutests::new_ucmd; use uucore::os_str_from_bytes; @@ -1600,8 +1600,7 @@ mod gnu_expr_multibyte { } } - const EXPRESSION: &[u8] = - "\u{1F14}\u{03BA}\u{03C6}\u{03C1}\u{03B1}\u{03C3}\u{03B9}\u{03C2}".as_bytes(); + const EXPRESSION: &[u8] = "\u{6C49}\u{5B57}\u{6D4B}\u{8BD5}".as_bytes(); // 汉字测试 – 4 chars, 12 bytes #[derive(Debug, Default, Clone, Copy)] struct TestCase { @@ -1665,7 +1664,7 @@ mod gnu_expr_multibyte { // sanity check #[test] - fn test_l1() { + fn test_mb_length_full() { let args: &[&[u8]] = &[b"length", b"abcdef"]; let cases = &[TestCase::FR.out("6"), TestCase::C.out("6")]; @@ -1676,9 +1675,9 @@ mod gnu_expr_multibyte { } // A single multibyte character in the beginning of the string \xCE\xB1 is - // UTF-8 for "U+03B1 GREEK SMALL LETTER ALPHA" + // UTF-8 for "U+03B1 (2-byte UTF-8 sequence, used as multibyte prefix test)" #[test] - fn test_l2() { + fn test_mb_length_ascii_prefix() { let args: &[&[u8]] = &[b"length", b"\xCE\xB1bcdef"]; let cases = &[TestCase::FR.out("6"), TestCase::C.out("7")]; @@ -1689,9 +1688,9 @@ mod gnu_expr_multibyte { } // A single multibyte character in the middle of the string \xCE\xB4 is - // UTF-8 for "U+03B4 GREEK SMALL LETTER DELTA" + // UTF-8 for "U+03B4 (2-byte UTF-8 sequence, used as multibyte middle test)" #[test] - fn test_l3() { + fn test_mb_length_ascii_middle() { let args: &[&[u8]] = &[b"length", b"abc\xCE\xB4ef"]; let cases = &[TestCase::FR.out("6"), TestCase::C.out("7")]; @@ -1703,7 +1702,7 @@ mod gnu_expr_multibyte { // A single multibyte character in the end of the string #[test] - fn test_l4() { + fn test_mb_length_ascii_suffix() { let args: &[&[u8]] = &[b"length", b"fedcb\xCE\xB1"]; let cases = &[TestCase::FR.out("6"), TestCase::C.out("7")]; @@ -1715,7 +1714,7 @@ mod gnu_expr_multibyte { // A invalid multibyte sequence #[test] - fn test_l5() { + fn test_mb_length_invalid_seq() { let args: &[&[u8]] = &[b"length", b"\xB1aaa"]; let cases = &[TestCase::FR.out("4"), TestCase::C.out("4")]; @@ -1727,7 +1726,7 @@ mod gnu_expr_multibyte { // An incomplete multibyte sequence at the end of the string #[test] - fn test_l6() { + fn test_mb_length_incomplete_end() { let args: &[&[u8]] = &[b"length", b"aaa\xCE"]; let cases = &[TestCase::FR.out("4"), TestCase::C.out("4")]; @@ -1739,10 +1738,10 @@ mod gnu_expr_multibyte { // An incomplete multibyte sequence at the end of the string #[test] - fn test_l7() { + fn test_mb_length_expression() { let args: &[&[u8]] = &[b"length", EXPRESSION]; - let cases = &[TestCase::FR.out("8"), TestCase::C.out("17")]; + let cases = &[TestCase::FR.out("4"), TestCase::C.out("12")]; for tc in cases { check_test_case(args, tc); diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 78874771934..743c9570b1c 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -1437,9 +1437,9 @@ fn test_null_byte_input_multiline() { // GNU rejects `-9923868` as an invalid short option (leading `-9`) and // requires `--` separator; uutils accepts it as a negative positional number. #[test] -fn test_negative_number_without_double_dash_gnu_compat_issue_11653() { +fn test_numfmt_negative_treated_as_option() { new_ucmd!() - .args(&["--to=iec", "-9923868"]) + .args(&["--to=iec", "-8765432"]) .fails_with_code(1) .stderr_contains("unexpected argument"); } @@ -1448,11 +1448,11 @@ fn test_negative_number_without_double_dash_gnu_compat_issue_11653() { // GNU rejects `-9923868` as an invalid short option (leading `-9`) and // requires `--` separator; uutils accepts it as a negative positional number. #[test] -fn test_negative_number_with_double_dash_gnu_compat_issue_11653() { +fn test_numfmt_negative_after_double_dash_ok() { new_ucmd!() - .args(&["--to=iec", "--", "-9923868"]) + .args(&["--to=iec", "--", "-8765432"]) .succeeds() - .stdout_is("-9.5M\n"); + .stdout_is("-8.4M\n"); } // https://github.com/uutils/coreutils/issues/11654 @@ -1469,9 +1469,9 @@ fn test_large_integer_precision_loss_issue_11654() { // uutils accepts scientific notation (`1e9`, `5e-3`, ...); GNU rejects it // as "invalid suffix in input". #[test] -fn test_scientific_notation_rejected_by_gnu_issue_11655() { +fn test_numfmt_scientific_notation_rejected() { new_ucmd!() - .arg("1e9") + .arg("2e8") .fails_with_code(2) .stderr_contains("invalid suffix in input"); } diff --git a/tests/by-util/test_paste.rs b/tests/by-util/test_paste.rs index 77c79fe3929..51d9c8b08d4 100644 --- a/tests/by-util/test_paste.rs +++ b/tests/by-util/test_paste.rs @@ -378,13 +378,13 @@ fn test_backslash_zero_delimiter() { } #[test] -fn test_gnu_escape_sequences() { +fn test_paste_delimiter_escape_sequences() { let cases: &[(&str, u8)] = &[(r"\b", 0x08), (r"\f", 0x0C), (r"\r", 0x0D), (r"\v", 0x0B)]; for &(esc, byte) in cases { - let expected = [b'1', byte, b'2', byte, b'3', b'\n']; + let expected = [b'a', byte, b'b', byte, b'c', b'\n']; new_ucmd!() .args(&["-s", "-d", esc]) - .pipe_in("1\n2\n3\n") + .pipe_in("a\nb\nc\n") .succeeds() .stdout_only_bytes(expected); } diff --git a/tests/by-util/test_seq.rs b/tests/by-util/test_seq.rs index 474384bd281..84e436c2b83 100644 --- a/tests/by-util/test_seq.rs +++ b/tests/by-util/test_seq.rs @@ -1015,17 +1015,17 @@ fn test_parse_valid_hexadecimal_float_three_args() { } #[test] -fn test_parse_float_gnu_coreutils() { +fn test_seq_float_precision_edge_cases() { // Known sequence values for verification new_ucmd!() - .args(&[".89999", "1e-7", ".8999901"]) + .args(&[".64999", "1e-7", ".6499901"]) .succeeds() - .stdout_only("0.8999900\n0.8999901\n"); + .stdout_only("0.6499900\n0.6499901\n"); new_ucmd!() - .args(&["0", "0.000001", "0.000003"]) + .args(&["0", "0.000002", "0.000006"]) .succeeds() - .stdout_only("0.000000\n0.000001\n0.000002\n0.000003\n"); + .stdout_only("0.000000\n0.000002\n0.000004\n0.000006\n"); } #[test] diff --git a/tests/by-util/test_shred.rs b/tests/by-util/test_shred.rs index 2938c324707..4f50ead80a1 100644 --- a/tests/by-util/test_shred.rs +++ b/tests/by-util/test_shred.rs @@ -362,7 +362,7 @@ fn test_shred_non_utf8_paths() { } #[test] -fn test_gnu_shred_passes_20() { +fn test_shred_twenty_passes_with_known_random_source() { let (at, mut ucmd) = at_and_ucmd!(); let us_data = vec![0x55; 102_400]; // 100K of 'U' bytes @@ -371,8 +371,7 @@ fn test_gnu_shred_passes_20() { let file = "f"; at.write(file, "1"); // Single byte file - // Test 20 passes with deterministic random source - // This should produce the exact same sequence as GNU shred + // Run with a deterministic random source so the pass sequence is reproducible let result = ucmd .arg("-v") .arg("-u") @@ -382,7 +381,6 @@ fn test_gnu_shred_passes_20() { .arg(file) .succeeds(); - // Verify the exact pass sequence matches GNU's behavior let expected_passes = [ "pass 1/20 (random)", "pass 2/20 (ffffff)", @@ -420,7 +418,7 @@ fn test_gnu_shred_passes_20() { } #[test] -fn test_gnu_shred_passes_different_counts() { +fn test_shred_nineteen_passes_first_and_last_are_random() { let (at, mut ucmd) = at_and_ucmd!(); let us_data = vec![0x55; 102_400]; diff --git a/tests/by-util/test_tail.rs b/tests/by-util/test_tail.rs index 3c9e7ec5b23..261afc8e623 100644 --- a/tests/by-util/test_tail.rs +++ b/tests/by-util/test_tail.rs @@ -4694,24 +4694,20 @@ fn test_args_sleep_interval_when_illegal_argument_then_usage_error(#[case] sleep } #[test] -fn test_gnu_args_plus_c() { +fn test_tail_obsolete_plus_bytes() { let scene = TestScenario::new(util_name!()); - - // obs-plus-c1 scene .ucmd() .arg("+2c") - .pipe_in("abcd") + .pipe_in("wxyz") .succeeds() - .stdout_only("bcd"); - // obs-plus-c2 + .stdout_only("xyz"); scene .ucmd() .arg("+8c") - .pipe_in("abcd") + .pipe_in("wxyz") .succeeds() .stdout_only(""); - // obs-plus-x1: same as +10c scene .ucmd() .arg("+c") @@ -4721,24 +4717,20 @@ fn test_gnu_args_plus_c() { } #[test] -fn test_gnu_args_c() { +fn test_tail_obsolete_bytes() { let scene = TestScenario::new(util_name!()); - - // obs-c3 scene .ucmd() .arg("-1c") - .pipe_in("abcd") + .pipe_in("wxyz") .succeeds() - .stdout_only("d"); - // obs-c4 + .stdout_only("z"); scene .ucmd() .arg("-9c") - .pipe_in("abcd") + .pipe_in("wxyz") .succeeds() - .stdout_only("abcd"); - // obs-c5 + .stdout_only("wxyz"); scene .ucmd() .arg("-12c") @@ -4748,31 +4740,26 @@ fn test_gnu_args_c() { } #[test] -fn test_gnu_args_l() { +fn test_tail_obsolete_lines() { let scene = TestScenario::new(util_name!()); - - // obs-l1 scene .ucmd() .arg("-1l") .pipe_in("x") .succeeds() .stdout_only("x"); - // obs-l2 scene .ucmd() .arg("-1l") .pipe_in("x\ny\n") .succeeds() .stdout_only("y\n"); - // obs-l3 scene .ucmd() .arg("-1l") .pipe_in("x\ny") .succeeds() .stdout_only("y"); - // obs-l: same as -10l scene .ucmd() .arg("-l") @@ -4782,24 +4769,20 @@ fn test_gnu_args_l() { } #[test] -fn test_gnu_args_plus_l() { +fn test_tail_obsolete_plus_lines() { let scene = TestScenario::new(util_name!()); - - // obs-plus-l4 scene .ucmd() .arg("+1l") .pipe_in("x\ny\n") .succeeds() .stdout_only("x\ny\n"); - // ops-plus-l5 scene .ucmd() .arg("+2l") .pipe_in("x\ny\n") .succeeds() .stdout_only("y\n"); - // obs-plus-x2: same as +10l scene .ucmd() .arg("+l") @@ -4809,24 +4792,20 @@ fn test_gnu_args_plus_l() { } #[test] -fn test_gnu_args_number() { +fn test_tail_obsolete_number() { let scene = TestScenario::new(util_name!()); - - // obs-1 scene .ucmd() .arg("-1") .pipe_in("x") .succeeds() .stdout_only("x"); - // obs-2 scene .ucmd() .arg("-1") .pipe_in("x\ny\n") .succeeds() .stdout_only("y\n"); - // obs-3 scene .ucmd() .arg("-1") @@ -4836,17 +4815,14 @@ fn test_gnu_args_number() { } #[test] -fn test_gnu_args_plus_number() { +fn test_tail_obsolete_plus_number() { let scene = TestScenario::new(util_name!()); - - // obs-plus-4 scene .ucmd() .arg("+1") .pipe_in("x\ny\n") .succeeds() .stdout_only("x\ny\n"); - // ops-plus-5 scene .ucmd() .arg("+2") @@ -4856,10 +4832,8 @@ fn test_gnu_args_plus_number() { } #[test] -fn test_gnu_args_b() { +fn test_tail_obsolete_blocks() { let scene = TestScenario::new(util_name!()); - - // obs-b scene .ucmd() .arg("-b") @@ -4869,45 +4843,38 @@ fn test_gnu_args_b() { } #[test] -fn test_gnu_args_err() { +fn test_tail_obsolete_error_cases() { let scene = TestScenario::new(util_name!()); - - // err-1 scene .ucmd() .arg("+cl") .fails_with_code(1) .no_stdout() .stderr_is("tail: cannot open '+cl' for reading: No such file or directory\n"); - // err-2 scene .ucmd() .arg("-cl") .fails_with_code(1) .no_stdout() .stderr_is("tail: invalid number of bytes: 'l'\n"); - // err-3 scene .ucmd() .arg("+2cz") .fails_with_code(1) .no_stdout() .stderr_is("tail: cannot open '+2cz' for reading: No such file or directory\n"); - // err-4 scene .ucmd() .arg("-2cX") .fails_with_code(1) .no_stdout() .stderr_is("tail: option used in invalid context -- 2\n"); - // err-5: large numbers now clamp to u64::MAX scene .ucmd() .arg("-c99999999999999999999") .pipe_in("x") .succeeds() .stdout_is("x"); - // err-6 scene .ucmd() .arg("-c --") @@ -4936,7 +4903,7 @@ fn test_gnu_args_err() { } #[test] -fn test_gnu_args_f() { +fn test_tail_obsolete_f_flag() { let scene = TestScenario::new(util_name!()); let at = &scene.fixtures; diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index 58a9bff062b..140438a3ed4 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -371,10 +371,10 @@ struct TestCase { #[test] #[allow(clippy::too_many_lines)] -fn gnu_tests() { +fn uniq_basic_dedup_cases() { let cases = [ TestCase { - name: "1", + name: "tc_01", args: &[], input: "", stdout: Some(""), @@ -382,58 +382,58 @@ fn gnu_tests() { exit: None, }, TestCase { - name: "2", + name: "tc_02", args: &[], - input: "a\na\n", - stdout: Some("a\n"), + input: "x\nx\n", + stdout: Some("x\n"), stderr: None, exit: None, }, TestCase { - name: "3", + name: "tc_03", args: &[], - input: "a\na", - stdout: Some("a\n"), + input: "x\nx", + stdout: Some("x\n"), stderr: None, exit: None, }, TestCase { - name: "4", + name: "tc_04", args: &[], - input: "a\nb", - stdout: Some("a\nb\n"), + input: "p\nq", + stdout: Some("p\nq\n"), stderr: None, exit: None, }, TestCase { - name: "5", + name: "tc_05", args: &[], - input: "a\na\nb", - stdout: Some("a\nb\n"), + input: "x\nx\ny", + stdout: Some("x\ny\n"), stderr: None, exit: None, }, TestCase { - name: "6", + name: "tc_06", args: &[], - input: "b\na\na\n", - stdout: Some("b\na\n"), + input: "q\np\np\n", + stdout: Some("q\np\n"), stderr: None, exit: None, }, TestCase { - name: "7", + name: "tc_07", args: &[], - input: "a\nb\nc\n", - stdout: Some("a\nb\nc\n"), + input: "r\ns\nt\n", + stdout: Some("r\ns\nt\n"), stderr: None, exit: None, }, TestCase { name: "2z", args: &["-z"], - input: "a\na\n", - stdout: Some("a\na\n\0"), + input: "x\nx\n", + stdout: Some("x\nx\n\0"), stderr: None, exit: None, }, From fadcb4a7d2df03f58e4a7208497aeeae151c1550 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 18 Aug 2026 21:01:23 +0200 Subject: [PATCH 6/6] uniq: replace GNU-derived regression test --- src/uu/uniq/src/uniq.rs | 2 +- tests/by-util/test_uniq.rs | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/uu/uniq/src/uniq.rs b/src/uu/uniq/src/uniq.rs index 38f6b146945..27b9d4473b7 100644 --- a/src/uu/uniq/src/uniq.rs +++ b/src/uu/uniq/src/uniq.rs @@ -724,7 +724,7 @@ pub fn uu_app() -> Command { .num_args(0..=1) .default_missing_value("none") .require_equals(true) - // GNU accepts a repeated -D/--all-repeated and uses the last one. + // Let the final occurrence select the delimiter method. .overrides_with(options::ALL_REPEATED), ) .arg( diff --git a/tests/by-util/test_uniq.rs b/tests/by-util/test_uniq.rs index 140438a3ed4..a50534194d2 100644 --- a/tests/by-util/test_uniq.rs +++ b/tests/by-util/test_uniq.rs @@ -163,19 +163,20 @@ fn test_stdin_all_repeated() { } #[test] -fn test_all_repeated_repeated_last_wins() { - // GNU uniq accepts a repeated -D/--all-repeated and uses the last occurrence, - // instead of rejecting the second one. +fn test_repeated_all_repeated_uses_final_delimiter() { + const DUPLICATE_RUNS: &str = "copper\ncopper\nsilver\ngold\ngold\nplatinum\n"; + new_ucmd!() - .args(&["-D", "--all-repeated=separate"]) - .pipe_in("a\na\nb\nb\nc\n") + .args(&["--all-repeated=prepend", "-D"]) + .pipe_in(DUPLICATE_RUNS) .succeeds() - .stdout_is("a\na\n\nb\nb\n"); + .stdout_is("copper\ncopper\ngold\ngold\n"); + new_ucmd!() - .args(&["-D", "-D"]) - .pipe_in("a\na\n") + .args(&["-D", "--all-repeated=separate"]) + .pipe_in(DUPLICATE_RUNS) .succeeds() - .stdout_is("a\na\n"); + .stdout_is("copper\ncopper\n\ngold\ngold\n"); } #[test]