// This file is part of the uutils coreutils package. // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore fffffffffffffffc use uutests::new_ucmd; #[test] fn basic_literal() { new_ucmd!() .args(&["hello world"]) .succeeds() .stdout_only("hello world"); } #[test] fn test_missing_escaped_hex_value() { new_ucmd!() .arg(r"\x") .fails_with_code(1) .stderr_only("printf: missing hexadecimal number in escape\n"); } #[test] fn escaped_octal_and_newline() { new_ucmd!() .args(&["\\101\\0377\\n"]) .succeeds() .stdout_only("A\x1F7\n"); } #[test] fn variable_sized_octal() { for x in ["|\\5|", "|\\05|", "|\\005|"] { new_ucmd!() .arg(x) .succeeds() .stdout_only_bytes([b'|', 5u8, b'|']); } new_ucmd!() .arg("|\\0005|") .succeeds() .stdout_only_bytes([b'|', 0, b'5', b'|']); } #[test] fn escaped_unicode_four_digit() { new_ucmd!().args(&["\\u0125"]).succeeds().stdout_only("ĥ"); } #[test] fn escaped_unicode_eight_digit() { new_ucmd!() .args(&["\\U00000125"]) .succeeds() .stdout_only("ĥ"); } #[test] fn escaped_unicode_null_byte() { new_ucmd!() .args(&["\\0001_"]) .succeeds() .stdout_is_bytes([0u8, b'1', b'_']); new_ucmd!() .args(&["%b", "\\0001_"]) .succeeds() .stdout_is_bytes([1u8, b'_']); } #[test] fn escaped_unicode_incomplete() { for arg in ["\\u", "\\U", "\\uabc", "\\Uabcd"] { new_ucmd!() .arg(arg) .fails_with_code(1) .stderr_only("printf: missing hexadecimal number in escape\n"); } } #[test] fn escaped_unicode_invalid() { for arg in ["\\ud9d0", "\\U0000D8F9"] { new_ucmd!().arg(arg).fails_with_code(1).stderr_only(format!( "printf: invalid universal character name {}\n", arg )); } } #[test] fn escaped_percent_sign() { new_ucmd!() .args(&["hello%% world"]) .succeeds() .stdout_only("hello% world"); } #[test] fn escaped_unrecognized() { new_ucmd!().args(&["c\\d"]).succeeds().stdout_only("c\\d"); } #[test] fn sub_b_string_handle_escapes() { new_ucmd!() .args(&["hello %b", "\\tworld"]) .succeeds() .stdout_only("hello \tworld"); } #[test] fn sub_b_string_variable_size_unicode() { for x in ["\\5|", "\\05|", "\\005|", "\\0005|"] { new_ucmd!() .args(&["|%b", x]) .succeeds() .stdout_only_bytes([b'|', 5u8, b'|']); } new_ucmd!() .args(&["|%b", "\\00005|"]) .succeeds() .stdout_only_bytes([b'|', 0, b'5', b'|']); } #[test] fn sub_b_string_validate_field_params() { new_ucmd!() .args(&["hello %7b", "world"]) .fails() .stdout_is("hello ") .stderr_is("printf: %7b: invalid conversion specification\n"); } #[test] fn sub_b_string_ignore_subs() { new_ucmd!() .args(&["hello %b", "world %% %i"]) .succeeds() .stdout_only("hello world %% %i"); } #[test] fn sub_q_string_non_printable() { new_ucmd!() .args(&["non-printable: %q", "\"$test\""]) .succeeds() .stdout_only("non-printable: '\"$test\"'"); } #[test] fn sub_q_string_validate_field_params() { new_ucmd!() .args(&["hello %7q", "world"]) .fails() .stdout_is("hello ") .stderr_is("printf: %7q: invalid conversion specification\n"); } #[test] fn sub_q_string_special_non_printable() { new_ucmd!() .args(&["non-printable: %q", "test~"]) .succeeds() .stdout_only("non-printable: test~"); } #[test] fn sub_q_string_empty() { new_ucmd!().args(&["%q", ""]).succeeds().stdout_only("''"); } #[test] fn sub_char() { new_ucmd!() .args(&["the letter %c", "A"]) .succeeds() .stdout_only("the letter A"); } #[test] fn sub_char_from_string() { new_ucmd!() .args(&["%c%c%c", "five", "%", "oval"]) .succeeds() .stdout_only("f%o"); } #[test] fn sub_num_int() { new_ucmd!() .args(&["twenty is %i", "20"]) .succeeds() .stdout_only("twenty is 20"); } #[test] fn sub_num_int_min_width() { new_ucmd!() .args(&["twenty is %1i", "20"]) .succeeds() .stdout_only("twenty is 20"); } #[test] fn sub_num_int_neg() { new_ucmd!() .args(&["neg. twenty is %i", "-20"]) .succeeds() .stdout_only("neg. twenty is -20"); } #[test] fn sub_num_int_oct_in() { new_ucmd!() .args(&["twenty is %i", "024"]) .succeeds() .stdout_only("twenty is 20"); } #[test] fn sub_num_int_oct_in_neg() { new_ucmd!() .args(&["neg. twenty is %i", "-024"]) .succeeds() .stdout_only("neg. twenty is -20"); } #[test] fn sub_num_int_hex_in() { new_ucmd!() .args(&["twenty is %i", "0x14"]) .succeeds() .stdout_only("twenty is 20"); } #[test] fn sub_num_int_hex_in_neg() { new_ucmd!() .args(&["neg. twenty is %i", "-0x14"]) .succeeds() .stdout_only("neg. twenty is -20"); } #[test] fn sub_num_int_char_const_in() { new_ucmd!() .args(&["ninety seven is %i", "'a"]) .succeeds() .stdout_only("ninety seven is 97"); new_ucmd!() .args(&["emoji is %i", "'🙃"]) .succeeds() .stdout_only("emoji is 128579"); new_ucmd!() .args(&["ninety seven is %i", "\"a"]) .succeeds() .stdout_only("ninety seven is 97"); new_ucmd!() .args(&["emoji is %i", "\"🙃"]) .succeeds() .stdout_only("emoji is 128579"); } #[test] fn sub_num_thousands() { // For "C" locale, the thousands separator is ignored but should // not result in an error new_ucmd!() .args(&["%'i", "123456"]) .succeeds() .stdout_only("123456"); } #[test] fn sub_num_uint() { new_ucmd!() .args(&["twenty is %u", "20"]) .succeeds() .stdout_only("twenty is 20"); } #[test] fn sub_num_octal() { new_ucmd!() .args(&["twenty in octal is %o", "20"]) .succeeds() .stdout_only("twenty in octal is 24"); } #[test] fn sub_num_hex_lower() { new_ucmd!() .args(&["thirty in hex is %x", "30"]) .succeeds() .stdout_only("thirty in hex is 1e"); } #[test] fn sub_num_hex_upper() { new_ucmd!() .args(&["thirty in hex is %X", "30"]) .succeeds() .stdout_only("thirty in hex is 1E"); } #[test] fn sub_num_hex_non_numerical() { new_ucmd!() .args(&["parameters need to be numbers %X", "%194"]) .fails_with_code(1); } #[test] fn sub_num_float() { new_ucmd!() .args(&["twenty is %f", "20"]) .succeeds() .stdout_only("twenty is 20.000000"); } #[test] fn sub_num_float_e_round() { new_ucmd!() .args(&["%e", "99999999"]) .succeeds() .stdout_only("1.000000e+08"); } #[test] fn sub_num_float_e_no_round() { new_ucmd!() .args(&["%e", "99999994"]) .succeeds() .stdout_only("9.999999e+07"); } #[test] fn sub_num_float_round_to_one() { new_ucmd!() .args(&["one is %f", "0.9999995"]) .succeeds() .stdout_only("one is 1.000000"); } #[test] #[ignore = "Requires 'long double' precision floats to be used internally"] fn sub_num_float_round_to_two() { new_ucmd!() .args(&["two is %f", "1.9999995"]) .succeeds() .stdout_only("two is 2.000000"); } #[test] fn sub_num_float_round_nines_dec() { new_ucmd!() .args(&["%f", "0.99999999"]) .succeeds() .stdout_only("1.000000"); } #[test] fn sub_num_sci_lower() { new_ucmd!() .args(&["twenty is %e", "20"]) .succeeds() .stdout_only("twenty is 2.000000e+01"); } #[test] fn sub_num_sci_upper() { new_ucmd!() .args(&["twenty is %E", "20"]) .succeeds() .stdout_only("twenty is 2.000000E+01"); } #[test] fn sub_num_sci_trunc() { new_ucmd!() .args(&["pi is ~ %e", "3.1415926535"]) .succeeds() .stdout_only("pi is ~ 3.141593e+00"); } #[test] fn sub_num_dec_trunc() { new_ucmd!() .args(&["pi is ~ %g", "3.1415926535"]) .succeeds() .stdout_only("pi is ~ 3.14159"); } #[test] fn sub_num_sci_negative() { new_ucmd!() .args(&["-1234 is %e", "-1234"]) .succeeds() .stdout_only("-1234 is -1.234000e+03"); } #[test] fn sub_num_hex_float_lower() { new_ucmd!() .args(&["%a", ".875"]) .succeeds() .stdout_only("0xep-4"); } #[test] fn sub_num_hex_float_upper() { new_ucmd!() .args(&["%A", ".875"]) .succeeds() .stdout_only("0XEP-4"); } #[test] fn sub_min_width() { new_ucmd!() .args(&["hello %7s", "world"]) .succeeds() .stdout_only("hello world"); } #[test] fn sub_min_width_negative() { new_ucmd!() .args(&["hello %-7s", "world"]) .succeeds() .stdout_only("hello world "); } #[test] fn sub_str_max_chars_input() { new_ucmd!() .args(&["hello %7.2s", "world"]) .succeeds() .stdout_only("hello wo"); } #[test] fn sub_int_decimal() { new_ucmd!() .args(&["%0.i", "11"]) .succeeds() .stdout_only("11"); } #[test] fn sub_int_leading_zeroes() { new_ucmd!() .args(&["%.4i", "11"]) .succeeds() .stdout_only("0011"); } #[test] fn sub_int_leading_zeroes_padded() { new_ucmd!() .args(&["%5.4i", "11"]) .succeeds() .stdout_only(" 0011"); } #[test] fn sub_float_dec_places() { new_ucmd!() .args(&["pi is ~ %.11f", "3.1415926535"]) .succeeds() .stdout_only("pi is ~ 3.14159265350"); } #[test] fn sub_float_hex_in() { new_ucmd!() .args(&["%f", "0xF1.1F"]) .succeeds() .stdout_only("241.121094"); } #[test] fn sub_float_no_octal_in() { new_ucmd!() .args(&["%f", "077"]) .succeeds() .stdout_only("77.000000"); } #[test] fn sub_any_asterisk_first_param() { new_ucmd!() .args(&["%*i", "3", "11", "4", "12"]) .succeeds() .stdout_only(" 11 12"); } #[test] fn sub_any_asterisk_second_param() { new_ucmd!() .args(&["%.*i", "3", "11", "4", "12"]) .succeeds() .stdout_only("0110012"); } #[test] fn sub_any_asterisk_both_params() { new_ucmd!() .args(&["%*.*i", "4", "3", "11", "5", "4", "12"]) .succeeds() .stdout_only(" 011 0012"); } #[test] fn sub_any_asterisk_octal_arg() { new_ucmd!() .args(&["%.*i", "011", "12345678"]) .succeeds() .stdout_only("012345678"); } #[test] fn sub_any_asterisk_hex_arg() { new_ucmd!() .args(&["%.*i", "0xA", "123456789"]) .succeeds() .stdout_only("0123456789"); } #[test] fn sub_any_asterisk_negative_first_param() { new_ucmd!() .args(&["a(%*s)b", "-5", "xyz"]) .succeeds() .stdout_only("a(xyz )b"); // Would be 'a( xyz)b' if -5 was 5 // Negative octal new_ucmd!() .args(&["a(%*s)b", "-010", "xyz"]) .succeeds() .stdout_only("a(xyz )b"); // Negative hexadecimal new_ucmd!() .args(&["a(%*s)b", "-0x10", "xyz"]) .succeeds() .stdout_only("a(xyz )b"); // Should also work on %c new_ucmd!() .args(&["a(%*c)b", "-5", "x"]) .succeeds() .stdout_only("a(x )b"); // Would be 'a( x)b' if -5 was 5 } #[test] fn sub_any_asterisk_first_param_with_integer() { new_ucmd!() .args(&["|%*d|", "3", "0"]) .succeeds() .stdout_only("| 0|"); new_ucmd!() .args(&["|%*d|", "1", "0"]) .succeeds() .stdout_only("|0|"); new_ucmd!() .args(&["|%*d|", "0", "0"]) .succeeds() .stdout_only("|0|"); new_ucmd!() .args(&["|%*d|", "-1", "0"]) .succeeds() .stdout_only("|0|"); // Negative widths are left-aligned new_ucmd!() .args(&["|%*d|", "-3", "0"]) .succeeds() .stdout_only("|0 |"); } #[test] fn sub_any_asterisk_second_param_with_integer() { new_ucmd!() .args(&["|%.*d|", "3", "10"]) .succeeds() .stdout_only("|010|"); new_ucmd!() .args(&["|%*.d|", "1", "10"]) .succeeds() .stdout_only("|10|"); new_ucmd!() .args(&["|%.*d|", "0", "10"]) .succeeds() .stdout_only("|10|"); new_ucmd!() .args(&["|%.*d|", "-1", "10"]) .succeeds() .stdout_only("|10|"); new_ucmd!() .args(&["|%.*d|", "-2", "10"]) .succeeds() .stdout_only("|10|"); new_ucmd!() .args(&["|%.*d|", &i64::MIN.to_string(), "10"]) .succeeds() .stdout_only("|10|"); new_ucmd!() .args(&["|%.*d|", &format!("-{}", u128::MAX), "10"]) .fails_with_code(1) .stdout_is("|10|") .stderr_is( "printf: '-340282366920938463463374607431768211455': Numerical result out of range\n", ); } #[test] fn sub_any_specifiers() { // spell-checker:disable-next-line for format in ["%ztlhLji", "%0ztlhLji", "%0.ztlhLji"] { new_ucmd!().args(&[format, "3"]).succeeds().stdout_only("3"); } } #[test] fn unspecified_left_justify_is_1_width() { new_ucmd!().args(&["%-o"]).succeeds().stdout_only("0"); } #[test] fn sub_any_specifiers_after_second_param() { new_ucmd!() .args(&["%0.0ztlhLji", "3"]) //spell-checker:disable-line .succeeds() .stdout_only("3"); } #[test] fn stop_after_additional_escape() { new_ucmd!() .args(&["A%sC\\cD%sF", "B", "E"]) .succeeds() .stdout_only("ABC"); } #[test] fn sub_float_leading_zeroes() { new_ucmd!() .args(&["%010f", "1"]) .succeeds() .stdout_only("001.000000"); } #[test] fn sub_general_float() { new_ucmd!() .args(&["%g", "1.1"]) .succeeds() .stdout_only("1.1"); } #[test] fn sub_general_truncate_to_integer() { new_ucmd!().args(&["%g", "1.0"]).succeeds().stdout_only("1"); } #[test] fn sub_general_scientific_notation() { new_ucmd!() .args(&["%g", "1000010"]) .succeeds() .stdout_only("1.00001e+06"); } #[test] fn sub_general_round_scientific_notation() { new_ucmd!() .args(&["%g", "123456789"]) .succeeds() .stdout_only("1.23457e+08"); } #[test] fn sub_general_round_float() { new_ucmd!() .args(&["%g", "12345.6789"]) .succeeds() .stdout_only("12345.7"); } #[test] fn sub_general_round_float_to_integer() { new_ucmd!() .args(&["%g", "123456.7"]) .succeeds() .stdout_only("123457"); } #[test] fn sub_general_round_float_leading_zeroes() { new_ucmd!() .args(&["%g", "1.000009"]) .succeeds() .stdout_only("1.00001"); } #[test] fn partial_float() { new_ucmd!() .args(&["%.2f is %s", "42.03x", "a lot"]) .fails_with_code(1) .stdout_is("42.03 is a lot") .stderr_is("printf: '42.03x': value not completely converted\n"); } #[test] fn partial_integer() { new_ucmd!() .args(&["%d is %s", "42x23", "a lot"]) .fails_with_code(1) .stdout_is("42 is a lot") .stderr_is("printf: '42x23': value not completely converted\n"); new_ucmd!() .args(&["%d is not %s", "0xwa", "a lot"]) .fails_with_code(1) .stdout_is("0 is not a lot") .stderr_is("printf: '0xwa': value not completely converted\n"); } #[test] fn unsigned_hex_negative_wraparound() { new_ucmd!() .args(&["%x", "-0b100"]) .succeeds() .stdout_only("fffffffffffffffc"); new_ucmd!() .args(&["%x", "-0100"]) .succeeds() .stdout_only("ffffffffffffffc0"); new_ucmd!() .args(&["%x", "-100"]) .succeeds() .stdout_only("ffffffffffffff9c"); new_ucmd!() .args(&["%x", "-0x100"]) .succeeds() .stdout_only("ffffffffffffff00"); new_ucmd!() .args(&["%x", "-92233720368547758150"]) .fails_with_code(1) .stdout_is("ffffffffffffffff") .stderr_is("printf: '-92233720368547758150': Numerical result out of range\n"); new_ucmd!() .args(&["%u", "-1002233720368547758150"]) .fails_with_code(1) .stdout_is("18446744073709551615") .stderr_is("printf: '-1002233720368547758150': Numerical result out of range\n"); } #[test] fn test_overflow() { new_ucmd!() .args(&["%d", "36893488147419103232"]) .fails_with_code(1) .stdout_is("9223372036854775807") .stderr_is("printf: '36893488147419103232': Numerical result out of range\n"); new_ucmd!() .args(&["%d", "-36893488147419103232"]) .fails_with_code(1) .stdout_is("-9223372036854775808") .stderr_is("printf: '-36893488147419103232': Numerical result out of range\n"); new_ucmd!() .args(&["%u", "36893488147419103232"]) .fails_with_code(1) .stdout_is("18446744073709551615") .stderr_is("printf: '36893488147419103232': Numerical result out of range\n"); } #[test] fn partial_char() { new_ucmd!() .args(&["%d", "'abc"]) .fails_with_code(1) .stdout_is("97") .stderr_is( "printf: warning: bc: character(s) following character constant have been ignored\n", ); } #[test] fn sub_alternative_lower_hex_0() { new_ucmd!().args(&["%#x", "0"]).succeeds().stdout_only("0"); } #[test] fn sub_alternative_lower_hex() { new_ucmd!() .args(&["%#x", "42"]) .succeeds() .stdout_only("0x2a"); } #[test] fn sub_alternative_upper_hex_0() { new_ucmd!().args(&["%#X", "0"]).succeeds().stdout_only("0"); } #[test] fn sub_alternative_upper_hex() { new_ucmd!() .args(&["%#X", "42"]) .succeeds() .stdout_only("0X2A"); } #[test] fn char_as_byte() { new_ucmd!() .args(&["%c", "🙃"]) .succeeds() .no_stderr() .stdout_is_bytes(b"\xf0"); } #[test] fn no_infinite_loop() { new_ucmd!() .args(&["a", "b"]) .succeeds() .stdout_is("a") .stderr_contains("warning: ignoring excess arguments, starting with 'b'"); } #[test] fn pad_octal_with_prefix() { new_ucmd!() .args(&[">%#15.6o<", "0"]) .succeeds() .stdout_only("> 000000<"); new_ucmd!() .args(&[">%#15.6o<", "01"]) .succeeds() .stdout_only("> 000001<"); new_ucmd!() .args(&[">%#15.6o<", "01234"]) .succeeds() .stdout_only("> 001234<"); new_ucmd!() .args(&[">%#15.6o<", "012345"]) .succeeds() .stdout_only("> 012345<"); new_ucmd!() .args(&[">%#15.6o<", "0123456"]) .succeeds() .stdout_only("> 0123456<"); } #[test] fn pad_unsigned_zeroes() { for format in ["%.3u", "%.3x", "%.3X", "%.3o"] { new_ucmd!() .args(&[format, "0"]) .succeeds() .stdout_only("000"); } } #[test] fn pad_unsigned_three() { for (format, expected) in [ ("%.3u", "003"), ("%.3x", "003"), ("%.3X", "003"), ("%.3o", "003"), ("%#.3x", "0x003"), ("%#.3X", "0X003"), ("%#.3o", "003"), ("%#05x", "0x003"), ("%#05X", "0X003"), ("%3x", " 3"), ("%3X", " 3"), ] { new_ucmd!() .args(&[format, "3"]) .succeeds() .stdout_only(expected); } } #[test] fn pad_char() { for (format, expected) in [("%3c", " X"), ("%1c", "X"), ("%-1c", "X"), ("%-3c", "X ")] { new_ucmd!() .args(&[format, "X"]) .succeeds() .stdout_only(expected); } } #[test] fn pad_string() { for (format, expected) in [ ("%8s", " bottle"), ("%-8s", "bottle "), ("%6s", "bottle"), ("%-6s", "bottle"), ] { new_ucmd!() .args(&[format, "bottle"]) .succeeds() .stdout_only(expected); } } #[test] fn format_spec_zero_fails() { // It is invalid to have the format spec for format in ["%0c", "%0s"] { new_ucmd!().args(&[format, "3"]).fails_with_code(1); } } #[test] fn invalid_precision_tests() { // It is invalid to have length of output string greater than i32::MAX for format in ["%.*d", "%.*f"] { let expected_error = "printf: invalid precision: '2147483648'\n"; new_ucmd!() .args(&[format, "2147483648", "0"]) .fails() .stderr_is(expected_error); } } // The following padding-tests test for the cases in which flags in ['0', ' '] are given. // For integer, only try to pad when no precision is given, while // for float, always try to pad #[test] fn space_padding_with_space_test() { // Check if printf gives an extra space in the beginning new_ucmd!() .args(&["% 3d", "1"]) .succeeds() .stdout_only(" 1"); } #[test] fn zero_padding_with_space_test() { new_ucmd!() .args(&["% 03d", "1"]) .succeeds() .stdout_only(" 01"); } #[test] fn zero_padding_with_plus_test() { new_ucmd!() .args(&["%+04d", "1"]) .succeeds() .stdout_only("+001"); } #[test] fn negative_zero_padding_test() { new_ucmd!() .args(&["%03d", "-1"]) .succeeds() .stdout_only("-01"); } #[test] fn negative_zero_padding_with_space_test() { new_ucmd!() .args(&["% 03d", "-1"]) .succeeds() .stdout_only("-01"); } #[test] fn spaces_before_numbers_are_ignored() { new_ucmd!() .args(&["%*.*d", " 5", " 3", " 6"]) .succeeds() .stdout_only(" 006"); } #[test] fn float_with_zero_precision_should_pad() { new_ucmd!() .args(&["%03.0f", "-1"]) .succeeds() .stdout_only("-01"); } #[test] fn float_non_finite() { new_ucmd!() .args(&[ "%f %f %F %f %f %F", "nan", "-nan", "nan", "inf", "-inf", "inf", ]) .succeeds() .stdout_only("nan -nan NAN inf -inf INF"); } #[test] fn float_zero_neg_zero() { new_ucmd!() .args(&["%f %f", "0.0", "-0.0"]) .succeeds() .stdout_only("0.000000 -0.000000"); } #[test] fn precision_check() { new_ucmd!() .args(&["%.3d", "1"]) .succeeds() .stdout_only("001"); } #[test] fn space_padding_with_precision() { new_ucmd!() .args(&["%4.3d", "1"]) .succeeds() .stdout_only(" 001"); } #[test] fn float_zero_padding_with_precision() { new_ucmd!() .args(&["%04.1f", "1"]) .succeeds() .stdout_only("01.0"); } #[test] fn float_space_padding_with_precision() { new_ucmd!() .args(&["%4.1f", "1"]) .succeeds() .stdout_only(" 1.0"); } #[test] fn negative_float_zero_padding_with_precision() { new_ucmd!() .args(&["%05.1f", "-1"]) .succeeds() .stdout_only("-01.0"); } #[test] fn float_default_precision_space_padding() { new_ucmd!() .args(&["%10f", "1"]) .succeeds() .stdout_only(" 1.000000"); } #[test] fn float_default_precision_zero_padding() { new_ucmd!() .args(&["%010f", "1"]) .succeeds() .stdout_only("001.000000"); } #[test] fn flag_position_space_padding() { new_ucmd!() .args(&["% +3.1d", "1"]) .succeeds() .stdout_only(" +1"); } #[test] fn float_flag_position_space_padding() { new_ucmd!() .args(&["% +5.1f", "1"]) .succeeds() .stdout_only(" +1.0"); } #[test] fn float_large_precision() { // Note: This does not match GNU coreutils output (0.100000000000000000001355252716 on x86), // as we parse and format using ExtendedBigDecimal, which provides arbitrary precision. new_ucmd!() .args(&["%.30f", "0.1"]) .succeeds() .stdout_only("0.100000000000000000000000000000"); } #[test] fn float_non_finite_space_padding() { new_ucmd!() .args(&["% 5.2f|% 5.2f|% 5.2f|% 5.2f", "inf", "-inf", "nan", "-nan"]) .succeeds() .stdout_only(" inf| -inf| nan| -nan"); } #[test] fn float_non_finite_zero_padding() { // Zero-padding pads non-finite numbers with spaces. new_ucmd!() .args(&["%05.2f|%05.2f|%05.2f|%05.2f", "inf", "-inf", "nan", "-nan"]) .succeeds() .stdout_only(" inf| -inf| nan| -nan"); } #[test] fn float_abs_value_less_than_one() { new_ucmd!() .args(&["%g", "0.1171875"]) .succeeds() .stdout_only("0.117188"); // The original value from #7031 issue new_ucmd!() .args(&["%g", "-0.1171875"]) .succeeds() .stdout_only("-0.117188"); new_ucmd!() .args(&["%g", "0.01171875"]) .succeeds() .stdout_only("0.0117188"); new_ucmd!() .args(&["%g", "-0.01171875"]) .succeeds() .stdout_only("-0.0117188"); new_ucmd!() .args(&["%g", "0.001171875001"]) .succeeds() .stdout_only("0.00117188"); new_ucmd!() .args(&["%g", "-0.001171875001"]) .succeeds() .stdout_only("-0.00117188"); } #[test] fn float_switch_switch_decimal_scientific() { new_ucmd!() .args(&["%g", "0.0001"]) .succeeds() .stdout_only("0.0001"); new_ucmd!() .args(&["%g", "0.00001"]) .succeeds() .stdout_only("1e-05"); } #[test] fn float_arg_zero() { new_ucmd!() .args(&["%f", "0."]) .succeeds() .stdout_only("0.000000"); new_ucmd!() .args(&["%f", ".0"]) .succeeds() .stdout_only("0.000000"); new_ucmd!() .args(&["%f", ".0e100000"]) .succeeds() .stdout_only("0.000000"); } #[test] fn float_arg_invalid() { // Just a dot fails. new_ucmd!() .args(&["%f", "."]) .fails() .stdout_is("0.000000") .stderr_contains("expected a numeric value"); new_ucmd!() .args(&["%f", "-."]) .fails() .stdout_is("0.000000") .stderr_contains("expected a numeric value"); // Just an exponent indicator fails. new_ucmd!() .args(&["%f", "e"]) .fails() .stdout_is("0.000000") .stderr_contains("expected a numeric value"); // No digit but only exponent fails new_ucmd!() .args(&["%f", ".e12"]) .fails() .stdout_is("0.000000") .stderr_contains("expected a numeric value"); // No exponent partially fails new_ucmd!() .args(&["%f", "123e"]) .fails() .stdout_is("123.000000") .stderr_contains("value not completely converted"); // Nothing past `0x` parses as zero new_ucmd!() .args(&["%f", "0x"]) .fails() .stdout_is("0.000000") .stderr_contains("value not completely converted"); new_ucmd!() .args(&["%f", "0x."]) .fails() .stdout_is("0.000000") .stderr_contains("value not completely converted"); new_ucmd!() .args(&["%f", "0xp12"]) .fails() .stdout_is("0.000000") .stderr_contains("value not completely converted"); } #[test] fn float_arg_with_whitespace() { new_ucmd!() .args(&["%f", " \u{0020}\u{000d}\t\n0.000001"]) .succeeds() .stdout_only("0.000001"); new_ucmd!() .args(&["%f", "0.1 "]) .fails() .stderr_contains("value not completely converted"); // Unicode whitespace should not be allowed in a number new_ucmd!() .args(&["%f", "\u{2029}0.1"]) .fails() .stderr_contains("expected a numeric value"); // An input string with a whitespace special character that has // not already been expanded should fail. new_ucmd!() .args(&["%f", "\\t0.1"]) .fails() .stderr_contains("expected a numeric value"); } #[test] fn mb_input() { for format in ["\"á", "\'á", "'\u{e1}"] { new_ucmd!() .args(&["%04x\n", format]) .succeeds() .stdout_only("00e1\n"); } let cases = vec![ ("\"á=", "="), ("\'á-", "-"), ("\'á=-==", "=-=="), ("'\u{e1}++", "++"), ]; for (format, expected) in cases { new_ucmd!() .args(&["%04x\n", format]) .succeeds() .stdout_is("00e1\n") .stderr_is(format!("printf: warning: {expected}: character(s) following character constant have been ignored\n")); } } #[test] fn positional_format_specifiers() { new_ucmd!() .args(&["%1$d%d-", "5", "10", "6", "20"]) .succeeds() .stdout_only("55-1010-66-2020-"); new_ucmd!() .args(&["%2$d%d-", "5", "10", "6", "20"]) .succeeds() .stdout_only("105-206-"); new_ucmd!() .args(&["%3$d%d-", "5", "10", "6", "20"]) .succeeds() .stdout_only("65-020-"); new_ucmd!() .args(&["%4$d%d-", "5", "10", "6", "20"]) .succeeds() .stdout_only("205-"); new_ucmd!() .args(&["%5$d%d-", "5", "10", "6", "20"]) .succeeds() .stdout_only("05-"); new_ucmd!() .args(&["%0$d%d-", "5", "10", "6", "20"]) .fails_with_code(1) .stderr_only("printf: %0$: invalid conversion specification\n"); new_ucmd!() .args(&[ "Octal: %6$o, Int: %1$d, Float: %4$f, String: %2$s, Hex: %7$x, Scientific: %5$e, Char: %9$c, Unsigned: %3$u, Integer: %8$i", "42", // 1$d - Int "hello", // 2$s - String "100", // 3$u - Unsigned "3.14159", // 4$f - Float "0.00001", // 5$e - Scientific "77", // 6$o - Octal "255", // 7$x - Hex "123", // 8$i - Integer "A", // 9$c - Char ]) .succeeds() .stdout_only("Octal: 115, Int: 42, Float: 3.141590, String: hello, Hex: ff, Scientific: 1.000000e-05, Char: A, Unsigned: 100, Integer: 123"); }