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