mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
numfmt: buffer output in non-abort invalid modes and re-enable GNU tests
Buffer formatted output so that --invalid=fail does not duplicate lines on error, and --invalid=abort streams directly for partial output. Fixes GNU numfmt.pl test: field-3. Re-enables the full numfmt.pl test suite by removing the skip list added earlier in the stack.
This commit is contained in:
@@ -596,7 +596,7 @@ fn split_bytes<'a>(input: &'a [u8], delim: &'a [u8]) -> impl Iterator<Item = &'a
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write_formatted_with_delimiter<W: std::io::Write>(
|
||||
pub fn write_formatted_with_delimiter<W: std::io::Write + ?Sized>(
|
||||
writer: &mut W,
|
||||
input: &[u8],
|
||||
options: &NumfmtOptions,
|
||||
@@ -632,7 +632,7 @@ pub fn write_formatted_with_delimiter<W: std::io::Write>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_formatted_with_whitespace<W: std::io::Write>(
|
||||
pub fn write_formatted_with_whitespace<W: std::io::Write + ?Sized>(
|
||||
writer: &mut W,
|
||||
s: &str,
|
||||
options: &NumfmtOptions,
|
||||
|
||||
@@ -20,6 +20,7 @@ use std::str::FromStr;
|
||||
use units::{IEC_BASES, SI_BASES};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::UResult;
|
||||
use uucore::util_name;
|
||||
|
||||
use uucore::i18n::decimal::locale_grouping_separator;
|
||||
use uucore::parser::shortcut_value_parser::ShortcutValueParser;
|
||||
@@ -46,15 +47,28 @@ fn format_and_write<W: std::io::Write>(
|
||||
Some(i) => &input_line[..i],
|
||||
None => input_line,
|
||||
};
|
||||
|
||||
// In non-abort modes we buffer the formatted output so that on error we
|
||||
// can emit the original line instead.
|
||||
let buffer_output = !matches!(options.invalid, InvalidModes::Abort);
|
||||
let mut formatted_line = Vec::new();
|
||||
let handled_line = if options.delimiter.is_some() {
|
||||
write_formatted_with_delimiter(&mut formatted_line, line, options, eol)
|
||||
} else {
|
||||
// Whitespace mode requires valid UTF-8
|
||||
match std::str::from_utf8(line) {
|
||||
Ok(s) => write_formatted_with_whitespace(&mut formatted_line, s, options, eol),
|
||||
Err(_) => {
|
||||
Err(translate!("numfmt-error-invalid-number", "input" => escape_line(line).quote()))
|
||||
let handled_line = {
|
||||
let output: &mut dyn std::io::Write = if buffer_output {
|
||||
&mut formatted_line
|
||||
} else {
|
||||
writer
|
||||
};
|
||||
|
||||
if options.delimiter.is_some() {
|
||||
write_formatted_with_delimiter(output, line, options, eol)
|
||||
} else {
|
||||
// Whitespace mode requires valid UTF-8
|
||||
match std::str::from_utf8(line) {
|
||||
Ok(s) => write_formatted_with_whitespace(output, s, options, eol),
|
||||
Err(_) => Err(translate!(
|
||||
"numfmt-error-invalid-number",
|
||||
"input" => escape_line(line).quote()
|
||||
)),
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -80,7 +94,9 @@ fn format_and_write<W: std::io::Write>(
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
writer.write_all(&formatted_line)?;
|
||||
if buffer_output {
|
||||
writer.write_all(&formatted_line)?;
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
|
||||
@@ -1253,6 +1253,15 @@ fn test_invalid_fail_with_fields_does_not_duplicate_output() {
|
||||
.stderr_is("numfmt: invalid number: 'Foo'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_abort_with_fields_preserves_partial_output() {
|
||||
new_ucmd!()
|
||||
.args(&["--field=3", "--from=auto", "Hello 40M World 90G"])
|
||||
.fails_with_code(2)
|
||||
.stdout_is("Hello 40M ")
|
||||
.stderr_is("numfmt: invalid number: 'World'\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rejects_malformed_number_forms() {
|
||||
new_ucmd!()
|
||||
|
||||
@@ -192,24 +192,6 @@ sed -i "s|--coreutils-prog=||g" tests/misc/coreutils.sh
|
||||
# Use the system coreutils where the test fails due to error in a util that is not the one being tested
|
||||
sed -i "s|grep '^#define HAVE_CAP 1' \$CONFIG_HEADER > /dev/null|true|" tests/ls/capability.sh
|
||||
|
||||
# Keep GNU numfmt coverage focused on the behavior we currently support.
|
||||
sed -i '/# uutils-numfmt-adjustments start/,/# uutils-numfmt-adjustments end/d' tests/numfmt/numfmt.pl
|
||||
sed -i '/push @Tests, @Locale_Tests if $locale ne '\''C'\'';/a\
|
||||
# uutils-numfmt-adjustments start\
|
||||
my %skip_uutils_numfmt_tests = map { $_ => 1 } qw(\
|
||||
unit-sep-22-fail grp-1 grp-2 delim-7 field-1\
|
||||
field-range-err-1 field-range-err-2 field-range-err-3 field-range-err-4\
|
||||
field-range-err-6 field-range-err-7 field-range-err-8 field-range-err-9\
|
||||
field-range-err-10 field-range-err-11 field-range-err-12 field-range-err-13\
|
||||
strtod-6 strtod-6.1 leading-4 debug-2\
|
||||
devdebug-1 devdebug-2 devdebug-3 devdebug-4 devdebug-5 devdebug-6\
|
||||
devdebug-7 devdebug-9 devdebug-10 devdebug-11\
|
||||
help-1 fmt-err-9 fmt-err-11 fmt-15\
|
||||
ign-err-5 ign-err-m2.2 ign-err-m3.1\
|
||||
);\
|
||||
@Tests = grep { !$skip_uutils_numfmt_tests{$_->[0]} } @Tests;\
|
||||
# uutils-numfmt-adjustments end' tests/numfmt/numfmt.pl
|
||||
|
||||
# our messages are better
|
||||
sed -i "s|cannot stat 'symlink': Permission denied|not writing through dangling symlink 'symlink'|" tests/cp/fail-perm.sh
|
||||
sed -i "s|cp: target directory 'symlink': Permission denied|cp: 'symlink' is not a directory|" tests/cp/fail-perm.sh
|
||||
|
||||
Reference in New Issue
Block a user