1#!/usr/bin/perl 2# Basic tests for "numfmt". 3 4# Copyright (C) 2012-2023 Free Software Foundation, Inc. 5 6# This program is free software: you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation, either version 3 of the License, or 9# (at your option) any later version. 10 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15 16# You should have received a copy of the GNU General Public License 17# along with this program. If not, see <https://www.gnu.org/licenses/>. 18 19use strict; 20 21(my $program_name = $0) =~ s|.*/||; 22my $prog = 'numfmt'; 23 24my $limits = getlimits (); 25 26# TODO: add localization tests with "grouping" 27# Turn off localization of executable's output. 28@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3; 29 30my $locale = $ENV{LOCALE_FR_UTF8}; 31! defined $locale || $locale eq 'none' 32 and $locale = 'C'; 33 34my $try = "Try '$prog --help' for more information.\n"; 35 36my @Tests = 37 ( 38 ['1', '1234', {OUT => "1234"}], 39 ['2', '--from=si 1K', {OUT => "1000"}], 40 ['3', '--from=iec 1K', {OUT => "1024"}], 41 ['4', '--from=auto 1K', {OUT => "1000"}], 42 ['5', '--from=auto 1Ki', {OUT => "1024"}], 43 ['5.1', '--from=iec-i 1Ki', {OUT => "1024"}], 44 45 ['6', {IN_PIPE => "1234\n"}, {OUT => "1234"}], 46 ['7', '--from=si', {IN_PIPE => "2K\n"}, {OUT => "2000"}], 47 ['7a', '--invalid=fail', {IN_PIPE => "no_NL"}, {OUT => "no_NL"}, 48 {ERR => "$prog: invalid number: 'no_NL'\n"}, 49 {EXIT => '2'}], 50 51 ['8', '--to=si 2000', {OUT => "2.0K"}], 52 ['9', '--to=si 2001', {OUT => "2.1K"}], 53 ['10', '--to=si 1999', {OUT => "2.0K"}], 54 ['11', '--to=si --round=down 2001', {OUT => "2.0K"}], 55 ['12', '--to=si --round=down 1999', {OUT => "1.9K"}], 56 ['13', '--to=si --round=up 1901', {OUT => "2.0K"}], 57 ['14', '--to=si --round=down 1901', {OUT => "1.9K"}], 58 ['15', '--to=si --round=nearest 1901', {OUT => "1.9K"}], 59 ['16', '--to=si --round=nearest 1945', {OUT => "1.9K"}], 60 ['17', '--to=si --round=nearest 1955', {OUT => "2.0K"}], 61 62 ['18', '--to=iec 2048', {OUT => "2.0K"}], 63 ['19', '--to=iec 2049', {OUT => "2.1K"}], 64 ['20', '--to=iec 2047', {OUT => "2.0K"}], 65 ['21', '--to=iec --round=down 2049', {OUT => "2.0K"}], 66 ['22', '--to=iec --round=down 2047', {OUT => "1.9K"}], 67 ['23', '--to=iec --round=up 2040', {OUT => "2.0K"}], 68 ['24', '--to=iec --round=down 2040', {OUT => "1.9K"}], 69 ['25', '--to=iec --round=nearest 1996', {OUT => "1.9K"}], 70 ['26', '--to=iec --round=nearest 1997', {OUT => "2.0K"}], 71 ['27', '--to=iec-i 2048', {OUT => "2.0Ki"}], 72 73 ['neg-1', '-- -1234', {OUT => "-1234"}], 74 ['neg-2', '--padding=5 -- -1234', {OUT => "-1234"}], 75 ['neg-3', '--padding=6 -- -1234', {OUT => " -1234"}], 76 ['neg-4', '--to=iec -- 9100 -9100', {OUT => "8.9K\n-8.9K"}], 77 ['neg-5', '-- -0.1', {OUT => "-0.1"}], 78 ['neg-6', '-- -0', {OUT => "0"}], 79 ['neg-7', '-- -0.-1', 80 {ERR => "$prog: invalid number: '-0.-1'\n"}, 81 {EXIT => '2'}], 82 83 ['float-1', '1.1', {OUT => "1.1"}], 84 ['float-2', '1.22', {OUT => "1.22"}], 85 ['float-3', '1.22.', 86 {ERR => "$prog: invalid suffix in input: '1.22.'\n"}, 87 {EXIT => '2'}], 88 89 ['unit-1', '--from-unit=512 4', {OUT => "2048"}], 90 ['unit-2', '--to-unit=512 2048', {OUT => "4"}], 91 ['unit-3', '--from-unit=512 --from=si 4M', {OUT => "2048000000"}], 92 ['unit-4', '--from-unit=512 --from=iec --to=iec 4M', {OUT => "2.0G"}], 93 ['unit-5', '--from-unit=AA --from=iec --to=iec 4M', 94 {ERR => "$prog: invalid unit size: 'AA'\n"}, 95 {EXIT => '1'}], 96 ['unit-6', '--from-unit=54W --from=iec --to=iec 4M', 97 {ERR => "$prog: invalid unit size: '54W'\n"}, 98 {EXIT => '1'}], 99 ['unit-7', '--from-unit=K 30', {OUT=>"30000"}], 100 ['unit-7.1', '--from-unit=Ki 30', {OUT=>"30720"}], 101 ['unit-7.2', '--from-unit=i 0', 102 {ERR => "$prog: invalid unit size: 'i'\n"}, 103 {EXIT => '1'}], 104 ['unit-7.3', '--from-unit=1i 0', 105 {ERR => "$prog: invalid unit size: '1i'\n"}, 106 {EXIT => '1'}], 107 ['unit-8', '--from-unit='.$limits->{UINTMAX_OFLOW}.' --to=iec 30', 108 {ERR => "$prog: invalid unit size: '$limits->{UINTMAX_OFLOW}'\n"}, 109 {EXIT => '1'}], 110 ['unit-9', '--from-unit=0 1', 111 {ERR => "$prog: invalid unit size: '0'\n"}, 112 {EXIT => '1'}], 113 ['unit-10', '--to-unit=0 1', 114 {ERR => "$prog: invalid unit size: '0'\n"}, 115 {EXIT => '1'}], 116 117 # Test Suffix logic 118 ['suf-1', '4000', {OUT=>'4000'}], 119 ['suf-2', '4J', 120 {ERR => "$prog: invalid suffix in input: '4J'\n"}, 121 {EXIT => '2'}], 122 ['suf-2.1', '4M', 123 {ERR => "$prog: rejecting suffix " . 124 "in input: '4M' (consider using --from)\n"}, 125 {EXIT => '2'}], 126 ['suf-3', '--from=si 4M', {OUT=>'4000000'}], 127 ['suf-4', '--from=si 4J', 128 {ERR => "$prog: invalid suffix in input: '4J'\n"}, 129 {EXIT => '2'}], 130 ['suf-5', '--from=si 4MJ', 131 {ERR => "$prog: invalid suffix in input '4MJ': 'J'\n"}, 132 {EXIT => '2'}], 133 134 ['suf-6', '--from=iec 4M', {OUT=>'4194304'}], 135 ['suf-7', '--from=auto 4M', {OUT=>'4000000'}], 136 ['suf-8', '--from=auto 4Mi', {OUT=>'4194304'}], 137 ['suf-9', '--from=auto 4MiJ', 138 {ERR => "$prog: invalid suffix in input '4MiJ': 'J'\n"}, 139 {EXIT => '2'}], 140 ['suf-10', '--from=auto 4JiJ', 141 {ERR => "$prog: invalid suffix in input: '4JiJ'\n"}, 142 {EXIT => '2'}], 143 144 # characters after a white space are OK - printed as-is 145 ['suf-11', '"4 M"', {OUT=>'4 M'}], 146 147 # Custom suffix 148 ['suf-12', '--suffix=Foo 70Foo', {OUT=>'70Foo'}], 149 ['suf-13', '--suffix=Foo 70', {OUT=>'70Foo'}], 150 ['suf-14', '--suffix=Foo --from=si 70K', {OUT=>'70000Foo'}], 151 ['suf-15', '--suffix=Foo --from=si 70KFoo', {OUT=>'70000Foo'}], 152 ['suf-16', '--suffix=Foo --to=si 7000Foo', {OUT=>'7.0KFoo'}], 153 ['suf-17', '--suffix=Foo --to=si 7000Bar', 154 {ERR => "$prog: invalid suffix in input: '7000Bar'\n"}, 155 {EXIT => '2'}], 156 ['suf-18', '--suffix=Foo --to=si 7000FooF', 157 {ERR => "$prog: invalid suffix in input: '7000FooF'\n"}, 158 {EXIT => '2'}], 159 # space(s) between number and suffix. Note only field 1 is used 160 # by default so specify the NUL delimiter to consider the whole "line". 161 ['suf-19', "-d '' --from=si '4.0 K'", {OUT => "4000"}], 162 ['suf-20', 163 '--suffix=Foo' . 'x' x 122 . 'y 0', 164 {OUT => '0Foo' . 'x' x 122 . 'y'}], 165 166 ## GROUPING 167 168 # "C" locale - no grouping (locale-specific tests, below) 169 ['grp-1', '--from=si --grouping 7M', {OUT=>'7000000'}], 170 ['grp-2', '--from=si --to=si --grouping 7M', 171 {ERR => "$prog: grouping cannot be combined with --to\n"}, 172 {EXIT => '1'}], 173 174 175 ## Padding 176 ['pad-1', '--padding=10 5', {OUT=>' 5'}], 177 ['pad-2', '--padding=-10 5', {OUT=>'5 '}], 178 ['pad-3', '--padding=A 5', 179 {ERR => "$prog: invalid padding value 'A'\n"}, 180 {EXIT => '1'}], 181 ['pad-3.1', '--padding=0 5', 182 {ERR => "$prog: invalid padding value '0'\n"}, 183 {EXIT => '1'}], 184 ['pad-4', '--padding=10 --to=si 50000', {OUT=>' 50K'}], 185 ['pad-5', '--padding=-10 --to=si 50000', {OUT=>'50K '}], 186 187 # padding too narrow 188 ['pad-6', '--padding=2 --to=si 1000', {OUT=>'1.0K'}], 189 190 191 # Padding + suffix 192 ['pad-7', '--padding=10 --suffix=foo --to=si 50000', 193 {OUT=>' 50Kfoo'}], 194 ['pad-8', '--padding=-10 --suffix=foo --to=si 50000', 195 {OUT=>'50Kfoo '}], 196 197 198 # Delimiters 199 ['delim-1', '--delimiter=: --from=auto 40M:', {OUT=>'40000000:'}], 200 ['delim-2', '--delimiter="" --from=auto "40 M"',{OUT=>'40000000'}], 201 ['delim-3', '--delimiter=" " --from=auto "40M Foo"',{OUT=>'40000000 Foo'}], 202 ['delim-4', '--delimiter=: --from=auto 40M:60M', {OUT=>'40000000:60M'}], 203 ['delim-5', '-d: --field=2 --from=auto :40M:60M', {OUT=>':40000000:60M'}], 204 ['delim-6', '-d: --field 3 --from=auto 40M:60M', {OUT=>"40M:60M"}], 205 ['delim-err-1', '-d,, --to=si 1', {EXIT=>1}, 206 {ERR => "$prog: the delimiter must be a single character\n"}], 207 208 #Fields 209 ['field-1', '--field A', 210 {ERR => "$prog: invalid field value 'A'\n$try"}, 211 {EXIT => '1'}], 212 ['field-2', '--field 2 --from=auto "Hello 40M World 90G"', 213 {OUT=>'Hello 40000000 World 90G'}], 214 ['field-3', '--field 3 --from=auto "Hello 40M World 90G"', 215 {OUT=>"Hello 40M "}, 216 {ERR=>"$prog: invalid number: 'World'\n"}, 217 {EXIT => 2},], 218 # Last field - no text after number 219 ['field-4', '--field 4 --from=auto "Hello 40M World 90G"', 220 {OUT=>"Hello 40M World 90000000000"}], 221 # Last field - a delimiter after the number 222 ['field-5', '--field 4 --from=auto "Hello 40M World 90G "', 223 {OUT=>"Hello 40M World 90000000000 "}], 224 225 # Mix Fields + Delimiters 226 ['field-6', '--delimiter=: --field 2 --from=auto "Hello:40M:World:90G"', 227 {OUT=>"Hello:40000000:World:90G"}], 228 229 # not enough fields 230 ['field-8', '--field 3 --to=si "Hello World"', {OUT=>"Hello World"}], 231 232 # Multiple fields 233 ['field-range-1', '--field 2,4 --to=si "1000 2000 3000 4000 5000"', 234 {OUT=>"1000 2.0K 3000 4.0K 5000"}], 235 236 ['field-range-2', '--field 2-4 --to=si "1000 2000 3000 4000 5000"', 237 {OUT=>"1000 2.0K 3.0K 4.0K 5000"}], 238 239 ['field-range-3', '--field 1,2,3-5 --to=si "1000 2000 3000 4000 5000"', 240 {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}], 241 242 ['field-range-4', '--field 1-5 --to=si "1000 2000 3000 4000 5000"', 243 {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}], 244 245 ['field-range-5', '--field 1-3,5 --to=si "1000 2000 3000 4000 5000"', 246 {OUT=>"1.0K 2.0K 3.0K 4000 5.0K"}], 247 248 ['field-range-6', '--field 3- --to=si "1000 2000 3000 4000 5000"', 249 {OUT=>"1000 2000 3.0K 4.0K 5.0K"}], 250 251 ['field-range-7', '--field -3 --to=si "1000 2000 3000 4000 5000"', 252 {OUT=>"1.0K 2.0K 3.0K 4000 5000"}], 253 254 ['field-range-8', '--field 1-2,4-5 --to=si "1000 2000 3000 4000 5000"', 255 {OUT=>"1.0K 2.0K 3000 4.0K 5.0K"}], 256 ['field-range-9', '--field 4-5,1-2 --to=si "1000 2000 3000 4000 5000"', 257 {OUT=>"1.0K 2.0K 3000 4.0K 5.0K"}], 258 259 ['field-range-10','--field 1-3,2-4 --to=si "1000 2000 3000 4000 5000"', 260 {OUT=>"1.0K 2.0K 3.0K 4.0K 5000"}], 261 ['field-range-11','--field 2-4,1-3 --to=si "1000 2000 3000 4000 5000"', 262 {OUT=>"1.0K 2.0K 3.0K 4.0K 5000"}], 263 264 ['field-range-12','--field 1-1,3-3 --to=si "1000 2000 3000 4000 5000"', 265 {OUT=>"1.0K 2000 3.0K 4000 5000"}], 266 267 ['field-range-13', '--field 1,-2 --to=si "1000 2000 3000"', 268 {OUT=>"1.0K 2.0K 3000"}], 269 270 ['field-range-14', '--field -2,4- --to=si "1000 2000 3000 4000 5000"', 271 {OUT=>"1.0K 2.0K 3000 4.0K 5.0K"}], 272 ['field-range-15', '--field -2,-4 --to=si "1000 2000 3000 4000 5000"', 273 {OUT=>"1.0K 2.0K 3.0K 4.0K 5000"}], 274 ['field-range-16', '--field 2-,4- --to=si "1000 2000 3000 4000 5000"', 275 {OUT=>"1000 2.0K 3.0K 4.0K 5.0K"}], 276 ['field-range-17', '--field 4-,2- --to=si "1000 2000 3000 4000 5000"', 277 {OUT=>"1000 2.0K 3.0K 4.0K 5.0K"}], 278 279 # white space are valid field separators 280 # (undocumented? but works in cut as well). 281 ['field-range-18', '--field "1,2 4" --to=si "1000 2000 3000 4000 5000"', 282 {OUT=>"1.0K 2.0K 3000 4.0K 5000"}], 283 284 # Unlike 'cut', a lone '-' means 'all fields', even as part of a list 285 # of fields. 286 ['field-range-19','--field 3,- --to=si "1000 2000 3000 4000 5000"', 287 {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}], 288 289 ['all-fields-1', '--field=- --to=si "1000 2000 3000 4000 5000"', 290 {OUT=>"1.0K 2.0K 3.0K 4.0K 5.0K"}], 291 292 ['field-range-err-1', '--field -foo --to=si 10', 293 {EXIT=>1}, {ERR=>"$prog: invalid field value 'foo'\n$try"}], 294 ['field-range-err-2', '--field --3 --to=si 10', 295 {EXIT=>1}, {ERR=>"$prog: invalid field range\n$try"}], 296 ['field-range-err-3', '--field 0 --to=si 10', 297 {EXIT=>1}, {ERR=>"$prog: fields are numbered from 1\n$try"}], 298 ['field-range-err-4', '--field 3-2 --to=si 10', 299 {EXIT=>1}, {ERR=>"$prog: invalid decreasing range\n$try"}], 300 ['field-range-err-6', '--field - --field 1- --to=si 10', 301 {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}], 302 ['field-range-err-7', '--field -1 --field 1- --to=si 10', 303 {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}], 304 ['field-range-err-8', '--field -1 --field 1,2,3 --to=si 10', 305 {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}], 306 ['field-range-err-9', '--field 1- --field 1,2,3 --to=si 10', 307 {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}], 308 ['field-range-err-10','--field 1,2,3 --field 1- --to=si 10', 309 {EXIT=>1}, {ERR=>"$prog: multiple field specifications\n"}], 310 ['field-range-err-11','--field 1-2-3 --to=si 10', 311 {EXIT=>1}, {ERR=>"$prog: invalid field range\n$try"}], 312 ['field-range-err-12','--field 0-1 --to=si 10', 313 {EXIT=>1}, {ERR=>"$prog: fields are numbered from 1\n$try"}], 314 ['field-range-err-13','--field '.$limits->{UINTMAX_MAX}.',22 --to=si 10', 315 {EXIT=>1}, {ERR=>"$prog: field number " . 316 "'".$limits->{UINTMAX_MAX}."' is too large\n$try"}], 317 318 # Auto-consume white-space, setup auto-padding 319 ['whitespace-1', '--to=si --field 2 "A 500 B"', {OUT=>"A 500 B"}], 320 ['whitespace-2', '--to=si --field 2 "A 5000 B"', {OUT=>"A 5.0K B"}], 321 ['whitespace-3', '--to=si " 500"', {OUT=>" 500"}], 322 ['whitespace-4', '--to=si " 6500"', {OUT=>" 6.5K"}], 323 # NOTE: auto-padding is not enabled if the value is on the first 324 # field and there's no white-space before it. 325 ['whitespace-5', '--to=si "6000000"', {OUT=>"6.0M"}], 326 # but if there is whitespace, assume auto-padding is desired. 327 ['whitespace-6', '--to=si " 6000000"', {OUT=>" 6.0M"}], 328 329 # auto-padding - lines have same padding-width 330 # (padding_buffer will be alloc'd just once) 331 ['whitespace-7', '--to=si --field 2', 332 {IN_PIPE=>"rootfs 100000\n" . 333 "udevxx 2000000\n"}, 334 {OUT =>"rootfs 100K\n" . 335 "udevxx 2.0M"}], 336 # auto-padding - second line requires a 337 # larger padding (padding-buffer needs to be realloc'd) 338 ['whitespace-8', '--to=si --field 2', 339 {IN_PIPE=>"rootfs 100000\n" . 340 "udev 20000000\n"}, 341 {OUT =>"rootfs 100K\n" . 342 "udev 20M"}], 343 344 345 # Corner-cases: 346 # weird mix of identical suffix,delimiters 347 # The priority is: 348 # 1. delimiters (and fields) are parsed (in process_line() 349 # 2. optional custom suffix is removed (in process_suffixed_number()) 350 # 3. Remaining suffixes must be valid SI/IEC (in human_xstrtol()) 351 352 # custom suffix comes BEFORE SI/IEC suffix, 353 # so these are 40 of "M", not 40,000,000. 354 ['mix-1', '--suffix=M --from=si 40M', {OUT=>"40M"}], 355 356 # These are forty-million Ms . 357 ['mix-2', '--suffix=M --from=si 40MM', {OUT=>"40000000M"}], 358 359 ['mix-3', '--suffix=M --from=auto 40MM', {OUT=>"40000000M"}], 360 ['mix-4', '--suffix=M --from=auto 40MiM', {OUT=>"41943040M"}], 361 ['mix-5', '--suffix=M --to=si --from=si 4MM', {OUT=>"4.0MM"}], 362 363 # This might be confusing to the user, but it's legit: 364 # The M in the output is the custom suffix, not Mega. 365 ['mix-6', '--suffix=M 40', {OUT=>"40M"}], 366 ['mix-7', '--suffix=M 4000000', {OUT=>"4000000M"}], 367 ['mix-8', '--suffix=M --to=si 4000000', {OUT=>"4.0MM"}], 368 369 # The output 'M' is the custom suffix. 370 ['mix-10', '--delimiter=M --suffix=M 40', {OUT=>"40M"}], 371 372 # The INPUT 'M' is a delimiter (delimiters are top priority) 373 # The output contains one M for custom suffix, and one 'M' delimiter. 374 ['mix-11', '--delimiter=M --suffix=M 40M', {OUT=>"40MM"}], 375 376 # Same as above, the "M" is NOT treated as a mega SI prefix, 377 ['mix-12', '--delimiter=M --from=si --suffix=M 40M', {OUT=>"40MM"}], 378 379 # The 'M' is treated as a delimiter, and so the input value is '4000' 380 ['mix-13', '--delimiter=M --to=si --from=auto 4000M5000M9000', 381 {OUT=>"4.0KM5000M9000"}], 382 # 'M' is the delimiter, so the second input field is '5000' 383 ['mix-14', '--delimiter=M --field 2 --from=auto --to=si 4000M5000M9000', 384 {OUT=>"4000M5.0KM9000"}], 385 386 387 388 ## Header testing 389 390 # header - silently ignored with command line parameters 391 ['header-1', '--header --to=iec 4096', {OUT=>"4.0K"}], 392 393 # header warning with --debug 394 ['header-2', '--debug --header --to=iec 4096', {OUT=>"4.0K"}, 395 {ERR=>"$prog: --header ignored with command-line input\n"}], 396 397 ['header-3', '--header=A', 398 {ERR=>"$prog: invalid header value 'A'\n"}, 399 {EXIT => 1},], 400 ['header-4', '--header=0', 401 {ERR=>"$prog: invalid header value '0'\n"}, 402 {EXIT => 1},], 403 ['header-5', '--header=-6', 404 {ERR=>"$prog: invalid header value '-6'\n"}, 405 {EXIT => 1},], 406 ['header-6', '--debug --header --to=iec', 407 {IN_PIPE=>"size\n5000\n90000\n"}, 408 {OUT=>"size\n4.9K\n88K"}], 409 ['header-7', '--debug --header=3 --to=iec', 410 {IN_PIPE=>"hello\nworld\nsize\n5000\n90000\n"}, 411 {OUT=>"hello\nworld\nsize\n4.9K\n88K"}], 412 # header, but no actual content 413 ['header-8', '--header=2 --to=iec', 414 {IN_PIPE=>"hello\nworld\n"}, 415 {OUT=>"hello\nworld"}], 416 # not enough header lines 417 ['header-9', '--header=3 --to=iec', 418 {IN_PIPE=>"hello\nworld\n"}, 419 {OUT=>"hello\nworld"}], 420 421 422 ## human_strtod testing 423 424 # NO_DIGITS_FOUND 425 ['strtod-1', '--from=si "foo"', 426 {ERR=>"$prog: invalid number: 'foo'\n"}, 427 {EXIT=> 2}], 428 ['strtod-2', '--from=si ""', 429 {ERR=>"$prog: invalid number: ''\n"}, 430 {EXIT=> 2}], 431 432 # FRACTION_NO_DIGITS_FOUND 433 ['strtod-5', '--from=si 12.', 434 {ERR=>"$prog: invalid number: '12.'\n"}, 435 {EXIT=>2}], 436 ['strtod-6', '--from=si 12.K', 437 {ERR=>"$prog: invalid number: '12.K'\n"}, 438 {EXIT=>2}], 439 440 # whitespace is not allowed after decimal-point 441 ['strtod-6.1', '--from=si --delimiter=, "12. 2"', 442 {ERR=>"$prog: invalid number: '12. 2'\n"}, 443 {EXIT=>2}], 444 445 # INVALID_SUFFIX 446 ['strtod-9', '--from=si 12.2J', 447 {ERR=>"$prog: invalid suffix in input: '12.2J'\n"}, 448 {EXIT=>2}], 449 450 # VALID_BUT_FORBIDDEN_SUFFIX 451 ['strtod-10', '12M', 452 {ERR => "$prog: rejecting suffix " . 453 "in input: '12M' (consider using --from)\n"}, 454 {EXIT=>2}], 455 456 # MISSING_I_SUFFIX 457 ['strtod-11', '--from=iec-i 12M', 458 {ERR => "$prog: missing 'i' suffix in input: " . 459 "'12M' (e.g Ki/Mi/Gi)\n"}, 460 {EXIT=>2}], 461 462 # 463 # Test double_to_human() 464 # 465 466 # 1K and smaller 467 ['dbl-to-human-1','--to=si 800', {OUT=>"800"}], 468 ['dbl-to-human-2','--to=si 0', {OUT=>"0"}], 469 ['dbl-to-human-2.1','--to=si 999', {OUT=>"999"}], 470 ['dbl-to-human-2.2','--to=si 1000', {OUT=>"1.0K"}], 471 #NOTE: the following are consistent with "ls -lh" output 472 ['dbl-to-human-2.3','--to=iec 999', {OUT=>"999"}], 473 ['dbl-to-human-2.4','--to=iec 1023', {OUT=>"1023"}], 474 ['dbl-to-human-2.5','--to=iec 1024', {OUT=>"1.0K"}], 475 ['dbl-to-human-2.6','--to=iec 1025', {OUT=>"1.1K"}], 476 ['dbl-to-human-2.7','--to=iec 0', {OUT=>"0"}], 477 # no "i" suffix if output has no suffix 478 ['dbl-to-human-2.8','--to=iec-i 0', {OUT=>"0"}], 479 480 # values resulting in "N.Nx" output 481 ['dbl-to-human-3','--to=si 8000', {OUT=>"8.0K"}], 482 ['dbl-to-human-3.1','--to=si 8001', {OUT=>"8.1K"}], 483 ['dbl-to-human-4','--to=si --round=down 8001', {OUT=>"8.0K"}], 484 485 ['dbl-to-human-5','--to=si --round=down 3500', {OUT=>"3.5K"}], 486 ['dbl-to-human-6','--to=si --round=nearest 3500', {OUT=>"3.5K"}], 487 ['dbl-to-human-7','--to=si --round=up 3500', {OUT=>"3.5K"}], 488 489 ['dbl-to-human-8','--to=si --round=down 3501', {OUT=>"3.5K"}], 490 ['dbl-to-human-9','--to=si --round=nearest 3501', {OUT=>"3.5K"}], 491 ['dbl-to-human-10','--to=si --round=up 3501', {OUT=>"3.6K"}], 492 493 ['dbl-to-human-11','--to=si --round=nearest 3550', {OUT=>"3.6K"}], 494 ['dbl-to-human-12','--to=si --from=si 999.89K', {OUT=>"1.0M"}], 495 ['dbl-to-human-13','--to=si --from=si 9.9K', {OUT=>"9.9K"}], 496 ['dbl-to-human-14','--to=si 9900', {OUT=>"9.9K"}], 497 ['dbl-to-human-15','--to=iec --from=si 3.3K', {OUT=>"3.3K"}], 498 ['dbl-to-human-16','--to=iec --round=down --from=si 3.3K', {OUT=>"3.2K"}], 499 500 # values resulting in 'NNx' output 501 ['dbl-to-human-17','--to=si 9999', {OUT=>"10K"}], 502 ['dbl-to-human-18','--to=si --round=down 35000', {OUT=>"35K"}], 503 ['dbl-to-human-19','--to=iec 35000', {OUT=>"35K"}], 504 ['dbl-to-human-20','--to=iec --round=down 35000', {OUT=>"34K"}], 505 ['dbl-to-human-21','--to=iec 35000000', {OUT=>"34M"}], 506 ['dbl-to-human-22','--to=iec --round=down 35000000', {OUT=>"33M"}], 507 ['dbl-to-human-23','--to=si 35000001', {OUT=>"36M"}], 508 ['dbl-to-human-24','--to=si --from=si 9.99M', {OUT=>"10M"}], 509 ['dbl-to-human-25','--to=si --from=iec 9.99M', {OUT=>"11M"}], 510 ['dbl-to-human-25.1','--to=iec 99999', {OUT=>"98K"}], 511 512 # values resulting in 'NNNx' output 513 ['dbl-to-human-26','--to=si 999000000000', {OUT=>"999G"}], 514 ['dbl-to-human-27','--to=iec 999000000000', {OUT=>"931G"}], 515 ['dbl-to-human-28','--to=si 123600000000000', {OUT=>"124T"}], 516 ['dbl-to-human-29','--to=si 998123', {OUT=>"999K"}], 517 ['dbl-to-human-30','--to=si --round=nearest 998123', {OUT=>"998K"}], 518 ['dbl-to-human-31','--to=si 99999', {OUT=>"100K"}], 519 ['dbl-to-human-32','--to=iec 102399', {OUT=>"100K"}], 520 ['dbl-to-human-33','--to=iec-i 102399', {OUT=>"100Ki"}], 521 522 523 # Default --round=from-zero 524 ['round-1','--to-unit=1024 -- 6000 -6000', 525 {OUT=>"6\n-6"}], 526 ['round-2','--to-unit=1024 -- 6000.0 -6000.0', 527 {OUT=>"5.9\n-5.9"}], 528 ['round-3','--to-unit=1024 -- 6000.00 -6000.00', 529 {OUT=>"5.86\n-5.86"}], 530 ['round-4','--to-unit=1024 -- 6000.000 -6000.000', 531 {OUT=>"5.860\n-5.860"}], 532 ['round-5','--to-unit=1024 -- 6000.0000 -6000.0000', 533 {OUT=>"5.8594\n-5.8594"}], 534 # --round=up 535 ['round-1-up','--round=up --to-unit=1024 -- 6000 -6000', 536 {OUT=>"6\n-5"}], 537 ['round-2-up','--round=up --to-unit=1024 -- 6000.0 -6000.0', 538 {OUT=>"5.9\n-5.8"}], 539 ['round-3-up','--round=up --to-unit=1024 -- 6000.00 -6000.00', 540 {OUT=>"5.86\n-5.85"}], 541 ['round-4-up','--round=up --to-unit=1024 -- 6000.000 -6000.000', 542 {OUT=>"5.860\n-5.859"}], 543 ['round-5-up','--round=up --to-unit=1024 -- 6000.0000 -6000.0000', 544 {OUT=>"5.8594\n-5.8593"}], 545 # --round=down 546 ['round-1-down','--round=down --to-unit=1024 -- 6000 -6000', 547 {OUT=>"5\n-6"}], 548 ['round-2-down','--round=down --to-unit=1024 -- 6000.0 -6000.0', 549 {OUT=>"5.8\n-5.9"}], 550 ['round-3-down','--round=down --to-unit=1024 -- 6000.00 -6000.00', 551 {OUT=>"5.85\n-5.86"}], 552 ['round-4-down','--round=down --to-unit=1024 -- 6000.000 -6000.000', 553 {OUT=>"5.859\n-5.860"}], 554 ['round-5-down','--round=down --to-unit=1024 -- 6000.0000 -6000.0000', 555 {OUT=>"5.8593\n-5.8594"}], 556 # --round=towards-zero 557 ['round-1-to-zero','--ro=towards-zero --to-u=1024 -- 6000 -6000', 558 {OUT=>"5\n-5"}], 559 ['round-2-to-zero','--ro=towards-zero --to-u=1024 -- 6000.0 -6000.0', 560 {OUT=>"5.8\n-5.8"}], 561 ['round-3-to-zero','--ro=towards-zero --to-u=1024 -- 6000.00 -6000.00', 562 {OUT=>"5.85\n-5.85"}], 563 ['round-4-to-zero','--ro=towards-zero --to-u=1024 -- 6000.000 -6000.000', 564 {OUT=>"5.859\n-5.859"}], 565 ['round-5-to-zero','--ro=towards-zero --to-u=1024 -- 6000.0000 -6000.0000', 566 {OUT=>"5.8593\n-5.8593"}], 567 # --round=nearest 568 ['round-1-near','--ro=nearest --to-u=1024 -- 6000 -6000', 569 {OUT=>"6\n-6"}], 570 ['round-2-near','--ro=nearest --to-u=1024 -- 6000.0 -6000.0', 571 {OUT=>"5.9\n-5.9"}], 572 ['round-3-near','--ro=nearest --to-u=1024 -- 6000.00 -6000.00', 573 {OUT=>"5.86\n-5.86"}], 574 ['round-4-near','--ro=nearest --to-u=1024 -- 6000.000 -6000.000', 575 {OUT=>"5.859\n-5.859"}], 576 ['round-5-near','--ro=nearest --to-u=1024 -- 6000.0000 -6000.0000', 577 {OUT=>"5.8594\n-5.8594"}], 578 579 580 # Leading zeros weren't handled appropriately before 8.24 581 ['leading-1','0000000000000000000000000001', {OUT=>"1"}], 582 ['leading-2','.1', {OUT=>"0.1"}], 583 ['leading-3','bad.1', 584 {ERR => "$prog: invalid number: 'bad.1'\n"}, 585 {EXIT => 2}], 586 ['leading-4','..1', 587 {ERR => "$prog: invalid suffix in input: '..1'\n"}, 588 {EXIT => 2}], 589 ['leading-5','1.', 590 {ERR => "$prog: invalid number: '1.'\n"}, 591 {EXIT => 2}], 592 593 # precision override 594 ['precision-1','--format=%.4f 9991239123 --to=si', {OUT=>"9.9913G"}], 595 ['precision-2','--format=%.1f 9991239123 --to=si', {OUT=>"10.0G"}], 596 ['precision-3','--format=%.1f 1', {OUT=>"1.0"}], 597 ['precision-4','--format=%.1f 1.12', {OUT=>"1.2"}], 598 ['precision-5','--format=%.1f 9991239123 --to-unit=G', {OUT=>"10.0"}], 599 ['precision-6','--format="% .1f" 9991239123 --to-unit=G', {OUT=>"10.0"}], 600 ['precision-7','--format=%.-1f 1.1', 601 {ERR => "$prog: invalid precision in format '%.-1f'\n"}, 602 {EXIT => 1}], 603 ['precision-8','--format=%.+1f 1.1', 604 {ERR => "$prog: invalid precision in format '%.+1f'\n"}, 605 {EXIT => 1}], 606 ['precision-9','--format="%. 1f" 1.1', 607 {ERR => "$prog: invalid precision in format '%. 1f'\n"}, 608 {EXIT => 1}], 609 610 # debug warnings 611 ['debug-1', '--debug 4096', {OUT=>"4096"}, 612 {ERR=>"$prog: no conversion option specified\n"}], 613 # '--padding' is a valid conversion option - no warning should be printed 614 ['debug-1.1', '--debug --padding 10 4096', {OUT=>" 4096"}], 615 ['debug-2', '--debug --grouping --from=si 4.0K', {OUT=>"4000"}, 616 {ERR=>"$prog: grouping has no effect in this locale\n"}], 617 618 # dev-debug messages - the actual messages don't matter 619 # just ensure the program works, and for code coverage testing. 620 ['devdebug-1', '---debug --from=si 4.9K', {OUT=>"4900"}, 621 {ERR=>""}, 622 {ERR_SUBST=>"s/.*//msg"}], 623 ['devdebug-2', '---debug 4900', {OUT=>"4900"}, 624 {ERR=>""}, 625 {ERR_SUBST=>"s/.*//msg"}], 626 ['devdebug-3', '---debug --from=auto 4Mi', {OUT=>"4194304"}, 627 {ERR=>""}, 628 {ERR_SUBST=>"s/.*//msg"}], 629 ['devdebug-4', '---debug --to=si 4000000', {OUT=>"4.0M"}, 630 {ERR=>""}, 631 {ERR_SUBST=>"s/.*//msg"}], 632 ['devdebug-5', '---debug --to=si --padding=5 4000000', {OUT=>" 4.0M"}, 633 {ERR=>""}, 634 {ERR_SUBST=>"s/.*//msg"}], 635 ['devdebug-6', '---debug --suffix=Foo 1234Foo', {OUT=>"1234Foo"}, 636 {ERR=>""}, 637 {ERR_SUBST=>"s/.*//msg"}], 638 ['devdebug-7', '---debug --suffix=Foo 1234', {OUT=>"1234Foo"}, 639 {ERR=>""}, 640 {ERR_SUBST=>"s/.*//msg"}], 641 ['devdebug-9', '---debug --grouping 10000', {OUT=>"10000"}, 642 {ERR=>""}, 643 {ERR_SUBST=>"s/.*//msg"}], 644 ['devdebug-10', '---debug --format %f 10000', {OUT=>"10000"}, 645 {ERR=>""}, 646 {ERR_SUBST=>"s/.*//msg"}], 647 ['devdebug-11', '---debug --format "%\'-10f" 10000',{OUT=>"10000 "}, 648 {ERR=>""}, 649 {ERR_SUBST=>"s/.*//msg"}], 650 651 # Invalid parameters 652 ['help-1', '--foobar', 653 {ERR=>"$prog: unrecognized option\n$try"}, 654 {ERR_SUBST=>"s/option.*/option/; s/unknown/unrecognized/"}, 655 {EXIT=>1}], 656 657 ## Format string - check error detection 658 ['fmt-err-1', '--format ""', 659 {ERR=>"$prog: format '' has no % directive\n"}, 660 {EXIT=>1}], 661 ['fmt-err-2', '--format "hello"', 662 {ERR=>"$prog: format 'hello' has no % directive\n"}, 663 {EXIT=>1}], 664 ['fmt-err-3', '--format "hello%"', 665 {ERR=>"$prog: format 'hello%' ends in %\n"}, 666 {EXIT=>1}], 667 ['fmt-err-4', '--format "%d"', 668 {ERR=>"$prog: invalid format '%d', " . 669 "directive must be %[0]['][-][N][.][N]f\n"}, 670 {EXIT=>1}], 671 ['fmt-err-5', '--format "% -43 f"', 672 {ERR=>"$prog: invalid format '% -43 f', " . 673 "directive must be %[0]['][-][N][.][N]f\n"}, 674 {EXIT=>1}], 675 ['fmt-err-6', '--format "%f %f"', 676 {ERR=>"$prog: format '%f %f' has too many % directives\n"}, 677 {EXIT=>1}], 678 ['fmt-err-9', '--format "%f" --grouping', 679 {ERR=>"$prog: --grouping cannot be combined with --format\n"}, 680 {EXIT=>1}], 681 ['fmt-err-10', '--format "%\'f" --to=si', 682 {ERR=>"$prog: grouping cannot be combined with --to\n"}, 683 {EXIT=>1}], 684 ['fmt-err-11', '--debug --format "%\'f" 5000', {OUT=>"5000"}, 685 {ERR=>"$prog: grouping has no effect in this locale\n"}], 686 687 ## Format string - check some corner cases 688 ['fmt-1', '--format "%% %f" 5000', {OUT=>"%%5000"}], 689 ['fmt-2', '--format "%f %%" 5000', {OUT=>"5000 %%"}], 690 691 ['fmt-3', '--format "--%f--" 5000000', {OUT=>"--5000000--"}], 692 ['fmt-4', '--format "--%f--" --to=si 5000000', {OUT=>"--5.0M--"}], 693 694 ['fmt-5', '--format "--%10f--" --to=si 5000000',{OUT=>"-- 5.0M--"}], 695 ['fmt-6', '--format "--%-10f--" --to=si 5000000',{OUT=>"--5.0M --"}], 696 ['fmt-7', '--format "--%10f--" 5000000',{OUT=>"-- 5000000--"}], 697 ['fmt-8', '--format "--%-10f--" 5000000',{OUT=>"--5000000 --"}], 698 699 # too-short width 700 ['fmt-9', '--format "--%5f--" 5000000',{OUT=>"--5000000--"}], 701 702 # Format + Suffix 703 ['fmt-10', '--format "--%10f--" --suffix Foo 50', {OUT=>"-- 50Foo--"}], 704 ['fmt-11', '--format "--%-10f--" --suffix Foo 50',{OUT=>"--50Foo --"}], 705 706 # Grouping in C locale - no grouping effect 707 ['fmt-12', '--format "%\'f" 50000',{OUT=>"50000"}], 708 ['fmt-13', '--format "%\'10f" 50000', {OUT=>" 50000"}], 709 ['fmt-14', '--format "%\'-10f" 50000',{OUT=>"50000 "}], 710 711 # Very large format strings 712 ['fmt-15', '--format "--%100000f--" --to=si 4200', 713 {OUT=>"--" . " " x 99996 . "4.2K--" }], 714 715 # --format padding overrides --padding 716 ['fmt-16', '--format="%6f" --padding=66 1234',{OUT=>" 1234"}], 717 718 # zero padding 719 ['fmt-17', '--format="%06f" 1234',{OUT=>"001234"}], 720 # also support spaces (which are ignored as spacing is handled separately) 721 ['fmt-18', '--format="%0 6f" 1234',{OUT=>"001234"}], 722 # handle generic padding in combination 723 ['fmt-22', '--format="%06f" --padding=7 1234',{OUT=>" 001234"}], 724 ['fmt-23', '--format="%06f" --padding=-7 1234',{OUT=>"001234 "}], 725 726 727 ## Check all errors again, this time with --invalid=fail 728 ## Input will be printed without conversion, 729 ## and exit code will be 2 730 ['ign-err-1', '--invalid=fail 4J', 731 {ERR => "$prog: invalid suffix in input: '4J'\n"}, 732 {OUT => "4J\n"}, 733 {EXIT => 2}], 734 ['ign-err-2', '--invalid=fail 4M', 735 {ERR => "$prog: rejecting suffix " . 736 "in input: '4M' (consider using --from)\n"}, 737 {OUT => "4M\n"}, 738 {EXIT => 2}], 739 ['ign-err-3', '--invalid=fail --from=si 4MJ', 740 {ERR => "$prog: invalid suffix in input '4MJ': 'J'\n"}, 741 {OUT => "4MJ\n"}, 742 {EXIT => 2}], 743 ['ign-err-4', '--invalid=fail --suffix=Foo --to=si 7000FooF', 744 {ERR => "$prog: invalid suffix in input: '7000FooF'\n"}, 745 {OUT => "7000FooF\n"}, 746 {EXIT => 2}], 747 ['ign-err-5','--invalid=fail --field 3 --from=auto "Hello 40M World 90G"', 748 {ERR => "$prog: invalid number: 'World'\n"}, 749 {OUT => "Hello 40M World 90G\n"}, 750 {EXIT => 2}], 751 ['ign-err-7', '--invalid=fail --from=si "foo"', 752 {ERR => "$prog: invalid number: 'foo'\n"}, 753 {OUT => "foo\n"}, 754 {EXIT=> 2}], 755 ['ign-err-8', '--invalid=fail 12M', 756 {ERR => "$prog: rejecting suffix " . 757 "in input: '12M' (consider using --from)\n"}, 758 {OUT => "12M\n"}, 759 {EXIT => 2}], 760 ['ign-err-9', '--invalid=fail --from=iec-i 12M', 761 {ERR => "$prog: missing 'i' suffix in input: " . 762 "'12M' (e.g Ki/Mi/Gi)\n"}, 763 {OUT => "12M\n"}, 764 {EXIT=>2}], 765 766 ## Ignore Errors with multiple conversions 767 ['ign-err-m1', '--invalid=ignore --to=si 1000 2000 bad 3000', 768 {OUT => "1.0K\n2.0K\nbad\n3.0K"}, 769 {EXIT => 0}], 770 ['ign-err-m1.1', '--invalid=ignore --to=si', 771 {IN_PIPE => "1000\n2000\nbad\n3000\n"}, 772 {OUT => "1.0K\n2.0K\nbad\n3.0K"}, 773 {EXIT => 0}], 774 ['ign-err-m1.3', '--invalid=fail --debug --to=si 1000 2000 3000', 775 {OUT => "1.0K\n2.0K\n3.0K"}, 776 {EXIT => 0}], 777 ['ign-err-m2', '--invalid=fail --to=si 1000 Foo 3000', 778 {OUT => "1.0K\nFoo\n3.0K\n"}, 779 {ERR => "$prog: invalid number: 'Foo'\n"}, 780 {EXIT => 2}], 781 ['ign-err-m2.1', '--invalid=warn --to=si', 782 {IN_PIPE => "1000\nFoo\n3000\n"}, 783 {OUT => "1.0K\nFoo\n3.0K"}, 784 {ERR => "$prog: invalid number: 'Foo'\n"}, 785 {EXIT => 0}], 786 787 # --debug will trigger a final warning at EOF 788 ['ign-err-m2.2', '--invalid=fail --debug --to=si 1000 Foo 3000', 789 {OUT => "1.0K\nFoo\n3.0K\n"}, 790 {ERR => "$prog: invalid number: 'Foo'\n" . 791 "$prog: failed to convert some of the input numbers\n"}, 792 {EXIT => 2}], 793 794 ['ign-err-m3', '--invalid=fail --field 2 --from=si --to=iec', 795 {IN_PIPE => "A 1K x\nB 2M y\nC 3G z\n"}, 796 {OUT => "A 1000 x\nB 2.0M y\nC 2.8G z"}, 797 {EXIT => 0}], 798 # invalid input on one of the fields 799 ['ign-err-m3.1', '--invalid=fail --field 2 --from=si --to=iec', 800 {IN_PIPE => "A 1K x\nB Foo y\nC 3G z\n"}, 801 {OUT => "A 1000 x\nB Foo y\nC 2.8G z\n"}, 802 {ERR => "$prog: invalid number: 'Foo'\n"}, 803 {EXIT => 2}], 804 ); 805 806# test null-terminated lines 807my @NullDelim_Tests = 808 ( 809 # Input from STDIN 810 ['z1', '-z --to=iec', 811 {IN_PIPE => "1025\x002048\x00"}, {OUT=>"1.1K\x002.0K\x00"}], 812 813 # Input from the commandline - terminated by NULL vs NL 814 ['z3', ' --to=iec 1024', {OUT=>"1.0K\n"}], 815 ['z2', '-z --to=iec 1024', {OUT=>"1.0K\x00"}], 816 817 # Input from STDIN, with fields 818 ['z4', '-z --field=3 --to=si', 819 {IN_PIPE => "A B 1001 C\x00" . 820 "D E 2002 F\x00"}, 821 {OUT => "A B 1.1K C\x00" . 822 "D E 2.1K F\x00"}], 823 824 # Input from STDIN, with fields and embedded NL 825 ['z5', '-z --field=3 --to=si', 826 {IN_PIPE => "A\nB 1001 C\x00" . 827 "D E\n2002 F\x00"}, 828 {OUT => "A B 1.1K C\x00" . 829 "D E 2.1K F\x00"}], 830 ); 831 832my @Limit_Tests = 833 ( 834 # Large Values 835 ['large-1','1000000000000000', {OUT=>"1000000000000000"}], 836 # 18 digits is OK 837 ['large-2','1000000000000000000', {OUT=>"1000000000000000000"}], 838 # 19 digits is too much (without output scaling) 839 ['large-3','10000000000000000000', 840 {ERR => "$prog: value too large to be printed: '1e+19' " . 841 "(consider using --to)\n"}, 842 {EXIT=>2}], 843 ['large-4','1000000000000000000.0', 844 {ERR => "$prog: value/precision too large to be printed: " . 845 "'1e+18/1' (consider using --to)\n"}, 846 {EXIT=>2}], 847 848 849 # Test input: 850 # Up to 33 digits is OK. 851 ['large-3.1', '--to=si 1', {OUT=> "1"}], 852 ['large-3.2', '--to=si 10', {OUT=> "10"}], 853 ['large-3.3', '--to=si 100', {OUT=> "100"}], 854 ['large-3.4', '--to=si 1000', {OUT=>"1.0K"}], 855 ['large-3.5', '--to=si 10000', {OUT=> "10K"}], 856 ['large-3.6', '--to=si 100000', {OUT=>"100K"}], 857 ['large-3.7', '--to=si 1000000', {OUT=>"1.0M"}], 858 ['large-3.8', '--to=si 10000000', {OUT=> "10M"}], 859 ['large-3.9', '--to=si 100000000', {OUT=>"100M"}], 860 ['large-3.10','--to=si 1000000000', {OUT=>"1.0G"}], 861 ['large-3.11','--to=si 10000000000', {OUT=> "10G"}], 862 ['large-3.12','--to=si 100000000000', {OUT=>"100G"}], 863 ['large-3.13','--to=si 1000000000000', {OUT=>"1.0T"}], 864 ['large-3.14','--to=si 10000000000000', {OUT=> "10T"}], 865 ['large-3.15','--to=si 100000000000000', {OUT=>"100T"}], 866 ['large-3.16','--to=si 1000000000000000', {OUT=>"1.0P"}], 867 ['large-3.17','--to=si 10000000000000000', {OUT=> "10P"}], 868 ['large-3.18','--to=si 100000000000000000', {OUT=>"100P"}], 869 ['large-3.19','--to=si 1000000000000000000', {OUT=>"1.0E"}], 870 ['large-3.20','--to=si 10000000000000000000', {OUT=> "10E"}], 871 ['large-3.21','--to=si 210000000000000000000', {OUT=>"210E"}], 872 ['large-3.22','--to=si 3210000000000000000000', {OUT=>"3.3Z"}], 873 ['large-3.23','--to=si 43210000000000000000000', {OUT=> "44Z"}], 874 ['large-3.24','--to=si 543210000000000000000000', {OUT=>"544Z"}], 875 ['large-3.25','--to=si 6543210000000000000000000', {OUT=>"6.6Y"}], 876 ['large-3.26','--to=si 76543210000000000000000000', {OUT=> "77Y"}], 877 ['large-3.27','--to=si 876543210000000000000000000', {OUT=>"877Y"}], 878 ['large-3.28','--to=si 9876543210000000000000000000', {OUT=>"9.9R"}], 879 ['large-3.29','--to=si 19876543210000000000000000000', {OUT=> "20R"}], 880 ['large-3.30','--to=si 219876543210000000000000000000', {OUT=>"220R"}], 881 ['large-3.31','--to=si 3219876543210000000000000000000', {OUT=>"3.3Q"}], 882 ['large-3.32','--to=si 43219876543210000000000000000000', {OUT=> "44Q"}], 883 ['large-3.33','--to=si 543219876543210000000000000000000', {OUT=>"544Q"}], 884 885 # More than 33 digits is not OK 886 ['large-3.34','--to=si 6543219876543210000000000000000000', 887 {ERR => "$prog: value too large to be converted: " . 888 "'6543219876543210000000000000000000'\n"}, 889 {EXIT => 2}], 890 891 # Test Output 892 ['large-4.1', '--from=si 9.7M', {OUT=>"9700000"}], 893 ['large-4.2', '--from=si 10M', {OUT =>"10000000"}], 894 ['large-4.3', '--from=si 200M', {OUT =>"200000000"}], 895 ['large-4.4', '--from=si 3G', {OUT =>"3000000000"}], 896 ['large-4.5', '--from=si 40G', {OUT =>"40000000000"}], 897 ['large-4.6', '--from=si 500G', {OUT =>"500000000000"}], 898 ['large-4.7', '--from=si 6T', {OUT =>"6000000000000"}], 899 ['large-4.8', '--from=si 70T', {OUT =>"70000000000000"}], 900 ['large-4.9', '--from=si 800T', {OUT =>"800000000000000"}], 901 ['large-4.10','--from=si 9P', {OUT =>"9000000000000000"}], 902 ['large-4.11','--from=si 10P', {OUT =>"10000000000000000"}], 903 ['large-4.12','--from=si 200P', {OUT =>"200000000000000000"}], 904 ['large-4.13','--from=si 3E', {OUT =>"3000000000000000000"}], 905 906 # More than 18 digits of output without scaling - no good. 907 ['large-4.14','--from=si 40E', 908 {ERR => "$prog: value too large to be printed: '4e+19' " . 909 "(consider using --to)\n"}, 910 {EXIT => 2}], 911 ['large-4.15','--from=si 500E', 912 {ERR => "$prog: value too large to be printed: '5e+20' " . 913 "(consider using --to)\n"}, 914 {EXIT => 2}], 915 ['large-4.16','--from=si 6Z', 916 {ERR => "$prog: value too large to be printed: '6e+21' " . 917 "(consider using --to)\n"}, 918 {EXIT => 2}], 919 ['large-4.17','--from=si 70Z', 920 {ERR => "$prog: value too large to be printed: '7e+22' " . 921 "(consider using --to)\n"}, 922 {EXIT => 2}], 923 ['large-4.18','--from=si 800Z', 924 {ERR => "$prog: value too large to be printed: '8e+23' " . 925 "(consider using --to)\n"}, 926 {EXIT => 2}], 927 ['large-4.19','--from=si 9Y', 928 {ERR => "$prog: value too large to be printed: '9e+24' " . 929 "(consider using --to)\n"}, 930 {EXIT => 2}], 931 ['large-4.20','--from=si 10Y', 932 {ERR => "$prog: value too large to be printed: '1e+25' " . 933 "(consider using --to)\n"}, 934 {EXIT => 2}], 935 ['large-4.21','--from=si 200Y', 936 {ERR => "$prog: value too large to be printed: '2e+26' " . 937 "(consider using --to)\n"}, 938 {EXIT => 2}], 939 940 ['large-5.1','--to=si 1000000000000000000', {OUT=>"1.0E"}], 941 ['large-5','--from=si --to=si 2E', {OUT=>"2.0E"}], 942 ['large-6','--from=si --to=si 3.4Z', {OUT=>"3.4Z"}], 943 ['large-7','--from=si --to=si 80Y', {OUT=>"80Y"}], 944 ['large-8','--from=si --to=si 9000Z', {OUT=>"9.0Y"}], 945 946 ['large-10','--from=si --to=si 999Q', {OUT=>"999Q"}], 947 ['large-11','--from=si --to=iec 999Q', {OUT=>"789Q"}], 948 ['large-12','--from=si --round=down --to=iec 999Q', {OUT=>"788Q"}], 949 950 # units can also affect the output 951 ['large-13','--from=si --from-unit=1000000 9P', 952 {ERR => "$prog: value too large to be printed: '9e+21' " . 953 "(consider using --to)\n"}, 954 {EXIT => 2}], 955 ['large-13.1','--from=si --from-unit=1000000 --to=si 9P', {OUT=>"9.0Z"}], 956 957 # Numbers>999Q are never acceptable, regardless of scaling 958 ['large-14','--from=si --to=si 999Q', {OUT=>"999Q"}], 959 ['large-14.1','--from=si --to=si 1000Q', 960 {ERR => "$prog: value too large to be printed: '1e+33' " . 961 "(cannot handle values > 999Q)\n"}, 962 {EXIT => 2}], 963 ['large-14.2','--from=si --to=si --from-unit=10000 1Q', 964 {ERR => "$prog: value too large to be printed: '1e+34' " . 965 "(cannot handle values > 999Q)\n"}, 966 {EXIT => 2}], 967 968 # intmax_t overflow when rounding caused this to fail before 8.24 969 ['large-15',$limits->{INTMAX_OFLOW}, {OUT=>$limits->{INTMAX_OFLOW}}], 970 ['large-16','9.300000000000000000', {OUT=>'9.300000000000000000'}], 971 972 # INTEGRAL_OVERFLOW 973 ['strtod-3', '--from=si "1234567890123456789012345678901234567890'. 974 '1234567890123456789012345678901234567890"', 975 {ERR=>"$prog: value too large to be converted: '" . 976 "1234567890123456789012345678901234567890" . 977 "1234567890123456789012345678901234567890'\n", 978 }, 979 {EXIT=> 2}], 980 981 # FRACTION_OVERFLOW 982 ['strtod-7', '--from=si "12.1234567890123456789012345678901234567890'. 983 '1234567890123456789012345678901234567890"', 984 {ERR=>"$prog: value too large to be converted: '" . 985 "12.1234567890123456789012345678901234567890" . 986 "1234567890123456789012345678901234567890'\n", 987 }, 988 {EXIT=> 2}], 989 990 ['debug-4', '--to=si --debug 12345678901234567890', 991 {OUT=>"13E"}, 992 {ERR=>"$prog: large input value '12345678901234567890':" . 993 " possible precision loss\n"}], 994 ['debug-5', '--to=si --from=si --debug 1.12345678901234567890Y', 995 {OUT=>"1.2Y"}, 996 {ERR=>"$prog: large input value '1.12345678901234567890Y':" . 997 " possible precision loss\n"}], 998 999 ['ign-err-10','--invalid=fail 10000000000000000000', 1000 {ERR => "$prog: value too large to be printed: '1e+19' " . 1001 "(consider using --to)\n"}, 1002 {OUT => "10000000000000000000\n"}, 1003 {EXIT=>2}], 1004 ['ign-err-11','--invalid=fail --to=si 6543219876543210000000000000000000', 1005 {ERR => "$prog: value too large to be converted: " . 1006 "'6543219876543210000000000000000000'\n"}, 1007 {OUT => "6543219876543210000000000000000000\n"}, 1008 {EXIT => 2}], 1009 ); 1010# Restrict these tests to systems with LDBL_DIG == 18 1011(system "$prog ---debug 1 2>&1|grep 'MAX_UNSCALED_DIGITS: 18' > /dev/null") == 0 1012 and push @Tests, @Limit_Tests; 1013 1014my @Locale_Tests = 1015 ( 1016 # Locale that supports grouping, but without '--grouping' parameter 1017 ['lcl-grp-1', '--from=si 7M', {OUT=>"7000000"}, 1018 {ENV=>"LC_ALL=$locale"}], 1019 1020 # Locale with grouping 1021 ['lcl-grp-2', '--from=si --grouping 7M', {OUT=>"7 000 000"}, 1022 {ENV=>"LC_ALL=$locale"}], 1023 1024 # Locale with grouping and debug - no debug warning message 1025 ['lcl-grp-3', '--from=si --debug --grouping 7M', {OUT=>"7 000 000"}, 1026 {ENV=>"LC_ALL=$locale"}], 1027 1028 # Input with locale'd decimal-point 1029 ['lcl-stdtod-1', '--from=si 12,2K', {OUT=>"12200"}, 1030 {ENV=>"LC_ALL=$locale"}], 1031 1032 ['lcl-dbl-to-human-1', '--to=si 1100', {OUT=>"1,1K"}, 1033 {ENV=>"LC_ALL=$locale"}], 1034 1035 # Format + Grouping 1036 ['lcl-fmt-1', '--format "%\'f" 50000',{OUT=>"50 000"}, 1037 {ENV=>"LC_ALL=$locale"}], 1038 ['lcl-fmt-2', '--format "--%\'10f--" 50000', {OUT=>"-- 50 000--"}, 1039 {ENV=>"LC_ALL=$locale"}], 1040 ['lcl-fmt-3', '--format "--%\'-10f--" 50000',{OUT=>"--50 000 --"}, 1041 {ENV=>"LC_ALL=$locale"}], 1042 ['lcl-fmt-4', '--format "--%-10f--" --to=si 5000000', 1043 {OUT=>"--5,0M --"}, 1044 {ENV=>"LC_ALL=$locale"}], 1045 # handle zero/grouping in combination 1046 ['lcl-fmt-5', '--format="%\'06f" 1234',{OUT=>"01 234"}, 1047 {ENV=>"LC_ALL=$locale"}], 1048 ['lcl-fmt-6', '--format="%0\'6f" 1234',{OUT=>"01 234"}, 1049 {ENV=>"LC_ALL=$locale"}], 1050 ['lcl-fmt-7', '--format="%0\'\'6f" 1234',{OUT=>"01 234"}, 1051 {ENV=>"LC_ALL=$locale"}], 1052 1053 ); 1054if ($locale ne 'C') 1055 { 1056 # Reset locale to 'C' if LOCALE_FR_UTF8 doesn't output as expected 1057 # as determined by the separate printf program. 1058 open(LOC_NUM, "env LC_ALL=$locale printf \"%'d\" 1234|") 1059 or die "Can't fork command: $!"; 1060 my $loc_num = <LOC_NUM>; 1061 close(LOC_NUM) || die "Failed to read grouped number from printf"; 1062 if ($loc_num ne '1 234') 1063 { 1064 warn "skipping locale grouping tests as 1234 groups like $loc_num\n"; 1065 $locale = 'C'; 1066 } 1067 } 1068push @Tests, @Locale_Tests if $locale ne 'C'; 1069 1070## Check all valid/invalid suffixes 1071foreach my $suf ( 'A' .. 'Z', 'a' .. 'z' ) { 1072 if ( $suf =~ /^[KMGTPEZYRQ]$/ ) 1073 { 1074 push @Tests, ["auto-suf-si-$suf","--from=si --to=si 1$suf", 1075 {OUT=>"1.0$suf"}]; 1076 push @Tests, ["auto-suf-iec-$suf","--from=iec --to=iec 1$suf", 1077 {OUT=>"1.0$suf"}]; 1078 push @Tests, ["auto-suf-auto-$suf","--from=auto --to=iec 1${suf}i", 1079 {OUT=>"1.0$suf"}]; 1080 push @Tests, ["auto-suf-iec-to-ieci-$suf","--from=iec --to=iec-i 1${suf}", 1081 {OUT=>"1.0${suf}i"}]; 1082 push @Tests, ["auto-suf-ieci-to-iec-$suf", 1083 "--from=iec-i --to=iec 1${suf}i",{OUT=>"1.0${suf}"}]; 1084 } 1085 else 1086 { 1087 push @Tests, ["auto-suf-si-$suf","--from=si --to=si 1$suf", 1088 {ERR=>"$prog: invalid suffix in input: '1${suf}'\n"}, 1089 {EXIT=>2}]; 1090 } 1091} 1092 1093# Prepend the command line argument and append a newline to end 1094# of each expected 'OUT' string. 1095my $t; 1096 1097Test: 1098foreach $t (@Tests) 1099 { 1100 # Don't fiddle with expected OUT string if there's a nonzero exit status. 1101 foreach my $e (@$t) 1102 { 1103 ref $e eq 'HASH' && exists $e->{EXIT} && $e->{EXIT} 1104 and next Test; 1105 } 1106 1107 foreach my $e (@$t) 1108 { 1109 ref $e eq 'HASH' && exists $e->{OUT} 1110 and $e->{OUT} .= "\n" 1111 } 1112 } 1113 1114# Add test for null-terminated lines (after adjusting the OUT string, above). 1115push @Tests, @NullDelim_Tests; 1116 1117my $save_temps = $ENV{SAVE_TEMPS}; 1118my $verbose = $ENV{VERBOSE}; 1119 1120my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose); 1121exit $fail; 1122