diff --git a/tests/by-util/test_ls.rs b/tests/by-util/test_ls.rs index a0da1400b..f47ebb5b6 100644 --- a/tests/by-util/test_ls.rs +++ b/tests/by-util/test_ls.rs @@ -2690,6 +2690,71 @@ mod quoting { &[], ); } + + #[cfg(not(any(target_vendor = "apple", target_os = "windows", target_os = "openbsd")))] + #[test] + /// This test creates files with an UTF-8 encoded name and verify that it + /// gets escaped depending on the used locale. + fn test_locale_aware_quoting() { + let cases: &[(&[u8], _, _, &[&str])] = &[ + ( + "😁".as_bytes(), // == b"\xF0\x9F\x98\x81" + "''$'\\360\\237\\230\\201'\n", // ASCII sees 4 bytes + "😁\n", // UTF-8 sees an emoji + &["--quoting-style=shell-escape"], + ), + ( + "€".as_bytes(), // == b"\xE2\x82\xAC" + "''$'\\342\\202\\254'\n", // ASCII sees 3 bytes + "€\n", // UTF-8 still only 2 + &["--quoting-style=shell-escape"], + ), + ( + b"\xC2\x80\xC2\x81", // 2 first Unicode control characters + "????\n", // ASCII sees 4 bytes + "??\n", // UTF-8 sees only 2 + &["--quoting-style=literal", "--hide-control-char"], + ), + ( + b"\xC2\xC2\x81", + "???\n", // ASCII sees 3 bytes + "??\n", // UTF-8 still only 2 + &["--quoting-style=literal", "--hide-control-char"], + ), + ( + b"\xC2\x81\xC2", + "???\n", // ASCII sees 3 bytes + "??\n", // UTF-8 still only 2 + &["--quoting-style=literal", "--hide-control-char"], + ), + ]; + + for (filename, ascii_ref, utf_8_ref, args) in cases { + let scene = TestScenario::new(util_name!()); + let at = &scene.fixtures; + + let filename = uucore::os_str_from_bytes(filename) + .expect("Filename is valid Unicode supported on Linux"); + + at.touch(filename); + + // When the locale does not handle UTF-8 encoding, escaping is done. + scene + .ucmd() + .env("LC_ALL", "C") // Non UTF-8 locale + .args(args) + .succeeds() + .stdout_only(ascii_ref); + + // When the locale has UTF-8 support, the symbol is shown as-is. + scene + .ucmd() + .env("LC_ALL", "en_US.UTF-8") // UTF-8 locale + .args(args) + .succeeds() + .stdout_only(utf_8_ref); + } + } } #[test]