sort: refine error handling and localize field parsing errors (#10068)

* sort: refactor error handling and localize field parsing errors

* style(test): fix formatting and spell-checker ignore in sort tests

- Add 'dfgi' to spell-checker ignore list for accurate linting
- Reformat tuple and method call in test_conflict_check_out for consistency and to resolve clippy warnings

* refactor(sort): use Self::default() and remove unnecessary .into() in error handling

- Changed `ModeFlags::default()` to `Self::default()` for better idiomatic Rust code.
- Removed `.into()` call in `FieldSelector::from` method as it was redundant, simplifying error construction.
This commit is contained in:
mattsu
2026-01-13 22:39:22 +01:00
committed by GitHub
parent 4ba5db0903
commit 0b0ba60d41
4 changed files with 466 additions and 264 deletions
+9
View File
@@ -32,6 +32,15 @@ sort-field-index-cannot-be-zero = field index can not be 0
sort-failed-parse-char-index = failed to parse character index {$char}: {$error}
sort-invalid-option = invalid option: '{$option}'
sort-invalid-char-index-zero-start = invalid character index 0 for the start position of a field
sort-invalid-field-spec = {$msg}: invalid field specification {$spec}
sort-invalid-count-at-start-of = invalid count at start of {$string}
sort-invalid-number-at-field-start = invalid number at field start
sort-invalid-number-after-dash = invalid number after '-'
sort-invalid-number-after-dot = invalid number after '.'
sort-invalid-number-after-comma = invalid number after ','
sort-field-number-is-zero = field number is zero
sort-character-offset-is-zero = character offset is zero
sort-stray-character-field-spec = stray character in field spec
sort-invalid-batch-size-arg = invalid --batch-size argument '{$arg}'
sort-minimum-batch-size-two = minimum --batch-size argument is '2'
sort-batch-size-too-large = --batch-size argument {$arg} too large
+9
View File
@@ -32,6 +32,15 @@ sort-field-index-cannot-be-zero = l'index de champ ne peut pas être 0
sort-failed-parse-char-index = échec d'analyse de l'index de caractère {$char} : {$error}
sort-invalid-option = option invalide : '{$option}'
sort-invalid-char-index-zero-start = index de caractère 0 invalide pour la position de début d'un champ
sort-invalid-field-spec = {$msg} : spécification de champ invalide {$spec}
sort-invalid-count-at-start-of = nombre invalide au début de {$string}
sort-invalid-number-at-field-start = nombre invalide au début du champ
sort-invalid-number-after-dash = nombre invalide après '-'
sort-invalid-number-after-dot = nombre invalide après '.'
sort-invalid-number-after-comma = nombre invalide après ','
sort-field-number-is-zero = le numéro de champ est zéro
sort-character-offset-is-zero = le décalage de caractère est zéro
sort-stray-character-field-spec = caractère parasite dans la spécification de champ
sort-invalid-batch-size-arg = argument --batch-size invalide '{$arg}'
sort-minimum-batch-size-two = l'argument --batch-size minimum est '2'
sort-batch-size-too-large = argument --batch-size {$arg} trop grand
+356 -250
View File
File diff suppressed because it is too large Load Diff
+92 -14
View File
@@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (words) ints (linux) NOFILE
// spell-checker:ignore (words) ints (linux) NOFILE dfgi
#![allow(clippy::cast_possible_wrap)]
use std::env;
@@ -620,7 +620,7 @@ fn test_keys_invalid_field() {
new_ucmd!()
.args(&["-k", "1."])
.fails()
.stderr_only("sort: failed to parse key '1.': failed to parse character index '': cannot parse integer from empty string\n");
.stderr_only("sort: invalid number after '.': invalid count at start of ''\n");
}
#[test]
@@ -628,7 +628,7 @@ fn test_keys_invalid_field_option() {
new_ucmd!()
.args(&["-k", "1.1x"])
.fails()
.stderr_only("sort: failed to parse key '1.1x': invalid option: 'x'\n");
.stderr_only("sort: stray character in field spec: invalid field specification '1.1x'\n");
}
#[test]
@@ -636,7 +636,7 @@ fn test_keys_invalid_field_zero() {
new_ucmd!()
.args(&["-k", "0.1"])
.fails()
.stderr_only("sort: failed to parse key '0.1': field index can not be 0\n");
.stderr_only("sort: field number is zero: invalid field specification '0.1'\n");
}
#[test]
@@ -644,7 +644,73 @@ fn test_keys_invalid_char_zero() {
new_ucmd!()
.args(&["-k", "1.0"])
.fails()
.stderr_only("sort: failed to parse key '1.0': invalid character index 0 for the start position of a field\n");
.stderr_only("sort: character offset is zero: invalid field specification '1.0'\n");
}
#[test]
fn test_keys_invalid_number_formats() {
new_ucmd!()
.args(&["-k", "0"])
.fails_with_code(2)
.stderr_only("sort: field number is zero: invalid field specification '0'\n");
new_ucmd!()
.args(&["-k", "2.,3"])
.fails_with_code(2)
.stderr_only("sort: invalid number after '.': invalid count at start of ',3'\n");
new_ucmd!()
.args(&["-k", "2,"])
.fails_with_code(2)
.stderr_only("sort: invalid number after ',': invalid count at start of ''\n");
new_ucmd!()
.args(&["-k", "1.1,-k0"])
.fails_with_code(2)
.stderr_only("sort: invalid number after ',': invalid count at start of '-k0'\n");
}
#[test]
fn test_incompatible_options() {
new_ucmd!()
.arg("-hn")
.fails_with_code(2)
.stderr_only("sort: options '-hn' are incompatible\n");
new_ucmd!()
.arg("-in")
.fails_with_code(2)
.stderr_only("sort: options '-in' are incompatible\n");
new_ucmd!()
.arg("-nR")
.fails_with_code(2)
.stderr_only("sort: options '-nR' are incompatible\n");
new_ucmd!()
.arg("-dfgiMnR")
.fails_with_code(2)
.stderr_only("sort: options '-dfgMnR' are incompatible\n");
new_ucmd!()
.args(&["--sort=random", "-n"])
.fails_with_code(2)
.stderr_only("sort: options '-nR' are incompatible\n");
new_ucmd!()
.args(&["-c", "-o", "out"])
.fails_with_code(2)
.stderr_only("sort: options '-co' are incompatible\n");
new_ucmd!()
.args(&["-C", "-o", "out"])
.fails_with_code(2)
.stderr_only("sort: options '-Co' are incompatible\n");
new_ucmd!()
.args(&["-c", "-C"])
.fails_with_code(2)
.stderr_only("sort: options '-cC' are incompatible\n");
}
#[test]
@@ -1154,16 +1220,22 @@ fn test_sigpipe_panic() {
#[test]
fn test_conflict_check_out() {
let check_flags = ["-c=silent", "-c=quiet", "-c=diagnose-first", "-c", "-C"];
for check_flag in &check_flags {
let cases = [
("-c=silent", "sort: options '-Co' are incompatible\n"),
("-c=quiet", "sort: options '-Co' are incompatible\n"),
(
"-c=diagnose-first",
"sort: options '-co' are incompatible\n",
),
("-c", "sort: options '-co' are incompatible\n"),
("-C", "sort: options '-Co' are incompatible\n"),
];
for (check_flag, expected) in &cases {
new_ucmd!()
.arg(check_flag)
.arg("-o=/dev/null")
.fails()
.stderr_contains(
// the rest of the message might be subject to change
"error: the argument",
);
.stderr_contains(expected);
}
}
@@ -1204,7 +1276,7 @@ fn test_verifies_files_after_keys() {
"nonexistent_dir/input_file",
])
.fails_with_code(2)
.stderr_contains("failed to parse key");
.stderr_contains("invalid field specification '0'");
}
#[test]
@@ -1735,8 +1807,14 @@ fn test_clap_localization_missing_required_argument() {
#[test]
fn test_clap_localization_invalid_value() {
let test_cases = vec![
("en_US.UTF-8", "sort: failed to parse key 'invalid'"),
("fr_FR.UTF-8", "sort: échec d'analyse de la clé 'invalid'"),
(
"en_US.UTF-8",
"sort: invalid number at field start: invalid count at start of 'invalid'",
),
(
"fr_FR.UTF-8",
"sort: nombre invalide au début du champ: nombre invalide au début de 'invalid'",
),
];
for (locale, expected_message) in test_cases {