@@ -936,3 +936,111 @@ fn test_parse_valid_hexadecimal_float_format_issues() {
936936 . succeeds ( )
937937 . stdout_only ( "9.92804e-09\n 1\n " ) ;
938938}
939+
940+ // GNU `seq` manual states that, when the parameters "all use a fixed point
941+ // decimal representation", the format should be `%.pf`, where the precision
942+ // is inferred from parameters. Else, `%g` is used.
943+ //
944+ // This is understandable, as translating hexadecimal precision to decimal precision
945+ // is not straightforward or intuitive to the user. There are some exceptions though,
946+ // if a mix of hexadecimal _integers_ and decimal floats are provided.
947+ //
948+ // The way precision is inferred is said to be able to "represent the output numbers
949+ // exactly". In practice, this means that trailing zeros in first/increment number are
950+ // considered, but not in the last number. This makes sense if we take that last number
951+ // as a "bound", and not really part of input/output.
952+ #[ test]
953+ fn test_precision_corner_cases ( ) {
954+ // Mixed input with integer hex still uses precision in decimal float
955+ new_ucmd ! ( )
956+ . args ( & [ "0x1" , "0.90" , "3" ] )
957+ . succeeds ( )
958+ . stdout_is ( "1.00\n 1.90\n 2.80\n " ) ;
959+
960+ // Mixed input with hex float reverts to %g
961+ new_ucmd ! ( )
962+ . args ( & [ "0x1.00" , "0.90" , "3" ] )
963+ . succeeds ( )
964+ . stdout_is ( "1\n 1.9\n 2.8\n " ) ;
965+
966+ // Even if it's the last number.
967+ new_ucmd ! ( )
968+ . args ( & [ "1" , "1.20" , "0x3.000000" ] )
969+ . succeeds ( )
970+ . stdout_is ( "1\n 2.2\n " ) ;
971+
972+ // Otherwise, precision in last number is ignored.
973+ new_ucmd ! ( )
974+ . args ( & [ "1" , "1.20" , "3.000000" ] )
975+ . succeeds ( )
976+ . stdout_is ( "1.00\n 2.20\n " ) ;
977+
978+ // Infinity is ignored
979+ new_ucmd ! ( )
980+ . args ( & [ "1" , "1.2" , "inf" ] )
981+ . run_stdout_starts_with ( b"1.0\n 2.2\n 3.4\n " )
982+ . success ( ) ;
983+ }
984+
985+ // GNU `seq` manual only makes guarantees about `-w` working if the
986+ // provided numbers "all use a fixed point decimal representation",
987+ // and guides the user to use `-f` for other cases.
988+ #[ test]
989+ fn test_equalize_widths_corner_cases ( ) {
990+ // Mixed input with hexadecimal does behave as expected
991+ new_ucmd ! ( )
992+ . args ( & [ "-w" , "0x1" , "5.2" , "9" ] )
993+ . succeeds ( )
994+ . stdout_is ( "1.0\n 6.2\n " ) ;
995+
996+ // Confusingly, the number of integral digits in the last number is
997+ // used to pad the output numbers, while it is ignored for precision
998+ // computation.
999+ //
1000+ // This problem has been reported on list here:
1001+ // "bug#77179: seq incorrectly(?) pads output when last parameter magnitude"
1002+ // https://lists.gnu.org/archive/html/bug-coreutils/2025-03/msg00028.html
1003+ //
1004+ // TODO: This case could be handled correctly, consider fixing this in
1005+ // `uutils` implementation. Output should probably be "1.0\n6.2\n".
1006+ new_ucmd ! ( )
1007+ . args ( & [ "-w" , "0x1" , "5.2" , "10.0000" ] )
1008+ . succeeds ( )
1009+ . stdout_is ( "01.0\n 06.2\n " ) ;
1010+
1011+ // But if we fixed the case above, we need to make sure we still pad
1012+ // if the last number in the output requires an extra digit.
1013+ new_ucmd ! ( )
1014+ . args ( & [ "-w" , "0x1" , "5.2" , "15.0000" ] )
1015+ . succeeds ( )
1016+ . stdout_is ( "01.0\n 06.2\n 11.4\n " ) ;
1017+
1018+ // GNU `seq` bails out if any hex float is in the output.
1019+ // Unlike the precision corner cases above, it is harder to justify
1020+ // this behavior for hexadecimal float inputs, as it is always be
1021+ // possible to output numbers with a fixed width.
1022+ //
1023+ // This problem has been reported on list here:
1024+ // "bug#76070: Subject: seq, hexadecimal args and equal width"
1025+ // https://lists.gnu.org/archive/html/bug-coreutils/2025-02/msg00007.html
1026+ //
1027+ // TODO: These cases could be handled correctly, consider fixing this in
1028+ // `uutils` implementation.
1029+ // If we ignore hexadecimal precision, the output should be "1.0\n6.2\n".
1030+ new_ucmd ! ( )
1031+ . args ( & [ "-w" , "0x1.0000" , "5.2" , "10" ] )
1032+ . succeeds ( )
1033+ . stdout_is ( "1\n 6.2\n " ) ;
1034+ // The equivalent `seq -w 1.0625 1.00002 3` correctly pads the first number: "1.06250\n2.06252\n"
1035+ new_ucmd ! ( )
1036+ . args ( & [ "-w" , "0x1.1" , "1.00002" , "3" ] )
1037+ . succeeds ( )
1038+ . stdout_is ( "1.0625\n 2.06252\n " ) ;
1039+
1040+ // We can't really pad with infinite number of zeros, so `-w` is ignored.
1041+ // (there is another test with infinity as an increment above)
1042+ new_ucmd ! ( )
1043+ . args ( & [ "-w" , "1" , "1.2" , "inf" ] )
1044+ . run_stdout_starts_with ( b"1.0\n 2.2\n 3.4\n " )
1045+ . success ( ) ;
1046+ }
0 commit comments