From 5cd887c61c5411619edfd85745a1a8f6f6450500 Mon Sep 17 00:00:00 2001 From: mattsu Date: Sat, 20 Dec 2025 21:07:20 +0900 Subject: [PATCH 1/7] feat(sort): support international decimal separators in numeric sorting Add locale-aware handling for decimal separators (comma vs. period) in general numeric sorting mode. This allows proper sorting of numeric fields in locales where comma is the standard decimal separator, such as many European countries. Changes include: - Enabling the "i18n-decimal" feature in uucore dependencies - Introducing locale_decimal_pt() to retrieve the locale-specific decimal separator - Updating get_leading_gen() and general_bd_parse() to accept and use the decimal point parameter - Converting input to standard period notation for parsing when locale uses comma This fixes sorting inaccuracies for international users with comma-based decimal notation. --- src/uu/sort/Cargo.toml | 2 +- src/uu/sort/src/sort.rs | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index 184f6776be7..1ec7f3733ff 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -34,7 +34,7 @@ self_cell = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } unicode-width = { workspace = true } -uucore = { workspace = true, features = ["fs", "parser-size", "version-cmp"] } +uucore = { workspace = true, features = ["fs", "parser-size", "version-cmp", "i18n-decimal"] } fluent = { workspace = true } [target.'cfg(unix)'.dependencies] diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 6122089e2f3..4f4929b6b0e 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -45,6 +45,7 @@ use uucore::error::{FromIo, strip_errno}; use uucore::error::{UError, UResult, USimpleError, UUsageError}; use uucore::extendedbigdecimal::ExtendedBigDecimal; use uucore::format_usage; +use uucore::i18n::decimal::locale_decimal_separator; use uucore::line_ending::LineEnding; use uucore::parser::num_parser::{ExtendedParser, ExtendedParserError}; use uucore::parser::parse_size::{ParseSizeError, Parser}; @@ -113,6 +114,14 @@ mod options { const DECIMAL_PT: u8 = b'.'; +fn locale_decimal_pt() -> u8 { + match locale_decimal_separator().as_bytes().first().copied() { + Some(b'.') => b'.', + Some(b',') => b',', + _ => DECIMAL_PT, + } +} + const NEGATIVE: &u8 = &b'-'; const POSITIVE: &u8 = &b'+'; @@ -633,7 +642,7 @@ impl<'a> Line<'a> { SortMode::GeneralNumeric => { let initial_selection = &self.line[selection.clone()]; - let leading = get_leading_gen(initial_selection); + let leading = get_leading_gen(initial_selection, locale_decimal_pt()); // Shorten selection to leading. selection.start += leading.start; @@ -955,7 +964,11 @@ impl FieldSelector { Selection::WithNumInfo(range_str, info) } else if self.settings.mode == SortMode::GeneralNumeric { // Parse this number as BigDecimal, as this is the requirement for general numeric sorting. - Selection::AsBigDecimal(general_bd_parse(&range_str[get_leading_gen(range_str)])) + let decimal_pt = locale_decimal_pt(); + Selection::AsBigDecimal(general_bd_parse( + &range_str[get_leading_gen(range_str, decimal_pt)], + decimal_pt, + )) } else { // This is not a numeric sort, so we don't need a NumCache. Selection::Str(range_str) @@ -2010,7 +2023,7 @@ fn ascii_case_insensitive_cmp(a: &[u8], b: &[u8]) -> Ordering { // scientific notation, so we strip those lines only after the end of the following numeric string. // For example, 5e10KFD would be 5e10 or 5x10^10 and +10000HFKJFK would become 10000. #[allow(clippy::cognitive_complexity)] -fn get_leading_gen(inp: &[u8]) -> Range { +fn get_leading_gen(inp: &[u8], decimal_pt: u8) -> Range { let trimmed = inp.trim_ascii_start(); let leading_whitespace_len = inp.len() - trimmed.len(); @@ -2048,7 +2061,7 @@ fn get_leading_gen(inp: &[u8]) -> Range { continue; } - if c == DECIMAL_PT && !had_decimal_pt && !had_e_notation { + if c == decimal_pt && !had_decimal_pt && !had_e_notation { had_decimal_pt = true; continue; } @@ -2091,9 +2104,20 @@ pub enum GeneralBigDecimalParseResult { /// Parse the beginning string into a [`GeneralBigDecimalParseResult`]. /// Using a [`GeneralBigDecimalParseResult`] instead of [`ExtendedBigDecimal`] is necessary to correctly order floats. #[inline(always)] -fn general_bd_parse(a: &[u8]) -> GeneralBigDecimalParseResult { +fn general_bd_parse(a: &[u8], decimal_pt: u8) -> GeneralBigDecimalParseResult { + let mut parsed_bytes = Vec::new(); + let input = if decimal_pt == DECIMAL_PT { + a + } else { + parsed_bytes = a + .iter() + .map(|&b| if b == decimal_pt { DECIMAL_PT } else { b }) + .collect::>(); + parsed_bytes.as_slice() + }; + // The string should be valid ASCII to be parsed. - let Ok(a) = std::str::from_utf8(a) else { + let Ok(a) = std::str::from_utf8(input) else { return GeneralBigDecimalParseResult::Invalid; }; From 20531f39c25db722d049b672f2e5df31a523e835 Mon Sep 17 00:00:00 2001 From: mattsu Date: Mon, 22 Dec 2025 22:27:05 +0900 Subject: [PATCH 2/7] refactor(sort): simplify general_bd_parse decimal point handling using Option::then Refactored the `general_bd_parse` function to replace manual mutable vector initialization and conditional assignment with `Option::then` and `as_deref`, making the code more concise and idiomatic while maintaining the same logic for normalizing decimal points. --- src/uu/sort/src/sort.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 4f4929b6b0e..eb61fd18530 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -2105,16 +2105,12 @@ pub enum GeneralBigDecimalParseResult { /// Using a [`GeneralBigDecimalParseResult`] instead of [`ExtendedBigDecimal`] is necessary to correctly order floats. #[inline(always)] fn general_bd_parse(a: &[u8], decimal_pt: u8) -> GeneralBigDecimalParseResult { - let mut parsed_bytes = Vec::new(); - let input = if decimal_pt == DECIMAL_PT { - a - } else { - parsed_bytes = a - .iter() + let parsed_bytes = (decimal_pt != DECIMAL_PT).then(|| { + a.iter() .map(|&b| if b == decimal_pt { DECIMAL_PT } else { b }) - .collect::>(); - parsed_bytes.as_slice() - }; + .collect::>() + }); + let input = parsed_bytes.as_deref().unwrap_or(a); // The string should be valid ASCII to be parsed. let Ok(a) = std::str::from_utf8(input) else { From 344ebb8e360e362baa84bbeda0ee7176f22b2cee Mon Sep 17 00:00:00 2001 From: mattsu Date: Thu, 25 Dec 2025 20:15:05 +0900 Subject: [PATCH 3/7] feat: enhance decimal point detection in general numeric sorting Add `effective_decimal_pt` function to intelligently select the decimal point based on input content, ensuring correct sorting when locale uses comma but input uses period as decimal separator. This fixes parsing issues in general numeric mode by prioritizing input-based detection over strict locale adherence. --- src/uu/sort/src/sort.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index eb61fd18530..333406fe4e4 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -122,6 +122,16 @@ fn locale_decimal_pt() -> u8 { } } +fn effective_decimal_pt(input: &[u8], locale_decimal: u8) -> u8 { + if locale_decimal == b',' { + let has_comma = input.iter().any(|&c| c == b','); + if !has_comma && input.iter().any(|&c| c == b'.') { + return b'.'; + } + } + locale_decimal +} + const NEGATIVE: &u8 = &b'-'; const POSITIVE: &u8 = &b'+'; @@ -641,8 +651,9 @@ impl<'a> Line<'a> { } SortMode::GeneralNumeric => { let initial_selection = &self.line[selection.clone()]; - - let leading = get_leading_gen(initial_selection, locale_decimal_pt()); + let locale_decimal = locale_decimal_pt(); + let decimal_pt = effective_decimal_pt(initial_selection, locale_decimal); + let leading = get_leading_gen(initial_selection, decimal_pt); // Shorten selection to leading. selection.start += leading.start; @@ -964,7 +975,8 @@ impl FieldSelector { Selection::WithNumInfo(range_str, info) } else if self.settings.mode == SortMode::GeneralNumeric { // Parse this number as BigDecimal, as this is the requirement for general numeric sorting. - let decimal_pt = locale_decimal_pt(); + let locale_decimal = locale_decimal_pt(); + let decimal_pt = effective_decimal_pt(range_str, locale_decimal); Selection::AsBigDecimal(general_bd_parse( &range_str[get_leading_gen(range_str, decimal_pt)], decimal_pt, From ee75a8497de810f0c455e4169c3e312de0849f16 Mon Sep 17 00:00:00 2001 From: mattsu Date: Thu, 25 Dec 2025 21:21:33 +0900 Subject: [PATCH 4/7] chore(deps): update fuzz dependencies to latest versions Updated various crates in fuzz/Cargo.lock: windows-sys to 0.61.2, bumpalo to 3.19.1, cc to 1.2.50, crc to 3.3.0, crc-fast to 1.9.0, icu_properties and data to 2.1.2, jiff to 0.2.17. Added fixed_decimal, icu_decimal, and icu_decimal_data for improved functionality and compatibility. --- fuzz/Cargo.lock | 100 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 2b519a989f3..833a5799dce 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -53,7 +53,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -64,7 +64,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -184,9 +184,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytecount" @@ -196,9 +196,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "cc" -version = "1.2.48" +version = "1.2.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" +checksum = "9f50d563227a1c37cc0a263f64eca3334388c01c5e4c4861a9def205c614383c" dependencies = [ "find-msvc-tools", "jobserver", @@ -325,9 +325,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.4.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -340,9 +340,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc-fast" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f7c8d397a6353ef0c1d6217ab91b3ddb5431daf57fd013f506b967dcf44458" +checksum = "2fd92aca2c6001b1bf5ba0ff84ee74ec8501b52bbef0cac80bf25a6c1d87a83d" dependencies = [ "crc", "digest", @@ -504,7 +504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -519,6 +519,17 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +[[package]] +name = "fixed_decimal" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35eabf480f94d69182677e37571d3be065822acfafd12f2f085db44fbbcc8e57" +dependencies = [ + "displaydoc", + "smallvec", + "writeable", +] + [[package]] name = "flate2" version = "1.1.5" @@ -693,6 +704,27 @@ dependencies = [ "zerovec", ] +[[package]] +name = "icu_decimal" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38c52231bc348f9b982c1868a2af3195199623007ba2c7650f432038f5b3e8e" +dependencies = [ + "fixed_decimal", + "icu_decimal_data", + "icu_locale", + "icu_locale_core", + "icu_provider", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_decimal_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2905b4044eab2dd848fe84199f9195567b63ab3a93094711501363f63546fef7" + [[package]] name = "icu_locale" version = "2.1.1" @@ -753,9 +785,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -767,9 +799,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -824,9 +856,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" +checksum = "a87d9b8105c23642f50cbbae03d1f75d8422c5cb98ce7ee9271f7ff7505be6b8" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -834,14 +866,14 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "jiff-static" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" +checksum = "b787bebb543f8969132630c51fd0afab173a86c6abae56ff3b9e5e3e3f9f6e58" dependencies = [ "proc-macro2", "quote", @@ -850,9 +882,9 @@ dependencies = [ [[package]] name = "jiff-tzdb" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524" +checksum = "68971ebff725b9e2ca27a601c5eb38a4c5d64422c4cbab0c535f248087eda5c2" [[package]] name = "jiff-tzdb-platform" @@ -1119,9 +1151,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "f59e70c4aef1e55797c2e8fd94a4f2a973fc972cfde0e0b05f683667b0cd39dd" [[package]] name = "portable-atomic-util" @@ -1273,15 +1305,15 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1366,9 +1398,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "similar" @@ -1439,15 +1471,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.23.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1748,7 +1780,9 @@ dependencies = [ "glob", "hex", "icu_collator", + "icu_decimal", "icu_locale", + "icu_provider", "itertools", "libc", "md-5", @@ -1902,7 +1936,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] From e054dcdcedc45ac86e5ce191b574c62b3a4ebe59 Mon Sep 17 00:00:00 2001 From: mattsu Date: Thu, 25 Dec 2025 21:26:05 +0900 Subject: [PATCH 5/7] refactor(sort): simplify byte checks in effective_decimal_pt using contains method Use input.contains() instead of input.iter().any() for checking presence of comma and dot bytes, improving readability and reducing boilerplate. --- src/uu/sort/src/sort.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 614fc751da0..34d41be0686 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -124,8 +124,8 @@ fn locale_decimal_pt() -> u8 { fn effective_decimal_pt(input: &[u8], locale_decimal: u8) -> u8 { if locale_decimal == b',' { - let has_comma = input.iter().any(|&c| c == b','); - if !has_comma && input.iter().any(|&c| c == b'.') { + let has_comma = input.contains(&b','); + if !has_comma && input.contains(&b'.') { return b'.'; } } From b3a6323fb4a635cbaa8ef20cc19b56619487a347 Mon Sep 17 00:00:00 2001 From: mattsu Date: Thu, 25 Dec 2025 21:28:50 +0900 Subject: [PATCH 6/7] style(sort): format uucore features list in Cargo.toml for readability Split the uucore dependency features into multiple lines to improve code formatting and maintain consistency with other multi-line dependency declarations. --- src/uu/sort/Cargo.toml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index 1ec7f3733ff..e0f31c3c18c 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -34,7 +34,12 @@ self_cell = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } unicode-width = { workspace = true } -uucore = { workspace = true, features = ["fs", "parser-size", "version-cmp", "i18n-decimal"] } +uucore = { workspace = true, features = [ + "fs", + "parser-size", + "version-cmp", + "i18n-decimal", +] } fluent = { workspace = true } [target.'cfg(unix)'.dependencies] From 12222a5dd628b529aeb9c3b5e2568c21c940e081 Mon Sep 17 00:00:00 2001 From: mattsu Date: Fri, 26 Dec 2025 08:51:02 +0900 Subject: [PATCH 7/7] test: add locale-aware decimal separator test for sort -g Add test to verify that sort's general numeric (-g) option correctly handles decimal separators based on locale settings, ensuring proper ordering of numbers like "1,9" vs "1,10" in French locale (comma as separator). --- tests/by-util/test_sort.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index 99d388da0f1..18dec73db4a 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -1559,6 +1559,32 @@ fn test_g_float() { .stdout_is(output); } +#[test] +fn test_g_float_locale_decimal_separator() { + let Ok(locale_fr_utf8) = env::var("LOCALE_FR_UTF8") else { + return; + }; + if locale_fr_utf8 == "none" { + return; + } + + let ts = TestScenario::new("sort"); + + ts.ucmd() + .env("LC_ALL", &locale_fr_utf8) + .args(&["-g", "--stable"]) + .pipe_in("1,9\n1,10\n") + .succeeds() + .stdout_is("1,10\n1,9\n"); + + ts.ucmd() + .env("LC_ALL", &locale_fr_utf8) + .args(&["-g", "--stable"]) + .pipe_in("1.9\n1.10\n") + .succeeds() + .stdout_is("1.10\n1.9\n"); +} + #[test] // Test misc numbers ("'a" is not interpreted as literal, trailing text is ignored...) fn test_g_misc() {