From 6ca60cf2c782275c9a20c0e74ecc43a1449c6ab8 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 8 Jun 2025 20:52:54 +0200 Subject: [PATCH 1/3] l10n: port test for translation + add french --- src/uu/test/locales/en-US.ftl | 9 +++-- src/uu/test/locales/fr-FR.ftl | 72 +++++++++++++++++++++++++++++++++++ src/uu/test/src/test.rs | 5 ++- 3 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 src/uu/test/locales/fr-FR.ftl diff --git a/src/uu/test/locales/en-US.ftl b/src/uu/test/locales/en-US.ftl index 0f7a67394..bcb1bc486 100644 --- a/src/uu/test/locales/en-US.ftl +++ b/src/uu/test/locales/en-US.ftl @@ -63,9 +63,10 @@ test-after-help = Exit with the status determined by EXPRESSION. NOTE: Binary -a and -o are inherently ambiguous. Use test EXPR1 && test EXPR2 or test EXPR1 || test EXPR2 instead. - - NOTE: [ honors the --help and --version options, but test does not. + NOTE: {"["} honors the --help and --version options, but test does not. test treats each of those as it treats any other nonempty STRING. - - NOTE: your shell may have its own version of test and/or [, which usually supersedes the version described here. + NOTE: your shell may have its own version of test and/or {"["}, which usually supersedes the version described here. Please refer to your shell's documentation for details about the options it supports. + +# Error messages +test-error-missing-closing-bracket = missing '{"]"}' diff --git a/src/uu/test/locales/fr-FR.ftl b/src/uu/test/locales/fr-FR.ftl new file mode 100644 index 000000000..0c0ccf28e --- /dev/null +++ b/src/uu/test/locales/fr-FR.ftl @@ -0,0 +1,72 @@ +test-about = Vérifier les types de fichiers et comparer les valeurs. +test-usage = test EXPRESSION + test + {"[ EXPRESSION ]"} + {"[ ]"} + {"[ OPTION ]"} +test-after-help = Quitter avec le statut déterminé par EXPRESSION. + + Une EXPRESSION omise vaut false par défaut. + Sinon, EXPRESSION est true ou false et définit le statut de sortie. + + Il peut s'agir de : + + - ( EXPRESSION ) EXPRESSION est vraie + - ! EXPRESSION EXPRESSION est fausse + - EXPRESSION1 -a EXPRESSION2 EXPRESSION1 et EXPRESSION2 sont toutes deux vraies + - EXPRESSION1 -o EXPRESSION2 EXPRESSION1 ou EXPRESSION2 est vraie + + Opérations sur les chaînes : + - -n STRING la longueur de STRING est non nulle + - STRING équivalent à -n STRING + - -z STRING la longueur de STRING est nulle + - STRING1 = STRING2 les chaînes sont égales + - STRING1 != STRING2 les chaînes ne sont pas égales + + Comparaisons d'entiers : + - INTEGER1 -eq INTEGER2 INTEGER1 est égal à INTEGER2 + - INTEGER1 -ge INTEGER2 INTEGER1 est supérieur ou égal à INTEGER2 + - INTEGER1 -gt INTEGER2 INTEGER1 est supérieur à INTEGER2 + - INTEGER1 -le INTEGER2 INTEGER1 est inférieur ou égal à INTEGER2 + - INTEGER1 -lt INTEGER2 INTEGER1 est inférieur à INTEGER2 + - INTEGER1 -ne INTEGER2 INTEGER1 n'est pas égal à INTEGER2 + + Opérations sur les fichiers : + - FILE1 -ef FILE2 FILE1 et FILE2 ont les mêmes numéros de périphérique et d'inode + - FILE1 -nt FILE2 FILE1 est plus récent (date de modification) que FILE2 + - FILE1 -ot FILE2 FILE1 est plus ancien que FILE2 + + - -b FILE FILE existe et est un fichier spécial de type bloc + - -c FILE FILE existe et est un fichier spécial de type caractère + - -d FILE FILE existe et est un répertoire + - -e FILE FILE existe + - -f FILE FILE existe et est un fichier régulier + - -g FILE FILE existe et a le bit set-group-ID + - -G FILE FILE existe et appartient à l'ID de groupe effectif + - -h FILE FILE existe et est un lien symbolique (identique à -L) + - -k FILE FILE existe et a son bit sticky défini + - -L FILE FILE existe et est un lien symbolique (identique à -h) + - -N FILE FILE existe et a été modifié depuis sa dernière lecture + - -O FILE FILE existe et appartient à l'ID utilisateur effectif + - -p FILE FILE existe et est un tube nommé + - -r FILE FILE existe et la permission de lecture est accordée + - -s FILE FILE existe et a une taille supérieure à zéro + - -S FILE FILE existe et est un socket + - -t FD le descripteur de fichier FD est ouvert sur un terminal + - -u FILE FILE existe et son bit set-user-ID est défini + - -w FILE FILE existe et la permission d'écriture est accordée + - -x FILE FILE existe et la permission d'exécution (ou de recherche) est accordée + + À l'exception de -h et -L, tous les tests liés aux FILE déréférencent (suivent) les liens symboliques. + Attention : les parenthèses doivent être échappées (par exemple, par des barres obliques inverses) pour les shells. + INTEGER peut aussi être -l STRING, qui évalue la longueur de STRING. + + NOTE : Les -a et -o binaires sont intrinsèquement ambigus. + Utilisez test EXPR1 && test EXPR2 ou test EXPR1 || test EXPR2 à la place. + NOTE : {"["} honore les options --help et --version, mais test ne le fait pas. + test traite chacune de celles-ci comme il traite toute autre STRING non vide. + NOTE : votre shell peut avoir sa propre version de test et/ou {"["}, qui remplace généralement la version décrite ici. + Veuillez vous référer à la documentation de votre shell pour les détails sur les options qu'il prend en charge. + +# Messages d'erreur +test-error-missing-closing-bracket = '{"]"}' manquant diff --git a/src/uu/test/src/test.rs b/src/uu/test/src/test.rs index 674e70dd3..0f4263b7b 100644 --- a/src/uu/test/src/test.rs +++ b/src/uu/test/src/test.rs @@ -55,7 +55,10 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> { // If invoked via name '[', matching ']' must be in the last arg let last = args.pop(); if last.as_deref() != Some(OsStr::new("]")) { - return Err(USimpleError::new(2, "missing ']'")); + return Err(USimpleError::new( + 2, + get_message("test-error-missing-closing-bracket"), + )); } } From 09bb35e11ea404fb3b7235854f683c70cc0aa622 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 9 Jun 2025 09:39:49 +0200 Subject: [PATCH 2/3] test: move to thiserror --- Cargo.lock | 1 + fuzz/Cargo.lock | 1 + src/uu/test/Cargo.toml | 1 + src/uu/test/src/error.rs | 30 +++++++++++------------------- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ee0e3c28..0c66b92bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3578,6 +3578,7 @@ version = "0.1.0" dependencies = [ "clap", "libc", + "thiserror 2.0.12", "uucore", ] diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 6190e8ba6..6328b3f6e 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -1379,6 +1379,7 @@ version = "0.1.0" dependencies = [ "clap", "libc", + "thiserror", "uucore", ] diff --git a/src/uu/test/Cargo.toml b/src/uu/test/Cargo.toml index c59f9fcb4..53cf597af 100644 --- a/src/uu/test/Cargo.toml +++ b/src/uu/test/Cargo.toml @@ -21,6 +21,7 @@ path = "src/test.rs" clap = { workspace = true } libc = { workspace = true } uucore = { workspace = true, features = ["process"] } +thiserror = { workspace = true } [[bin]] name = "test" diff --git a/src/uu/test/src/error.rs b/src/uu/test/src/error.rs index e392216e1..235786bc6 100644 --- a/src/uu/test/src/error.rs +++ b/src/uu/test/src/error.rs @@ -2,42 +2,34 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. + +use thiserror::Error; + /// Represents an error encountered while parsing a test expression -#[derive(Debug)] +#[derive(Error, Debug)] pub enum ParseError { + #[error("expected value")] ExpectedValue, + #[error("expected {0}")] Expected(String), + #[error("extra argument {0}")] ExtraArgument(String), + #[error("missing argument after {0}")] MissingArgument(String), + #[error("unknown operator {0}")] UnknownOperator(String), + #[error("invalid integer {0}")] InvalidInteger(String), + #[error("{0}: unary operator expected")] UnaryOperatorExpected(String), } /// A Result type for parsing test expressions pub type ParseResult = Result; -/// Implement Display trait for ParseError to make it easier to print useful errors. -impl std::fmt::Display for ParseError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Expected(s) => write!(f, "expected {s}"), - Self::ExpectedValue => write!(f, "expected value"), - Self::MissingArgument(s) => write!(f, "missing argument after {s}"), - Self::ExtraArgument(s) => write!(f, "extra argument {s}"), - Self::UnknownOperator(s) => write!(f, "unknown operator {s}"), - Self::InvalidInteger(s) => write!(f, "invalid integer {s}"), - Self::UnaryOperatorExpected(op) => write!(f, "{op}: unary operator expected"), - } - } -} - /// Implement UError trait for ParseError to make it easier to return useful error codes from main(). impl uucore::error::UError for ParseError { fn code(&self) -> i32 { 2 } } - -/// Implement standard Error trait for UError -impl std::error::Error for ParseError {} From 90e91dd43dab67a340ae3d50dabeab5b19ed2e32 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 9 Jun 2025 09:48:26 +0200 Subject: [PATCH 3/3] test: also translate errors.rs --- src/uu/test/locales/en-US.ftl | 7 +++++++ src/uu/test/locales/fr-FR.ftl | 7 +++++++ src/uu/test/src/error.rs | 16 +++++++++------- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/uu/test/locales/en-US.ftl b/src/uu/test/locales/en-US.ftl index bcb1bc486..86871637f 100644 --- a/src/uu/test/locales/en-US.ftl +++ b/src/uu/test/locales/en-US.ftl @@ -70,3 +70,10 @@ test-after-help = Exit with the status determined by EXPRESSION. # Error messages test-error-missing-closing-bracket = missing '{"]"}' +test-error-expected = expected { $value } +test-error-expected-value = expected value +test-error-missing-argument = missing argument after { $argument } +test-error-extra-argument = extra argument { $argument } +test-error-unknown-operator = unknown operator { $operator } +test-error-invalid-integer = invalid integer { $value } +test-error-unary-operator-expected = { $operator }: unary operator expected diff --git a/src/uu/test/locales/fr-FR.ftl b/src/uu/test/locales/fr-FR.ftl index 0c0ccf28e..78cae9b44 100644 --- a/src/uu/test/locales/fr-FR.ftl +++ b/src/uu/test/locales/fr-FR.ftl @@ -70,3 +70,10 @@ test-after-help = Quitter avec le statut déterminé par EXPRESSION. # Messages d'erreur test-error-missing-closing-bracket = '{"]"}' manquant +test-error-expected = { $value } attendu +test-error-expected-value = valeur attendue +test-error-missing-argument = argument manquant après { $argument } +test-error-extra-argument = argument supplémentaire { $argument } +test-error-unknown-operator = opérateur inconnu { $operator } +test-error-invalid-integer = entier invalide { $value } +test-error-unary-operator-expected = { $operator } : opérateur unaire attendu diff --git a/src/uu/test/src/error.rs b/src/uu/test/src/error.rs index 235786bc6..fd66641a9 100644 --- a/src/uu/test/src/error.rs +++ b/src/uu/test/src/error.rs @@ -3,24 +3,26 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +use std::collections::HashMap; use thiserror::Error; +use uucore::locale::{get_message, get_message_with_args}; /// Represents an error encountered while parsing a test expression #[derive(Error, Debug)] pub enum ParseError { - #[error("expected value")] + #[error("{}", get_message("test-error-expected-value"))] ExpectedValue, - #[error("expected {0}")] + #[error("{}", get_message_with_args("test-error-expected", HashMap::from([("value".to_string(), .0.to_string())])))] Expected(String), - #[error("extra argument {0}")] + #[error("{}", get_message_with_args("test-error-extra-argument", HashMap::from([("argument".to_string(), .0.to_string())])))] ExtraArgument(String), - #[error("missing argument after {0}")] + #[error("{}", get_message_with_args("test-error-missing-argument", HashMap::from([("argument".to_string(), .0.to_string())])))] MissingArgument(String), - #[error("unknown operator {0}")] + #[error("{}", get_message_with_args("test-error-unknown-operator", HashMap::from([("operator".to_string(), .0.to_string())])))] UnknownOperator(String), - #[error("invalid integer {0}")] + #[error("{}", get_message_with_args("test-error-invalid-integer", HashMap::from([("value".to_string(), .0.to_string())])))] InvalidInteger(String), - #[error("{0}: unary operator expected")] + #[error("{}", get_message_with_args("test-error-unary-operator-expected", HashMap::from([("operator".to_string(), .0.to_string())])))] UnaryOperatorExpected(String), }