mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-07-01 10:21:45 +03:00
numfmt: a new command to format numbers
* AUTHORS: Add my name. * NEWS: Mention the new program. * README: Reference the new program. * src/numfmt.c: New file. * src/.gitignore: Ignore the new binary. * build-aux/gen-lists-of-programs.sh: Update. * scripts/git-hooks/commit-msg: Allow numfmt: commit prefix. * po/POTFILES.in: Add new c file. * tests/misc/numfmt.pl: A new test file giving >93% coverage. * tests/local.mk: Reference the new test. * man/.gitignore: Ignore the new man page. * man/local.mk: Reference the new man page. * man/numfmt.x: A new template. * doc/coreutils.texi: Document the new command.
This commit is contained in:
committed by
Pádraig Brady
parent
be7932e863
commit
8a303a8963
1
AUTHORS
1
AUTHORS
@ -52,6 +52,7 @@ nice: David MacKenzie
|
||||
nl: Scott Bartram, David MacKenzie
|
||||
nohup: Jim Meyering
|
||||
nproc: Giuseppe Scrivano
|
||||
numfmt: Assaf Gordon
|
||||
od: Jim Meyering
|
||||
paste: David M. Ihnat, David MacKenzie
|
||||
pathchk: Paul Eggert, David MacKenzie, Jim Meyering
|
||||
|
4
NEWS
4
NEWS
@ -2,6 +2,10 @@ GNU coreutils NEWS -*- outline -*-
|
||||
|
||||
* Noteworthy changes in release ?.? (????-??-??) [?]
|
||||
|
||||
** New programs
|
||||
|
||||
numfmt: reformat numbers
|
||||
|
||||
** New features
|
||||
|
||||
df now accepts the --output[=FIELD_LIST] option to define the list of columns
|
||||
|
6
README
6
README
@ -11,9 +11,9 @@ The programs that can be built with this package are:
|
||||
csplit cut date dd df dir dircolors dirname du echo env expand expr
|
||||
factor false fmt fold groups head hostid hostname id install join kill
|
||||
link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl nohup
|
||||
nproc od paste pathchk pinky pr printenv printf ptx pwd readlink realpath
|
||||
rm rmdir runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum shred
|
||||
shuf sleep sort split stat stdbuf stty sum sync tac tail tee test
|
||||
nproc numfmt od paste pathchk pinky pr printenv printf ptx pwd readlink
|
||||
realpath rm rmdir runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum
|
||||
shred shuf sleep sort split stat stdbuf stty sum sync tac tail tee test
|
||||
timeout touch tr true truncate tsort tty uname unexpand uniq unlink
|
||||
uptime users vdir wc who whoami yes
|
||||
|
||||
|
@ -85,6 +85,7 @@ normal_progs='
|
||||
nl
|
||||
nproc
|
||||
nohup
|
||||
numfmt
|
||||
od
|
||||
paste
|
||||
pathchk
|
||||
|
@ -85,6 +85,7 @@
|
||||
* nl: (coreutils)nl invocation. Number lines and write files.
|
||||
* nohup: (coreutils)nohup invocation. Immunize to hangups.
|
||||
* nproc: (coreutils)nproc invocation. Print the number of processors.
|
||||
* numfmt: (coreutils)numfmt invocation. Reformat numbers.
|
||||
* od: (coreutils)od invocation. Dump files in octal, etc.
|
||||
* paste: (coreutils)paste invocation. Merge lines of files.
|
||||
* pathchk: (coreutils)pathchk invocation. Check file name portability.
|
||||
@ -238,9 +239,12 @@ Output of entire files
|
||||
Formatting file contents
|
||||
|
||||
* fmt invocation:: Reformat paragraph text
|
||||
* numfmt invocation:: Reformat numbers
|
||||
* pr invocation:: Paginate or columnate files for printing
|
||||
* fold invocation:: Wrap input lines to fit in specified width
|
||||
|
||||
@command{numfmt}: General Options, Units
|
||||
|
||||
Output of parts of files
|
||||
|
||||
* head invocation:: Output the first part of files
|
||||
@ -764,8 +768,8 @@ other exit status values and a few associate different
|
||||
meanings with the values @samp{0} and @samp{1}.
|
||||
Here are some of the exceptions:
|
||||
@command{chroot}, @command{env}, @command{expr}, @command{nice},
|
||||
@command{nohup}, @command{printenv}, @command{sort}, @command{stdbuf},
|
||||
@command{test}, @command{timeout}, @command{tty}.
|
||||
@command{nohup}, @command{numfmt}, @command{printenv}, @command{sort},
|
||||
@command{stdbuf}, @command{test}, @command{timeout}, @command{tty}.
|
||||
|
||||
|
||||
@node Backup options
|
||||
@ -2122,6 +2126,7 @@ These commands reformat the contents of files.
|
||||
|
||||
@menu
|
||||
* fmt invocation:: Reformat paragraph text.
|
||||
* numfmt invocation:: Reformat numbers.
|
||||
* pr invocation:: Paginate or columnate files for printing.
|
||||
* fold invocation:: Wrap input lines to fit in specified width.
|
||||
@end menu
|
||||
@ -2231,6 +2236,325 @@ leaving the code unchanged.
|
||||
|
||||
@exitstatus
|
||||
|
||||
@node numfmt invocation
|
||||
@section @command{numfmt}: Reformat numbers
|
||||
|
||||
@pindex numfmt
|
||||
|
||||
@command{numfmt} reads numbers in various representations and reformats them
|
||||
as requested. The most common usage is converting numbers to/from @emph{human}
|
||||
representation (e.g. @samp{4G} @expansion{} @samp{4,000,000,000}).
|
||||
|
||||
@example
|
||||
numfmt [@var{option}]@dots{} [@var{number}]
|
||||
@end example
|
||||
|
||||
@command{numfmt} converts each @var{number} on the command-line according to the
|
||||
specified options (see below). If no @var{number}s are given, it reads numbers
|
||||
from standard input. @command{numfmt} can optionally extract numbers from
|
||||
specific columns, maintaining proper line padding and alignment.
|
||||
|
||||
@exitstatus
|
||||
|
||||
See @option{--invalid} for additional information regarding exit status.
|
||||
|
||||
@subsection General options
|
||||
|
||||
The program accepts the following options. Also see @ref{Common options}.
|
||||
|
||||
@table @samp
|
||||
|
||||
@item --from=@var{unit}
|
||||
@opindex --from
|
||||
Auto-scales input numbers according to @var{unit}. See @emph{Units} below.
|
||||
The default is no scaling, meaning suffixes (e.g. @samp{M}, @samp{G}) will
|
||||
trigger an error.
|
||||
|
||||
@item --from-unit=@var{n}
|
||||
@opindex --from-unit
|
||||
Specify the input unit size (instead of the default 1). Use this option when the
|
||||
input numbers represent other units (e.g. if the input number @samp{10}
|
||||
represents 10 units of 512 bytes, use @samp{--from=unit=512}).
|
||||
|
||||
@item --to=@var{unit}
|
||||
@opindex --to
|
||||
Auto-scales output numbers according to @var{unit}. See @emph{Units} below.
|
||||
The default is no scaling, meaning all the digits of the number are printed.
|
||||
|
||||
@item --to-unit=@var{n}
|
||||
@opindex --to-unit
|
||||
Specify the output unit size (instead of the default 1). Use this option when
|
||||
the output numbers represent other units (e.g. to represent @samp{4,000,000}
|
||||
bytes in blocks of 1KB, use @samp{--to=si --to=units=1000}).
|
||||
|
||||
@item --round=@var{method}
|
||||
@opindex --round
|
||||
@opindex --round=up
|
||||
@opindex --round=down
|
||||
@opindex --round=from-zero
|
||||
@opindex --round=towards-zero
|
||||
@opindex --round=nearest
|
||||
When converting number representations, round the number according to
|
||||
@var{method}, which can be @samp{up}, @samp{down},
|
||||
@samp{from-zero} (the default), @samp{towards-zero}, @samp{nearest}.
|
||||
|
||||
@item --suffix=@var{suffix}
|
||||
@opindex --suffix
|
||||
Add @samp{SUFFIX} to the output numbers, and accept optional @samp{SUFFIX} in
|
||||
input numbers.
|
||||
|
||||
@item --padding=@var{n}
|
||||
@opindex --padding
|
||||
Pad the output numbers to @var{n} characters, by adding spaces. If @var{n} is
|
||||
a positive number, numbers will be right-aligned. If @var{n} is a negative
|
||||
number, numbers will be left-aligned. By default, numbers are automatically
|
||||
aligned based on the input line's width (only with the default delimiter).
|
||||
|
||||
@item --grouping
|
||||
@opindex --grouping
|
||||
Group digits in output numbers according to the current locale's grouping rules
|
||||
(e.g @emph{Thousands Separator} character, commonly @samp{.} (dot) or @samp{,}
|
||||
comma). This option has no effect in @samp{POSIX/C} locale.
|
||||
|
||||
@item --header[=@var{n}]
|
||||
@opindex --header
|
||||
@opindex --header=N
|
||||
Print the first @var{n} (default: 1) lines without any conversion.
|
||||
|
||||
@item --field=@var{n}
|
||||
@opindex --field
|
||||
Convert the number in input field @var{n} (default: 1).
|
||||
|
||||
@item --format=@var{format}
|
||||
@opindex --format
|
||||
Use printf-style floating FORMAT string. The @var{format} string must contain
|
||||
one @samp{%f} directive, optionally with @samp{'}, @samp{-}, or width
|
||||
modifiers. @samp{'} modified will enable @option{--grouping}. @samp{-} modifier
|
||||
will enable left-aligned @option{--padding}. Width modifier will enable
|
||||
right-aligned @option{--padding}.
|
||||
|
||||
@item --invalid=@var{mode}
|
||||
@opindex --invalid
|
||||
The default action on input errors is to exit immediately with status code 2.
|
||||
@option{--invalid=@samp{abort}} explicitly specifies this default mode.
|
||||
With a @var{mode} of @samp{fail}, print a warning for @emph{each} conversion
|
||||
error, and exit with status 2. With a @var{mode} of @samp{warn}, exit with
|
||||
status 0, even in the presence of conversion errors, and with a @var{mode} of
|
||||
@samp{ignore} do not even print diagnostics.
|
||||
|
||||
@item -d @var{d}
|
||||
@itemx --delimiter=@var{d}
|
||||
@opindex -d
|
||||
@opindex --delimiter
|
||||
Use the character @var{d} as input field separator (default: whitespace).
|
||||
@emph{Note}: Using non-default delimiter turns off automatic padding.
|
||||
|
||||
@item --debug
|
||||
@opindex --debug
|
||||
Print (to standard error) warning messages about possible erroneous usage.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Possible @var{unit}s:
|
||||
|
||||
The following are the possible @var{unit} options with @option{--from=UNITS} and
|
||||
@option{--to=UNITS}:
|
||||
|
||||
@table @var
|
||||
|
||||
@item none
|
||||
No scaling is performed. For input numbers, no suffixes are accepted, and any
|
||||
trailing characters following the number will trigger an error. For output
|
||||
numbers, all digits of the numbers will be printed.
|
||||
|
||||
@item si
|
||||
Auto-scale numbers according to the @emph{International System of Units (SI)}
|
||||
standard.
|
||||
For input numbers, accept one of the following suffixes.
|
||||
For output numbers, values larger than 1000 will be rounded, and printed with
|
||||
one of the following suffixes:
|
||||
|
||||
@example
|
||||
@samp{K} => @math{1000^1 = 10^3} (Kilo)
|
||||
@samp{M} => @math{1000^2 = 10^6} (Mega)
|
||||
@samp{G} => @math{1000^3 = 10^9} (Giga)
|
||||
@samp{T} => @math{1000^4 = 10^{12}} (Tera)
|
||||
@samp{P} => @math{1000^5 = 10^{15}} (Peta)
|
||||
@samp{E} => @math{1000^6 = 10^{18}} (Exa)
|
||||
@samp{Z} => @math{1000^7 = 10^{21}} (Zetta)
|
||||
@samp{Y} => @math{1000^8 = 10^{24}} (Yotta)
|
||||
@end example
|
||||
|
||||
@item iec
|
||||
Auto-scale numbers according to the @emph{International Electronical
|
||||
Commission (IEC)} standard.
|
||||
For input numbers, accept one of the following suffixes.
|
||||
For output numbers, values larger than 1024 will be rounded, and printed with
|
||||
one of the following suffixes:
|
||||
|
||||
@example
|
||||
@samp{K} => @math{1024^1 = 2^{10}} (Kibi)
|
||||
@samp{M} => @math{1024^2 = 2^{20}} (Mebi)
|
||||
@samp{G} => @math{1024^3 = 2^{30}} (Gibi)
|
||||
@samp{T} => @math{1024^4 = 2^{40}} (Tebi)
|
||||
@samp{P} => @math{1024^5 = 2^{50}} (Pebi)
|
||||
@samp{E} => @math{1024^6 = 2^{60}} (Exbi)
|
||||
@samp{Z} => @math{1024^7 = 2^{70}} (Zebi)
|
||||
@samp{Y} => @math{1024^8 = 2^{80}} (Yobi)
|
||||
@end example
|
||||
|
||||
The @option{iec} option uses a single letter suffix (e.g. @samp{G}), which is
|
||||
not fully standard, as the @emph{iec} standard recommends a two-letter symbol
|
||||
(e.g @samp{Gi}) - but in practice, this method common. Compare with
|
||||
the @option{iec-i} option.
|
||||
|
||||
@item iec-i
|
||||
Auto-scale numbers according to the @emph{International Electronical
|
||||
Commission (IEC)} standard.
|
||||
For input numbers, accept one of the following suffixes.
|
||||
For output numbers, values larger than 1024 will be rounded, and printed with
|
||||
one of the following suffixes:
|
||||
|
||||
@example
|
||||
@samp{Ki} => @math{1024^1 = 2^{10}} (Kibi)
|
||||
@samp{Mi} => @math{1024^2 = 2^{20}} (Mebi)
|
||||
@samp{Gi} => @math{1024^3 = 2^{30}} (Gibi)
|
||||
@samp{Ti} => @math{1024^4 = 2^{40}} (Tebi)
|
||||
@samp{Pi} => @math{1024^5 = 2^{50}} (Pebi)
|
||||
@samp{Ei} => @math{1024^6 = 2^{60}} (Exbi)
|
||||
@samp{Zi} => @math{1024^7 = 2^{70}} (Zebi)
|
||||
@samp{Yi} => @math{1024^8 = 2^{80}} (Yobi)
|
||||
@end example
|
||||
|
||||
The @option{iec-i} option uses a two-letter suffix symbol (e.g. @samp{Gi}),
|
||||
as the @emph{iec} standard recommends, but this is not always common in
|
||||
practice. Compare with the @option{iec} option.
|
||||
|
||||
@item auto
|
||||
@samp{auto} can only be used with @option{--from}. With this method, numbers
|
||||
with @samp{K},@samp{M},@samp{G},@samp{T},@samp{P},@samp{E},@samp{Z},@samp{Y}
|
||||
suffixes are interpreted as @emph{SI} values, and numbers with @samp{Ki},
|
||||
@samp{Mi},@samp{Gi},@samp{Ti},@samp{Pi},@samp{Ei},@samp{Zi},@samp{Yi} suffixes
|
||||
are interpreted as @emph{IEC} values.
|
||||
|
||||
@end table
|
||||
|
||||
@subsection Examples of using @command{numfmt}
|
||||
|
||||
Converting a single number from/to @emph{human} representation:
|
||||
@example
|
||||
$ nunfmt --to=si 500000
|
||||
500K
|
||||
|
||||
$ numfmt --to=iec 500000
|
||||
489K
|
||||
|
||||
$ numfmt --to=iec-i 500000
|
||||
489Ki
|
||||
|
||||
$ numfmt --from=si 1M
|
||||
1000000
|
||||
|
||||
$ numfmt --from=iec 1M
|
||||
1048576
|
||||
|
||||
# with '--from=auto', M=Mega, Mi=Mebi
|
||||
$ numfmt --from=auto 1M
|
||||
1000000
|
||||
$ numfmt --from=auto 1Mi
|
||||
1048576
|
||||
@end example
|
||||
|
||||
Converting from @samp{SI} to @samp{IEC} scales (e.g. when a harddisk capacity is
|
||||
advertised as @samp{1TB}, while checking the drive's capacity gives lower
|
||||
values):
|
||||
|
||||
@example
|
||||
$ numfmt --from=si --to=iec 1T
|
||||
932G
|
||||
@end example
|
||||
|
||||
|
||||
Converting a single field from an input file / piped input (these contrived
|
||||
examples are for demonstration purposes only, as both @command{ls} and
|
||||
@command{df} support the @option{--human-readable} option to
|
||||
output sizes in human-readable format):
|
||||
|
||||
@example
|
||||
# Third field (file size) will be shown in SI representation
|
||||
$ ls -log | numfmt --field 3 --header --to=si | head -n4
|
||||
-rw-r--r-- 1 94K Aug 23 2011 ABOUT-NLS
|
||||
-rw-r--r-- 1 3.7K Jan 7 16:15 AUTHORS
|
||||
-rw-r--r-- 1 36K Jun 1 2011 COPYING
|
||||
-rw-r--r-- 1 0 Jan 7 15:15 ChangeLog
|
||||
|
||||
# Second field (size) will be shown in IEC representation
|
||||
$ df --block-size=1 | numfmt --field 2 --header --to=iec | head -n4
|
||||
File system 1B-blocks Used Available Use% Mounted on
|
||||
rootfs 132G 104741408 26554036 80% /
|
||||
tmpfs 794M 7580 804960 1% /run/shm
|
||||
/dev/sdb1 694G 651424756 46074696 94% /home
|
||||
@end example
|
||||
|
||||
|
||||
Output can be tweaked using @option{--padding} or @option{--format}:
|
||||
|
||||
@example
|
||||
# Pad to 10 characters, right-aligned
|
||||
$ du -s * | numfmt --to=si --padding=10
|
||||
2.5K config.log
|
||||
108 config.status
|
||||
1.7K configure
|
||||
20 configure.ac
|
||||
|
||||
# Pad to 10 characters, left-aligned
|
||||
$ du -s * | numfmt --to=si --padding=-10
|
||||
2.5K config.log
|
||||
108 config.status
|
||||
1.7K configure
|
||||
20 configure.ac
|
||||
|
||||
# Pad to 10 characters, left-aligned, using 'format'
|
||||
$ du -s * | numfmt --to=si --format="%10f"
|
||||
2.5K config.log
|
||||
108 config.status
|
||||
1.7K configure
|
||||
20 configure.ac
|
||||
|
||||
# Pad to 10 characters, left-aligned, using 'format'
|
||||
$ du -s * | numfmt --to=si --padding="%-10f"
|
||||
2.5K config.log
|
||||
108 config.status
|
||||
1.7K configure
|
||||
20 configure.ac
|
||||
@end example
|
||||
|
||||
With locales that support grouping digits, using @option{--grouping} or
|
||||
@option{--format} enables grouping. In @samp{POSIX} locale, grouping is silently
|
||||
ignored:
|
||||
|
||||
@example
|
||||
$ LC_ALL=C numfmt --from=iec --grouping 2G
|
||||
2147483648
|
||||
|
||||
$ LC_ALL=en_US.utf8 numfmt --from=iec --grouping 2G
|
||||
2,147,483,648
|
||||
|
||||
$ LC_ALL=ta_IN numfmt --from=iec --grouping 2G
|
||||
2,14,74,83,648
|
||||
|
||||
$ LC_ALL=C ./src/numfmt --from=iec --format="==%'15f==" 2G
|
||||
== 2147483648==
|
||||
|
||||
$ LC_ALL=en_US.utf8 ./src/numfmt --from=iec --format="==%'15f==" 2G
|
||||
== 2,147,483,648==
|
||||
|
||||
$ LC_ALL=en_US.utf8 ./src/numfmt --from=iec --format="==%'-15f==" 2G
|
||||
==2,147,483,648 ==
|
||||
|
||||
$ LC_ALL=ta_IN ./src/numfmt --from=iec --format="==%'15f==" 2G
|
||||
== 2,14,74,83,648==
|
||||
@end example
|
||||
|
||||
@node pr invocation
|
||||
@section @command{pr}: Paginate or columnate files for printing
|
||||
|
1
man/.gitignore
vendored
1
man/.gitignore
vendored
@ -49,6 +49,7 @@ nice.1
|
||||
nl.1
|
||||
nohup.1
|
||||
nproc.1
|
||||
numfmt.1
|
||||
od.1
|
||||
paste.1
|
||||
pathchk.1
|
||||
|
@ -115,6 +115,7 @@ man/nice.1: src/nice
|
||||
man/nl.1: src/nl
|
||||
man/nohup.1: src/nohup
|
||||
man/nproc.1: src/nproc
|
||||
man/numfmt.1: src/numfmt
|
||||
man/od.1: src/od
|
||||
man/paste.1: src/paste
|
||||
man/pathchk.1: src/pathchk
|
||||
|
4
man/numfmt.x
Normal file
4
man/numfmt.x
Normal file
@ -0,0 +1,4 @@
|
||||
[NAME]
|
||||
numfmt \- Convert numbers from/to human-readable strings
|
||||
[DESCRIPTION]
|
||||
.\" Add any additional description here
|
@ -91,6 +91,7 @@ src/nice.c
|
||||
src/nl.c
|
||||
src/nohup.c
|
||||
src/nproc.c
|
||||
src/numfmt.c
|
||||
src/od.c
|
||||
src/operand2sig.c
|
||||
src/paste.c
|
||||
|
@ -16,7 +16,7 @@ my @valid = qw(
|
||||
cp csplit cut date dd df dir dircolors dirname du echo env expand
|
||||
expr factor false fmt fold groups head hostid hostname id install
|
||||
join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp
|
||||
mv nice nl nohup nproc od paste pathchk pinky pr printenv printf
|
||||
mv nice nl nohup nproc numfmt od paste pathchk pinky pr printenv printf
|
||||
ptx pwd readlink realpath rm rmdir runcon seq sha1sum sha224sum sha256sum
|
||||
sha384sum sha512sum shred shuf sleep sort split stat stdbuf stty
|
||||
sum sync tac tail tee test timeout touch tr true truncate tsort
|
||||
|
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@ -59,6 +59,7 @@ nice
|
||||
nl
|
||||
nohup
|
||||
nproc
|
||||
numfmt
|
||||
od
|
||||
paste
|
||||
pathchk
|
||||
|
1522
src/numfmt.c
Normal file
1522
src/numfmt.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -288,6 +288,7 @@ all_tests = \
|
||||
tests/misc/nohup.sh \
|
||||
tests/misc/nproc-avail.sh \
|
||||
tests/misc/nproc-positive.sh \
|
||||
tests/misc/numfmt.pl \
|
||||
tests/misc/od-N.sh \
|
||||
tests/misc/od-multiple-t.sh \
|
||||
tests/misc/od-x8.sh \
|
||||
|
936
tests/misc/numfmt.pl
Normal file
936
tests/misc/numfmt.pl
Normal file
@ -0,0 +1,936 @@
|
||||
#!/usr/bin/perl
|
||||
# Basic tests for "numfmt".
|
||||
|
||||
# Copyright (C) 2012 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use strict;
|
||||
|
||||
(my $program_name = $0) =~ s|.*/||;
|
||||
my $prog = 'numfmt';
|
||||
|
||||
# TODO: add localization tests with "grouping"
|
||||
# Turn off localization of executable's output.
|
||||
@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
|
||||
|
||||
my $locale = $ENV{LOCALE_FR_UTF8};
|
||||
! defined $locale || $locale eq 'none'
|
||||
and $locale = 'C';
|
||||
|
||||
my @Tests =
|
||||
(
|
||||
['1', '1234', {OUT => "1234"}],
|
||||
['2', '--from=si 1K', {OUT => "1000"}],
|
||||
['3', '--from=iec 1K', {OUT => "1024"}],
|
||||
['4', '--from=auto 1K', {OUT => "1000"}],
|
||||
['5', '--from=auto 1Ki', {OUT => "1024"}],
|
||||
['5.1', '--from=iec-i 1Ki', {OUT => "1024"}],
|
||||
|
||||
['6', {IN_PIPE => "1234\n"}, {OUT => "1234"}],
|
||||
['7', '--from=si', {IN_PIPE => "2K\n"}, {OUT => "2000"}],
|
||||
['7a', '--invalid=fail', {IN_PIPE => "no_NL"}, {OUT => "no_NL"},
|
||||
{ERR => "$prog: invalid number: 'no_NL'\n"},
|
||||
{EXIT => '2'}],
|
||||
|
||||
['8', '--to=si 2000', {OUT => "2.0K"}],
|
||||
['9', '--to=si 2001', {OUT => "2.1K"}],
|
||||
['10', '--to=si 1999', {OUT => "2.0K"}],
|
||||
['11', '--to=si --round=down 2001', {OUT => "2.0K"}],
|
||||
['12', '--to=si --round=down 1999', {OUT => "1.9K"}],
|
||||
['13', '--to=si --round=up 1901', {OUT => "2.0K"}],
|
||||
['14', '--to=si --round=down 1901', {OUT => "1.9K"}],
|
||||
['15', '--to=si --round=nearest 1901', {OUT => "1.9K"}],
|
||||
['16', '--to=si --round=nearest 1945', {OUT => "1.9K"}],
|
||||
['17', '--to=si --round=nearest 1955', {OUT => "2.0K"}],
|
||||
|
||||
['18', '--to=iec 2048', {OUT => "2.0K"}],
|
||||
['19', '--to=iec 2049', {OUT => "2.1K"}],
|
||||
['20', '--to=iec 2047', {OUT => "2.0K"}],
|
||||
['21', '--to=iec --round=down 2049', {OUT => "2.0K"}],
|
||||
['22', '--to=iec --round=down 2047', {OUT => "1.9K"}],
|
||||
['23', '--to=iec --round=up 2040', {OUT => "2.0K"}],
|
||||
['24', '--to=iec --round=down 2040', {OUT => "1.9K"}],
|
||||
['25', '--to=iec --round=nearest 1996', {OUT => "1.9K"}],
|
||||
['26', '--to=iec --round=nearest 1997', {OUT => "2.0K"}],
|
||||
['27', '--to=iec-i 2048', {OUT => "2.0Ki"}],
|
||||
|
||||
['neg-1', '-- -1234', {OUT => "-1234"}],
|
||||
['neg-2', '--padding=5 -- -1234', {OUT => "-1234"}],
|
||||
['neg-3', '--padding=6 -- -1234', {OUT => " -1234"}],
|
||||
['neg-4', '--to=iec -- 9100 -9100', {OUT => "8.9K\n-8.9K"}],
|
||||
['neg-5', '-- -0.1', {OUT => "-0.1"}],
|
||||
['neg-6', '-- -0', {OUT => "0"}],
|
||||
['neg-7', '-- -0.-1',
|
||||
{ERR => "$prog: invalid number: '-0.-1'\n"},
|
||||
{EXIT => '2'}],
|
||||
|
||||
['float-1', '1.1', {OUT => "1.1"}],
|
||||
['float-2', '1.22', {OUT => "1.22"}],
|
||||
['float-3', '1.22.',
|
||||
{ERR => "$prog: invalid suffix in input: '1.22.'\n"},
|
||||
{EXIT => '2'}],
|
||||
|
||||
['unit-1', '--from-unit=512 4', {OUT => "2048"}],
|
||||
['unit-2', '--to-unit=512 2048', {OUT => "4"}],
|
||||
['unit-3', '--from-unit=512 --from=si 4M', {OUT => "2048000000"}],
|
||||
['unit-4', '--from-unit=512 --from=iec --to=iec 4M', {OUT => "2.0G"}],
|
||||
['unit-5', '--from-unit=AA --from=iec --to=iec 4M',
|
||||
{ERR => "$prog: invalid unit size: 'AA'\n"},
|
||||
{EXIT => '1'}],
|
||||
['unit-6', '--from-unit=54W --from=iec --to=iec 4M',
|
||||
{ERR => "$prog: invalid unit size: '54W'\n"},
|
||||
{EXIT => '1'}],
|
||||
# Not fully documented.. "--{from,to}-unit" can accept IEC suffixes
|
||||
['unit-7', '--from-unit=2K --to=iec 30', {OUT=>"60K"}],
|
||||
['unit-8', '--from-unit=1234567890123456789012345 --to=iec 30',
|
||||
{ERR => "$prog: invalid unit size: '1234567890123456789012345'\n"},
|
||||
{EXIT => '1'}],
|
||||
['unit-9', '--from-unit=0 1',
|
||||
{ERR => "$prog: invalid unit size: '0'\n"},
|
||||
{EXIT => '1'}],
|
||||
['unit-10', '--to-unit=0 1',
|
||||
{ERR => "$prog: invalid unit size: '0'\n"},
|
||||
{EXIT => '1'}],
|
||||
|
||||
# Test Suffix logic
|
||||
['suf-1', '4000', {OUT=>'4000'}],
|
||||
['suf-2', '4Q',
|
||||
{ERR => "$prog: invalid suffix in input: '4Q'\n"},
|
||||
{EXIT => '2'}],
|
||||
['suf-2.1', '4M',
|
||||
{ERR => "$prog: rejecting suffix " .
|
||||
"in input: '4M' (consider using --from)\n"},
|
||||
{EXIT => '2'}],
|
||||
['suf-3', '--from=si 4M', {OUT=>'4000000'}],
|
||||
['suf-4', '--from=si 4Q',
|
||||
{ERR => "$prog: invalid suffix in input: '4Q'\n"},
|
||||
{EXIT => '2'}],
|
||||
['suf-5', '--from=si 4MQ',
|
||||
{ERR => "$prog: invalid suffix in input '4MQ': 'Q'\n"},
|
||||
{EXIT => '2'}],
|
||||
|
||||
['suf-6', '--from=iec 4M', {OUT=>'4194304'}],
|
||||
['suf-7', '--from=auto 4M', {OUT=>'4000000'}],
|
||||
['suf-8', '--from=auto 4Mi', {OUT=>'4194304'}],
|
||||
['suf-9', '--from=auto 4MiQ',
|
||||
{ERR => "$prog: invalid suffix in input '4MiQ': 'Q'\n"},
|
||||
{EXIT => '2'}],
|
||||
['suf-10', '--from=auto 4QiQ',
|
||||
{ERR => "$prog: invalid suffix in input: '4QiQ'\n"},
|
||||
{EXIT => '2'}],
|
||||
|
||||
# characters after a white space are OK - printed as-is
|
||||
['suf-11', '"4 M"', {OUT=>'4 M'}],
|
||||
|
||||
# Custom suffix
|
||||
['suf-12', '--suffix=Foo 70Foo', {OUT=>'70Foo'}],
|
||||
['suf-13', '--suffix=Foo 70', {OUT=>'70Foo'}],
|
||||
['suf-14', '--suffix=Foo --from=si 70K', {OUT=>'70000Foo'}],
|
||||
['suf-15', '--suffix=Foo --from=si 70KFoo', {OUT=>'70000Foo'}],
|
||||
['suf-16', '--suffix=Foo --to=si 7000Foo', {OUT=>'7.0KFoo'}],
|
||||
['suf-17', '--suffix=Foo --to=si 7000Bar',
|
||||
{ERR => "$prog: invalid suffix in input: '7000Bar'\n"},
|
||||
{EXIT => '2'}],
|
||||
['suf-18', '--suffix=Foo --to=si 7000FooF',
|
||||
{ERR => "$prog: invalid suffix in input: '7000FooF'\n"},
|
||||
{EXIT => '2'}],
|
||||
# space(s) between number and suffix. Note only field 1 is used
|
||||
# by default so specify the NUL delimiter to consider the whole "line".
|
||||
['suf-19', "-d '' --from=si '4.0 K'", {OUT => "4000"}],
|
||||
|
||||
## GROUPING
|
||||
|
||||
# "C" locale - no grouping (locale-specific tests, below)
|
||||
['grp-1', '--from=si --grouping 7M', {OUT=>'7000000'}],
|
||||
['grp-2', '--from=si --to=si --grouping 7M',
|
||||
{ERR => "$prog: grouping cannot be combined with --to\n"},
|
||||
{EXIT => '1'}],
|
||||
|
||||
|
||||
## Padding
|
||||
['pad-1', '--padding=10 5', {OUT=>' 5'}],
|
||||
['pad-2', '--padding=-10 5', {OUT=>'5 '}],
|
||||
['pad-3', '--padding=A 5',
|
||||
{ERR => "$prog: invalid padding value 'A'\n"},
|
||||
{EXIT => '1'}],
|
||||
['pad-3.1', '--padding=0 5',
|
||||
{ERR => "$prog: invalid padding value '0'\n"},
|
||||
{EXIT => '1'}],
|
||||
['pad-4', '--padding=10 --to=si 50000', {OUT=>' 50K'}],
|
||||
['pad-5', '--padding=-10 --to=si 50000', {OUT=>'50K '}],
|
||||
|
||||
# padding too narrow
|
||||
['pad-6', '--padding=2 --to=si 1000', {OUT=>'1.0K'}],
|
||||
|
||||
|
||||
# Padding + suffix
|
||||
['pad-7', '--padding=10 --suffix=foo --to=si 50000',
|
||||
{OUT=>' 50Kfoo'}],
|
||||
['pad-8', '--padding=-10 --suffix=foo --to=si 50000',
|
||||
{OUT=>'50Kfoo '}],
|
||||
|
||||
|
||||
# Delimiters
|
||||
['delim-1', '--delimiter=: --from=auto 40M:', {OUT=>'40000000:'}],
|
||||
['delim-2', '--delimiter="" --from=auto "40 M"',{OUT=>'40000000'}],
|
||||
['delim-3', '--delimiter=" " --from=auto "40M Foo"',{OUT=>'40000000 Foo'}],
|
||||
['delim-4', '--delimiter=: --from=auto 40M:60M', {OUT=>'40000000:60M'}],
|
||||
['delim-5', '-d: --field=2 --from=auto :40M:60M', {OUT=>':40000000:60M'}],
|
||||
['delim-6', '--delimiter=: --field 3 --from=auto 40M:60M',
|
||||
{EXIT=>2},
|
||||
{ERR=>"$prog: input line is too short, no numbers found " .
|
||||
"to convert in field 3\n"}],
|
||||
|
||||
#Fields
|
||||
['field-1', '--field A',
|
||||
{ERR => "$prog: invalid field value 'A'\n"},
|
||||
{EXIT => '1'}],
|
||||
['field-1.1', '--field -5',
|
||||
{ERR => "$prog: invalid field value '-5'\n"},
|
||||
{EXIT => '1'}],
|
||||
['field-2', '--field 2 --from=auto "Hello 40M World 90G"',
|
||||
{OUT=>'Hello 40000000 World 90G'}],
|
||||
['field-3', '--field 3 --from=auto "Hello 40M World 90G"',
|
||||
{ERR=>"$prog: invalid number: 'World'\n"},
|
||||
{EXIT => 2},],
|
||||
# Last field - no text after number
|
||||
['field-4', '--field 4 --from=auto "Hello 40M World 90G"',
|
||||
{OUT=>"Hello 40M World 90000000000"}],
|
||||
# Last field - a delimiter after the number
|
||||
['field-5', '--field 4 --from=auto "Hello 40M World 90G "',
|
||||
{OUT=>"Hello 40M World 90000000000 "}],
|
||||
|
||||
# Mix Fields + Delimiters
|
||||
['field-6', '--delimiter=: --field 2 --from=auto "Hello:40M:World:90G"',
|
||||
{OUT=>"Hello:40000000:World:90G"}],
|
||||
|
||||
# not enough fields
|
||||
['field-8', '--field 3 --to=si "Hello World"',
|
||||
{EXIT=>2},
|
||||
{ERR=>"$prog: input line is too short, no numbers found " .
|
||||
"to convert in field 3\n"}],
|
||||
|
||||
# Auto-consume white-space, setup auto-padding
|
||||
['whitespace-1', '--to=si --field 2 "A 500 B"', {OUT=>"A 500 B"}],
|
||||
['whitespace-2', '--to=si --field 2 "A 5000 B"', {OUT=>"A 5.0K B"}],
|
||||
['whitespace-3', '--to=si " 500"', {OUT=>" 500"}],
|
||||
['whitespace-4', '--to=si " 6500"', {OUT=>" 6.5K"}],
|
||||
# NOTE: auto-padding is not enabled if the value is on the first
|
||||
# field and there's no white-space before it.
|
||||
['whitespace-5', '--to=si "6000000"', {OUT=>"6.0M"}],
|
||||
# but if there is whitespace, assume auto-padding is desired.
|
||||
['whitespace-6', '--to=si " 6000000"', {OUT=>" 6.0M"}],
|
||||
|
||||
# auto-padding - lines have same padding-width
|
||||
# (padding_buffer will be alloc'd just once)
|
||||
['whitespace-7', '--to=si --field 2',
|
||||
{IN_PIPE=>"rootfs 100000\n" .
|
||||
"udevxx 2000000\n"},
|
||||
{OUT =>"rootfs 100K\n" .
|
||||
"udevxx 2.0M"}],
|
||||
# auto-padding - second line requires a
|
||||
# larger padding (padding-buffer needs to be realloc'd)
|
||||
['whitespace-8', '--to=si --field 2',
|
||||
{IN_PIPE=>"rootfs 100000\n" .
|
||||
"udev 20000000\n"},
|
||||
{OUT =>"rootfs 100K\n" .
|
||||
"udev 20M"}],
|
||||
|
||||
|
||||
# Corner-cases:
|
||||
# weird mix of identical suffix,delimiters
|
||||
# The priority is:
|
||||
# 1. delimiters (and fields) are parsed (in process_line()
|
||||
# 2. optional custom suffix is removed (in process_suffixed_number())
|
||||
# 3. Remaining suffixes must be valid SI/IEC (in human_xstrtol())
|
||||
|
||||
# custom suffix comes BEFORE SI/IEC suffix,
|
||||
# so these are 40 of "M", not 40,000,000.
|
||||
['mix-1', '--suffix=M --from=si 40M', {OUT=>"40M"}],
|
||||
|
||||
# These are fourty-million Ms .
|
||||
['mix-2', '--suffix=M --from=si 40MM', {OUT=>"40000000M"}],
|
||||
|
||||
['mix-3', '--suffix=M --from=auto 40MM', {OUT=>"40000000M"}],
|
||||
['mix-4', '--suffix=M --from=auto 40MiM', {OUT=>"41943040M"}],
|
||||
['mix-5', '--suffix=M --to=si --from=si 4MM', {OUT=>"4.0MM"}],
|
||||
|
||||
# This might be confusing to the user, but it's legit:
|
||||
# The M in the output is the custom suffix, not Mega.
|
||||
['mix-6', '--suffix=M 40', {OUT=>"40M"}],
|
||||
['mix-7', '--suffix=M 4000000', {OUT=>"4000000M"}],
|
||||
['mix-8', '--suffix=M --to=si 4000000', {OUT=>"4.0MM"}],
|
||||
|
||||
# The output 'M' is the custom suffix.
|
||||
['mix-10', '--delimiter=M --suffix=M 40', {OUT=>"40M"}],
|
||||
|
||||
# The INPUT 'M' is a delimiter (delimiters are top priority)
|
||||
# The output contains one M for custom suffix, and one 'M' delimiter.
|
||||
['mix-11', '--delimiter=M --suffix=M 40M', {OUT=>"40MM"}],
|
||||
|
||||
# Same as above, the "M" is NOT treated as a mega SI prefix,
|
||||
['mix-12', '--delimiter=M --from=si --suffix=M 40M', {OUT=>"40MM"}],
|
||||
|
||||
# The 'M' is treated as a delimiter, and so the input value is '4000'
|
||||
['mix-13', '--delimiter=M --to=si --from=auto 4000M5000M9000',
|
||||
{OUT=>"4.0KM5000M9000"}],
|
||||
# 'M' is the delimiter, so the second input field is '5000'
|
||||
['mix-14', '--delimiter=M --field 2 --from=auto --to=si 4000M5000M9000',
|
||||
{OUT=>"4000M5.0KM9000"}],
|
||||
|
||||
|
||||
|
||||
## Header testing
|
||||
|
||||
# header - silently ignored with command line parameters
|
||||
['header-1', '--header --to=iec 4096', {OUT=>"4.0K"}],
|
||||
|
||||
# header warning with --debug
|
||||
['header-2', '--debug --header --to=iec 4096', {OUT=>"4.0K"},
|
||||
{ERR=>"$prog: --header ignored with command-line input\n"}],
|
||||
|
||||
['header-3', '--header=A',
|
||||
{ERR=>"$prog: invalid header value 'A'\n"},
|
||||
{EXIT => 1},],
|
||||
['header-4', '--header=0',
|
||||
{ERR=>"$prog: invalid header value '0'\n"},
|
||||
{EXIT => 1},],
|
||||
['header-5', '--header=-6',
|
||||
{ERR=>"$prog: invalid header value '-6'\n"},
|
||||
{EXIT => 1},],
|
||||
['header-6', '--debug --header --to=iec',
|
||||
{IN_PIPE=>"size\n5000\n90000\n"},
|
||||
{OUT=>"size\n4.9K\n88K"}],
|
||||
['header-7', '--debug --header=3 --to=iec',
|
||||
{IN_PIPE=>"hello\nworld\nsize\n5000\n90000\n"},
|
||||
{OUT=>"hello\nworld\nsize\n4.9K\n88K"}],
|
||||
# header, but no actual content
|
||||
['header-8', '--header=2 --to=iec',
|
||||
{IN_PIPE=>"hello\nworld\n"},
|
||||
{OUT=>"hello\nworld"}],
|
||||
# not enough header lines
|
||||
['header-9', '--header=3 --to=iec',
|
||||
{IN_PIPE=>"hello\nworld\n"},
|
||||
{OUT=>"hello\nworld"}],
|
||||
|
||||
|
||||
## human_strtod testing
|
||||
|
||||
# NO_DIGITS_FOUND
|
||||
['strtod-1', '--from=si "foo"',
|
||||
{ERR=>"$prog: invalid number: 'foo'\n"},
|
||||
{EXIT=> 2}],
|
||||
['strtod-2', '--from=si ""',
|
||||
{ERR=>"$prog: invalid number: ''\n"},
|
||||
{EXIT=> 2}],
|
||||
|
||||
# INTEGRAL_OVERFLOW
|
||||
['strtod-3', '--from=si "1234567890123456789012345678901234567890'.
|
||||
'1234567890123456789012345678901234567890"',
|
||||
{ERR=>"$prog: value too large to be converted: '" .
|
||||
"1234567890123456789012345678901234567890" .
|
||||
"1234567890123456789012345678901234567890'\n",
|
||||
},
|
||||
{EXIT=> 2}],
|
||||
|
||||
# FRACTION_NO_DIGITS_FOUND
|
||||
['strtod-5', '--from=si 12.',
|
||||
{ERR=>"$prog: invalid number: '12.'\n"},
|
||||
{EXIT=>2}],
|
||||
['strtod-6', '--from=si 12.K',
|
||||
{ERR=>"$prog: invalid number: '12.K'\n"},
|
||||
{EXIT=>2}],
|
||||
|
||||
# whitespace is not allowed after decimal-point
|
||||
['strtod-6.1', '--from=si --delimiter=, "12. 2"',
|
||||
{ERR=>"$prog: invalid number: '12. 2'\n"},
|
||||
{EXIT=>2}],
|
||||
|
||||
# FRACTION_OVERFLOW
|
||||
['strtod-7', '--from=si "12.1234567890123456789012345678901234567890'.
|
||||
'1234567890123456789012345678901234567890"',
|
||||
{ERR=>"$prog: value too large to be converted: '" .
|
||||
"12.1234567890123456789012345678901234567890" .
|
||||
"1234567890123456789012345678901234567890'\n",
|
||||
},
|
||||
{EXIT=> 2}],
|
||||
|
||||
# INVALID_SUFFIX
|
||||
['strtod-9', '--from=si 12.2Q',
|
||||
{ERR=>"$prog: invalid suffix in input: '12.2Q'\n"},
|
||||
{EXIT=>2}],
|
||||
|
||||
# VALID_BUT_FORBIDDEN_SUFFIX
|
||||
['strtod-10', '12M',
|
||||
{ERR => "$prog: rejecting suffix " .
|
||||
"in input: '12M' (consider using --from)\n"},
|
||||
{EXIT=>2}],
|
||||
|
||||
# MISSING_I_SUFFIX
|
||||
['strtod-11', '--from=iec-i 12M',
|
||||
{ERR => "$prog: missing 'i' suffix in input: " .
|
||||
"'12M' (e.g Ki/Mi/Gi)\n"},
|
||||
{EXIT=>2}],
|
||||
|
||||
#
|
||||
# Test double_to_human()
|
||||
#
|
||||
|
||||
# 1K and smaller
|
||||
['dbl-to-human-1','--to=si 800', {OUT=>"800"}],
|
||||
['dbl-to-human-2','--to=si 0', {OUT=>"0"}],
|
||||
['dbl-to-human-2.1','--to=si 999', {OUT=>"999"}],
|
||||
['dbl-to-human-2.2','--to=si 1000', {OUT=>"1.0K"}],
|
||||
#NOTE: the following are consistent with "ls -lh" output
|
||||
['dbl-to-human-2.3','--to=iec 999', {OUT=>"999"}],
|
||||
['dbl-to-human-2.4','--to=iec 1023', {OUT=>"1023"}],
|
||||
['dbl-to-human-2.5','--to=iec 1024', {OUT=>"1.0K"}],
|
||||
['dbl-to-human-2.6','--to=iec 1025', {OUT=>"1.1K"}],
|
||||
['dbl-to-human-2.7','--to=iec 0', {OUT=>"0"}],
|
||||
# no "i" suffix if output has no suffix
|
||||
['dbl-to-human-2.8','--to=iec-i 0', {OUT=>"0"}],
|
||||
|
||||
# values resulting in "N.Nx" output
|
||||
['dbl-to-human-3','--to=si 8000', {OUT=>"8.0K"}],
|
||||
['dbl-to-human-3.1','--to=si 8001', {OUT=>"8.1K"}],
|
||||
['dbl-to-human-4','--to=si --round=down 8001', {OUT=>"8.0K"}],
|
||||
|
||||
['dbl-to-human-5','--to=si --round=down 3500', {OUT=>"3.5K"}],
|
||||
['dbl-to-human-6','--to=si --round=nearest 3500', {OUT=>"3.5K"}],
|
||||
['dbl-to-human-7','--to=si --round=up 3500', {OUT=>"3.5K"}],
|
||||
|
||||
['dbl-to-human-8','--to=si --round=down 3501', {OUT=>"3.5K"}],
|
||||
['dbl-to-human-9','--to=si --round=nearest 3501', {OUT=>"3.5K"}],
|
||||
['dbl-to-human-10','--to=si --round=up 3501', {OUT=>"3.6K"}],
|
||||
|
||||
['dbl-to-human-11','--to=si --round=nearest 3550', {OUT=>"3.6K"}],
|
||||
['dbl-to-human-12','--to=si --from=si 999.89K', {OUT=>"1.0M"}],
|
||||
['dbl-to-human-13','--to=si --from=si 9.9K', {OUT=>"9.9K"}],
|
||||
['dbl-to-human-14','--to=si 9900', {OUT=>"9.9K"}],
|
||||
['dbl-to-human-15','--to=iec --from=si 3.3K', {OUT=>"3.3K"}],
|
||||
['dbl-to-human-16','--to=iec --round=down --from=si 3.3K', {OUT=>"3.2K"}],
|
||||
|
||||
# values resulting in 'NNx' output
|
||||
['dbl-to-human-17','--to=si 9999', {OUT=>"10K"}],
|
||||
['dbl-to-human-18','--to=si --round=down 35000', {OUT=>"35K"}],
|
||||
['dbl-to-human-19','--to=iec 35000', {OUT=>"35K"}],
|
||||
['dbl-to-human-20','--to=iec --round=down 35000', {OUT=>"34K"}],
|
||||
['dbl-to-human-21','--to=iec 35000000', {OUT=>"34M"}],
|
||||
['dbl-to-human-22','--to=iec --round=down 35000000', {OUT=>"33M"}],
|
||||
['dbl-to-human-23','--to=si 35000001', {OUT=>"36M"}],
|
||||
['dbl-to-human-24','--to=si --from=si 9.99M', {OUT=>"10M"}],
|
||||
['dbl-to-human-25','--to=si --from=iec 9.99M', {OUT=>"11M"}],
|
||||
['dbl-to-human-25.1','--to=iec 99999', {OUT=>"98K"}],
|
||||
|
||||
# values resulting in 'NNNx' output
|
||||
['dbl-to-human-26','--to=si 999000000000', {OUT=>"999G"}],
|
||||
['dbl-to-human-27','--to=iec 999000000000', {OUT=>"931G"}],
|
||||
['dbl-to-human-28','--to=si 123600000000000', {OUT=>"124T"}],
|
||||
['dbl-to-human-29','--to=si 998123', {OUT=>"999K"}],
|
||||
['dbl-to-human-30','--to=si --round=nearest 998123', {OUT=>"998K"}],
|
||||
['dbl-to-human-31','--to=si 99999', {OUT=>"100K"}],
|
||||
['dbl-to-human-32','--to=iec 102399', {OUT=>"100K"}],
|
||||
['dbl-to-human-33','--to=iec-i 102399', {OUT=>"100Ki"}],
|
||||
|
||||
|
||||
# Default --round=from-zero
|
||||
['round-1','--to-unit=1024 -- 6000 -6000',
|
||||
{OUT=>"6\n-6"}],
|
||||
['round-2','--to-unit=1024 -- 6000.0 -6000.0',
|
||||
{OUT=>"5.9\n-5.9"}],
|
||||
['round-3','--to-unit=1024 -- 6000.00 -6000.00',
|
||||
{OUT=>"5.86\n-5.86"}],
|
||||
['round-4','--to-unit=1024 -- 6000.000 -6000.000',
|
||||
{OUT=>"5.860\n-5.860"}],
|
||||
['round-5','--to-unit=1024 -- 6000.0000 -6000.0000',
|
||||
{OUT=>"5.8594\n-5.8594"}],
|
||||
# --round=up
|
||||
['round-1-up','--round=up --to-unit=1024 -- 6000 -6000',
|
||||
{OUT=>"6\n-5"}],
|
||||
['round-2-up','--round=up --to-unit=1024 -- 6000.0 -6000.0',
|
||||
{OUT=>"5.9\n-5.8"}],
|
||||
['round-3-up','--round=up --to-unit=1024 -- 6000.00 -6000.00',
|
||||
{OUT=>"5.86\n-5.85"}],
|
||||
['round-4-up','--round=up --to-unit=1024 -- 6000.000 -6000.000',
|
||||
{OUT=>"5.860\n-5.859"}],
|
||||
['round-5-up','--round=up --to-unit=1024 -- 6000.0000 -6000.0000',
|
||||
{OUT=>"5.8594\n-5.8593"}],
|
||||
# --round=down
|
||||
['round-1-down','--round=down --to-unit=1024 -- 6000 -6000',
|
||||
{OUT=>"5\n-6"}],
|
||||
['round-2-down','--round=down --to-unit=1024 -- 6000.0 -6000.0',
|
||||
{OUT=>"5.8\n-5.9"}],
|
||||
['round-3-down','--round=down --to-unit=1024 -- 6000.00 -6000.00',
|
||||
{OUT=>"5.85\n-5.86"}],
|
||||
['round-4-down','--round=down --to-unit=1024 -- 6000.000 -6000.000',
|
||||
{OUT=>"5.859\n-5.860"}],
|
||||
['round-5-down','--round=down --to-unit=1024 -- 6000.0000 -6000.0000',
|
||||
{OUT=>"5.8593\n-5.8594"}],
|
||||
# --round=towards-zero
|
||||
['round-1-to-zero','--ro=towards-zero --to-u=1024 -- 6000 -6000',
|
||||
{OUT=>"5\n-5"}],
|
||||
['round-2-to-zero','--ro=towards-zero --to-u=1024 -- 6000.0 -6000.0',
|
||||
{OUT=>"5.8\n-5.8"}],
|
||||
['round-3-to-zero','--ro=towards-zero --to-u=1024 -- 6000.00 -6000.00',
|
||||
{OUT=>"5.85\n-5.85"}],
|
||||
['round-4-to-zero','--ro=towards-zero --to-u=1024 -- 6000.000 -6000.000',
|
||||
{OUT=>"5.859\n-5.859"}],
|
||||
['round-5-to-zero','--ro=towards-zero --to-u=1024 -- 6000.0000 -6000.0000',
|
||||
{OUT=>"5.8593\n-5.8593"}],
|
||||
# --round=nearest
|
||||
['round-1-near','--ro=nearest --to-u=1024 -- 6000 -6000',
|
||||
{OUT=>"6\n-6"}],
|
||||
['round-2-near','--ro=nearest --to-u=1024 -- 6000.0 -6000.0',
|
||||
{OUT=>"5.9\n-5.9"}],
|
||||
['round-3-near','--ro=nearest --to-u=1024 -- 6000.00 -6000.00',
|
||||
{OUT=>"5.86\n-5.86"}],
|
||||
['round-4-near','--ro=nearest --to-u=1024 -- 6000.000 -6000.000',
|
||||
{OUT=>"5.859\n-5.859"}],
|
||||
['round-5-near','--ro=nearest --to-u=1024 -- 6000.0000 -6000.0000',
|
||||
{OUT=>"5.8594\n-5.8594"}],
|
||||
|
||||
|
||||
# Large Values
|
||||
['large-1','1000000000000000', {OUT=>"1000000000000000"}],
|
||||
# 18 digits is OK
|
||||
['large-2','1000000000000000000', {OUT=>"1000000000000000000"}],
|
||||
# 19 digits is too much (without output scaling)
|
||||
['large-3','10000000000000000000',
|
||||
{ERR => "$prog: value too large to be printed: '1e+19' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT=>2}],
|
||||
|
||||
# Test input:
|
||||
# Up to 27 digits is OK.
|
||||
['large-3.1', '--to=si 1', {OUT=> "1"}],
|
||||
['large-3.2', '--to=si 10', {OUT=> "10"}],
|
||||
['large-3.3', '--to=si 100', {OUT=> "100"}],
|
||||
['large-3.4', '--to=si 1000', {OUT=>"1.0K"}],
|
||||
['large-3.5', '--to=si 10000', {OUT=> "10K"}],
|
||||
['large-3.6', '--to=si 100000', {OUT=>"100K"}],
|
||||
['large-3.7', '--to=si 1000000', {OUT=>"1.0M"}],
|
||||
['large-3.8', '--to=si 10000000', {OUT=> "10M"}],
|
||||
['large-3.9', '--to=si 100000000', {OUT=>"100M"}],
|
||||
['large-3.10','--to=si 1000000000', {OUT=>"1.0G"}],
|
||||
['large-3.11','--to=si 10000000000', {OUT=> "10G"}],
|
||||
['large-3.12','--to=si 100000000000', {OUT=>"100G"}],
|
||||
['large-3.13','--to=si 1000000000000', {OUT=>"1.0T"}],
|
||||
['large-3.14','--to=si 10000000000000', {OUT=> "10T"}],
|
||||
['large-3.15','--to=si 100000000000000', {OUT=>"100T"}],
|
||||
['large-3.16','--to=si 1000000000000000', {OUT=>"1.0P"}],
|
||||
['large-3.17','--to=si 10000000000000000', {OUT=> "10P"}],
|
||||
['large-3.18','--to=si 100000000000000000', {OUT=>"100P"}],
|
||||
['large-3.19','--to=si 1000000000000000000', {OUT=>"1.0E"}],
|
||||
['large-3.20','--to=si 10000000000000000000', {OUT=> "10E"}],
|
||||
['large-3.21','--to=si 210000000000000000000', {OUT=>"210E"}],
|
||||
['large-3.22','--to=si 3210000000000000000000', {OUT=>"3.3Z"}],
|
||||
['large-3.23','--to=si 43210000000000000000000', {OUT=> "44Z"}],
|
||||
['large-3.24','--to=si 543210000000000000000000', {OUT=>"544Z"}],
|
||||
['large-3.25','--to=si 6543210000000000000000000', {OUT=>"6.6Y"}],
|
||||
['large-3.26','--to=si 76543210000000000000000000', {OUT=> "77Y"}],
|
||||
['large-3.27','--to=si 876543210000000000000000000', {OUT=>"877Y"}],
|
||||
|
||||
# More than 27 digits is not OK
|
||||
['large-3.28','--to=si 9876543210000000000000000000',
|
||||
{ERR => "$prog: value too large to be converted: " .
|
||||
"'9876543210000000000000000000'\n"},
|
||||
{EXIT => 2}],
|
||||
|
||||
# Test Output
|
||||
['large-4.1', '--from=si 9.7M', {OUT=>"9700000"}],
|
||||
['large-4.2', '--from=si 10M', {OUT =>"10000000"}],
|
||||
['large-4.3', '--from=si 200M', {OUT =>"200000000"}],
|
||||
['large-4.4', '--from=si 3G', {OUT =>"3000000000"}],
|
||||
['large-4.5', '--from=si 40G', {OUT =>"40000000000"}],
|
||||
['large-4.6', '--from=si 500G', {OUT =>"500000000000"}],
|
||||
['large-4.7', '--from=si 6T', {OUT =>"6000000000000"}],
|
||||
['large-4.8', '--from=si 70T', {OUT =>"70000000000000"}],
|
||||
['large-4.9', '--from=si 800T', {OUT =>"800000000000000"}],
|
||||
['large-4.10','--from=si 9P', {OUT =>"9000000000000000"}],
|
||||
['large-4.11','--from=si 10P', {OUT =>"10000000000000000"}],
|
||||
['large-4.12','--from=si 200P', {OUT =>"200000000000000000"}],
|
||||
['large-4.13','--from=si 3E', {OUT =>"3000000000000000000"}],
|
||||
|
||||
# More than 18 digits of output without scaling - no good.
|
||||
['large-4.14','--from=si 40E',
|
||||
{ERR => "$prog: value too large to be printed: '4e+19' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-4.15','--from=si 500E',
|
||||
{ERR => "$prog: value too large to be printed: '5e+20' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-4.16','--from=si 6Z',
|
||||
{ERR => "$prog: value too large to be printed: '6e+21' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-4.17','--from=si 70Z',
|
||||
{ERR => "$prog: value too large to be printed: '7e+22' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-4.18','--from=si 800Z',
|
||||
{ERR => "$prog: value too large to be printed: '8e+23' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-4.19','--from=si 9Y',
|
||||
{ERR => "$prog: value too large to be printed: '9e+24' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-4.20','--from=si 10Y',
|
||||
{ERR => "$prog: value too large to be printed: '1e+25' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-4.21','--from=si 200Y',
|
||||
{ERR => "$prog: value too large to be printed: '2e+26' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
|
||||
['large-5.1','--to=si 1000000000000000000', {OUT=>"1.0E"}],
|
||||
['large-5','--from=si --to=si 2E', {OUT=>"2.0E"}],
|
||||
['large-6','--from=si --to=si 3.4Z', {OUT=>"3.4Z"}],
|
||||
['large-7','--from=si --to=si 80Y', {OUT=>"80Y"}],
|
||||
['large-8','--from=si --to=si 9000Z', {OUT=>"9.0Y"}],
|
||||
|
||||
['large-10','--from=si --to=si 999Y', {OUT=>"999Y"}],
|
||||
['large-11','--from=si --to=iec 999Y', {OUT=>"827Y"}],
|
||||
['large-12','--from=si --round=down --to=iec 999Y', {OUT=>"826Y"}],
|
||||
|
||||
# units can also affect the output
|
||||
['large-13','--from=si --from-unit=1000000 9P',
|
||||
{ERR => "$prog: value too large to be printed: '9e+21' " .
|
||||
"(consider using --to)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-13.1','--from=si --from-unit=1000000 --to=si 9P', {OUT=>"9.0Z"}],
|
||||
|
||||
# Numbers>999Y are never acceptable, regardless of scaling
|
||||
['large-14','--from=si --to=si 999Y', {OUT=>"999Y"}],
|
||||
['large-14.1','--from=si --to=si 1000Y',
|
||||
{ERR => "$prog: value too large to be printed: '1e+27' " .
|
||||
"(cannot handle values > 999Y)\n"},
|
||||
{EXIT => 2}],
|
||||
['large-14.2','--from=si --to=si --from-unit=10000 1Y',
|
||||
{ERR => "$prog: value too large to be printed: '1e+28' " .
|
||||
"(cannot handle values > 999Y)\n"},
|
||||
{EXIT => 2}],
|
||||
|
||||
# debug warnings
|
||||
['debug-1', '--debug 4096', {OUT=>"4096"},
|
||||
{ERR=>"$prog: no conversion option specified\n"}],
|
||||
# '--padding' is a valid conversion option - no warning should be printed
|
||||
['debug-1.1', '--debug --padding 10 4096', {OUT=>" 4096"}],
|
||||
['debug-2', '--debug --grouping --from=si 4.0K', {OUT=>"4000"},
|
||||
{ERR=>"$prog: grouping has no effect in this locale\n"}],
|
||||
['debug-4', '--to=si --debug 12345678901234567890',
|
||||
{OUT=>"13E"},
|
||||
{ERR=>"$prog: large input value '12345678901234567890':" .
|
||||
" possible precision loss\n"}],
|
||||
['debug-5', '--to=si --from=si --debug 1.12345678901234567890Y',
|
||||
{OUT=>"1.2Y"},
|
||||
{ERR=>"$prog: large input value '1.12345678901234567890Y':" .
|
||||
" possible precision loss\n"}],
|
||||
|
||||
# dev-debug messages - the actual messages don't matter
|
||||
# just ensure the program works, and for code coverage testing.
|
||||
['devdebug-1', '---devdebug --from=si 4.9K', {OUT=>"4900"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-2', '---devdebug 4900', {OUT=>"4900"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-3', '---devdebug --from=auto 4Mi', {OUT=>"4194304"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-4', '---devdebug --to=si 4000000', {OUT=>"4.0M"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-5', '---devdebug --to=si --padding=5 4000000', {OUT=>" 4.0M"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-6', '---devdebug --suffix=Foo 1234Foo', {OUT=>"1234Foo"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-7', '---devdebug --suffix=Foo 1234', {OUT=>"1234Foo"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-9', '---devdebug --grouping 10000', {OUT=>"10000"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-10', '---devdebug --format %f 10000', {OUT=>"10000"},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-11', '---devdebug --format "%\'-10f" 10000',{OUT=>"10000 "},
|
||||
{ERR=>""},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
['devdebug-12', '---devdebug --field 2 A',{OUT=>""},
|
||||
{ERR=>""}, {EXIT=>2},
|
||||
{ERR_SUBST=>"s/.*//msg"}],
|
||||
|
||||
# Invalid parameters
|
||||
['help-1', '--foobar',
|
||||
{ERR=>"$prog: unrecognized option '--foobar'\n" .
|
||||
"Try '$prog --help' for more information.\n"},
|
||||
{EXIT=>1}],
|
||||
|
||||
## Format string - check error detection
|
||||
['fmt-err-1', '--format ""',
|
||||
{ERR=>"$prog: format '' has no % directive\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-2', '--format "hello"',
|
||||
{ERR=>"$prog: format 'hello' has no % directive\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-3', '--format "hello%"',
|
||||
{ERR=>"$prog: format 'hello%' ends in %\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-4', '--format "%d"',
|
||||
{ERR=>"$prog: invalid format '%d', " .
|
||||
"directive must be %['][-][N]f\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-5', '--format "% -43 f"',
|
||||
{ERR=>"$prog: invalid format '% -43 f', " .
|
||||
"directive must be %['][-][N]f\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-6', '--format "%f %f"',
|
||||
{ERR=>"$prog: format '%f %f' has too many % directives\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-7', '--format "%123456789012345678901234567890f"',
|
||||
{ERR=>"$prog: invalid format '%123456789012345678901234567890f'".
|
||||
" (width overflow)\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-8', '--format "%f" --padding 20',
|
||||
{ERR=>"$prog: --padding cannot be combined with --format\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-9', '--format "%f" --grouping',
|
||||
{ERR=>"$prog: --grouping cannot be combined with --format\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-10', '--format "%\'f" --to=si',
|
||||
{ERR=>"$prog: grouping cannot be combined with --to\n"},
|
||||
{EXIT=>1}],
|
||||
['fmt-err-11', '--debug --format "%\'f" 5000', {OUT=>"5000"},
|
||||
{ERR=>"$prog: grouping has no effect in this locale\n"}],
|
||||
|
||||
## Format string - check some corner cases
|
||||
['fmt-1', '--format "%% %f" 5000', {OUT=>"%%5000"}],
|
||||
['fmt-2', '--format "%f %%" 5000', {OUT=>"5000 %%"}],
|
||||
|
||||
['fmt-3', '--format "--%f--" 5000000', {OUT=>"--5000000--"}],
|
||||
['fmt-4', '--format "--%f--" --to=si 5000000', {OUT=>"--5.0M--"}],
|
||||
|
||||
['fmt-5', '--format "--%10f--" --to=si 5000000',{OUT=>"-- 5.0M--"}],
|
||||
['fmt-6', '--format "--%-10f--" --to=si 5000000',{OUT=>"--5.0M --"}],
|
||||
['fmt-7', '--format "--%10f--" 5000000',{OUT=>"-- 5000000--"}],
|
||||
['fmt-8', '--format "--%-10f--" 5000000',{OUT=>"--5000000 --"}],
|
||||
|
||||
# too-short width
|
||||
['fmt-9', '--format "--%5f--" 5000000',{OUT=>"--5000000--"}],
|
||||
|
||||
# Format + Suffix
|
||||
['fmt-10', '--format "--%10f--" --suffix Foo 50', {OUT=>"-- 50Foo--"}],
|
||||
['fmt-11', '--format "--%-10f--" --suffix Foo 50',{OUT=>"--50Foo --"}],
|
||||
|
||||
# Grouping in C locale - no grouping effect
|
||||
['fmt-12', '--format "%\'f" 50000',{OUT=>"50000"}],
|
||||
['fmt-13', '--format "%\'10f" 50000', {OUT=>" 50000"}],
|
||||
['fmt-14', '--format "%\'-10f" 50000',{OUT=>"50000 "}],
|
||||
|
||||
# Very large format strings
|
||||
['fmt-15', '--format "--%100000f--" --to=si 4200',
|
||||
{OUT=>"--" . " " x 99996 . "4.2K--" }],
|
||||
|
||||
|
||||
## Check all errors again, this time with --invalid=fail
|
||||
## Input will be printed without conversion,
|
||||
## and exit code will be 2
|
||||
['ign-err-1', '--invalid=fail 4Q',
|
||||
{ERR => "$prog: invalid suffix in input: '4Q'\n"},
|
||||
{OUT => "4Q\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-2', '--invalid=fail 4M',
|
||||
{ERR => "$prog: rejecting suffix " .
|
||||
"in input: '4M' (consider using --from)\n"},
|
||||
{OUT => "4M\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-3', '--invalid=fail --from=si 4MQ',
|
||||
{ERR => "$prog: invalid suffix in input '4MQ': 'Q'\n"},
|
||||
{OUT => "4MQ\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-4', '--invalid=fail --suffix=Foo --to=si 7000FooF',
|
||||
{ERR => "$prog: invalid suffix in input: '7000FooF'\n"},
|
||||
{OUT => "7000FooF\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-5','--invalid=fail --field 3 --from=auto "Hello 40M World 90G"',
|
||||
{ERR => "$prog: invalid number: 'World'\n"},
|
||||
{OUT => "Hello 40M World 90G\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-6', '--invalid=fail --field 3 --to=si "Hello World"',
|
||||
{ERR => "$prog: input line is too short, no numbers found " .
|
||||
"to convert in field 3\n"},
|
||||
{OUT => "Hello World\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-7', '--invalid=fail --from=si "foo"',
|
||||
{ERR => "$prog: invalid number: 'foo'\n"},
|
||||
{OUT => "foo\n"},
|
||||
{EXIT=> 2}],
|
||||
['ign-err-8', '--invalid=fail 12M',
|
||||
{ERR => "$prog: rejecting suffix " .
|
||||
"in input: '12M' (consider using --from)\n"},
|
||||
{OUT => "12M\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-9', '--invalid=fail --from=iec-i 12M',
|
||||
{ERR => "$prog: missing 'i' suffix in input: " .
|
||||
"'12M' (e.g Ki/Mi/Gi)\n"},
|
||||
{OUT => "12M\n"},
|
||||
{EXIT=>2}],
|
||||
['ign-err-10','--invalid=fail 10000000000000000000',
|
||||
{ERR => "$prog: value too large to be printed: '1e+19' " .
|
||||
"(consider using --to)\n"},
|
||||
{OUT => "10000000000000000000\n"},
|
||||
{EXIT=>2}],
|
||||
['ign-err-11','--invalid=fail --to=si 9876543210000000000000000000',
|
||||
{ERR => "$prog: value too large to be converted: " .
|
||||
"'9876543210000000000000000000'\n"},
|
||||
{OUT => "9876543210000000000000000000\n"},
|
||||
{EXIT => 2}],
|
||||
|
||||
## Ignore Errors with multiple conversions
|
||||
['ign-err-m1', '--invalid=ignore --to=si 1000 2000 bad 3000',
|
||||
{OUT => "1.0K\n2.0K\nbad\n3.0K"},
|
||||
{EXIT => 0}],
|
||||
['ign-err-m1.1', '--invalid=ignore --to=si',
|
||||
{IN_PIPE => "1000\n2000\nbad\n3000\n"},
|
||||
{OUT => "1.0K\n2.0K\nbad\n3.0K"},
|
||||
{EXIT => 0}],
|
||||
['ign-err-m1.3', '--invalid=fail --debug --to=si 1000 2000 3000',
|
||||
{OUT => "1.0K\n2.0K\n3.0K"},
|
||||
{EXIT => 0}],
|
||||
['ign-err-m2', '--invalid=fail --to=si 1000 Foo 3000',
|
||||
{OUT => "1.0K\nFoo\n3.0K\n"},
|
||||
{ERR => "$prog: invalid number: 'Foo'\n"},
|
||||
{EXIT => 2}],
|
||||
['ign-err-m2.1', '--invalid=warn --to=si',
|
||||
{IN_PIPE => "1000\nFoo\n3000\n"},
|
||||
{OUT => "1.0K\nFoo\n3.0K"},
|
||||
{ERR => "$prog: invalid number: 'Foo'\n"},
|
||||
{EXIT => 0}],
|
||||
|
||||
# --debug will trigger a final warning at EOF
|
||||
['ign-err-m2.2', '--invalid=fail --debug --to=si 1000 Foo 3000',
|
||||
{OUT => "1.0K\nFoo\n3.0K\n"},
|
||||
{ERR => "$prog: invalid number: 'Foo'\n" .
|
||||
"$prog: failed to convert some of the input numbers\n"},
|
||||
{EXIT => 2}],
|
||||
|
||||
['ign-err-m3', '--invalid=fail --field 2 --from=si --to=iec',
|
||||
{IN_PIPE => "A 1K x\nB 2M y\nC 3G z\n"},
|
||||
{OUT => "A 1000 x\nB 2.0M y\nC 2.8G z"},
|
||||
{EXIT => 0}],
|
||||
# invalid input on one of the fields
|
||||
['ign-err-m3.1', '--invalid=fail --field 2 --from=si --to=iec',
|
||||
{IN_PIPE => "A 1K x\nB Foo y\nC 3G z\n"},
|
||||
{OUT => "A 1000 x\nB Foo y\nC 2.8G z\n"},
|
||||
{ERR => "$prog: invalid number: 'Foo'\n"},
|
||||
{EXIT => 2}],
|
||||
# one of the lines is too short
|
||||
['ign-err-m3.2', '--invalid=fail --field 2 --from=si --to=iec',
|
||||
{IN_PIPE => "A 1K x\nB\nC 3G z\n"},
|
||||
{OUT => "A 1000 x\nB\nC 2.8G z\n"},
|
||||
{ERR => "$prog: input line is too short, no numbers found " .
|
||||
"to convert in field 2\n"},
|
||||
{EXIT => 2}],
|
||||
);
|
||||
|
||||
my @Locale_Tests =
|
||||
(
|
||||
# Locale that supports grouping, but without '--grouping' parameter
|
||||
['lcl-grp-1', '--from=si 7M', {OUT=>"7000000"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
|
||||
# Locale with grouping
|
||||
['lcl-grp-2', '--from=si --grouping 7M', {OUT=>"7 000 000"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
|
||||
# Locale with grouping and debug - no debug warning message
|
||||
['lcl-grp-3', '--from=si --debug --grouping 7M', {OUT=>"7 000 000"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
|
||||
# Input with locale'd decimal-point
|
||||
['lcl-stdtod-1', '--from=si 12,2K', {OUT=>"12200"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
|
||||
['lcl-dbl-to-human-1', '--to=si 1100', {OUT=>"1,1K"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
|
||||
# Format + Grouping
|
||||
['lcl-fmt-1', '--format "%\'f" 50000',{OUT=>"50 000"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
['lcl-fmt-2', '--format "--%\'10f--" 50000', {OUT=>"-- 50 000--"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
['lcl-fmt-3', '--format "--%\'-10f--" 50000',{OUT=>"--50 000 --"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
['lcl-fmt-4', '--format "--%-10f--" --to=si 5000000',
|
||||
{OUT=>"--5,0M --"},
|
||||
{ENV=>"LC_ALL=$locale"}],
|
||||
|
||||
);
|
||||
push @Tests, @Locale_Tests if $locale ne "C";
|
||||
|
||||
## Check all valid/invalid suffixes
|
||||
foreach my $suf ( 'A' .. 'Z', 'a' .. 'z' ) {
|
||||
if ( $suf =~ /^[KMGTPEZY]$/ )
|
||||
{
|
||||
push @Tests, ["auto-suf-si-$suf","--from=si --to=si 1$suf",
|
||||
{OUT=>"1.0$suf"}];
|
||||
push @Tests, ["auto-suf-iec-$suf","--from=iec --to=iec 1$suf",
|
||||
{OUT=>"1.0$suf"}];
|
||||
push @Tests, ["auto-suf-auto-$suf","--from=auto --to=iec 1${suf}i",
|
||||
{OUT=>"1.0$suf"}];
|
||||
push @Tests, ["auto-suf-iec-to-ieci-$suf","--from=iec --to=iec-i 1${suf}",
|
||||
{OUT=>"1.0${suf}i"}];
|
||||
push @Tests, ["auto-suf-ieci-to-iec-$suf",
|
||||
"--from=iec-i --to=iec 1${suf}i",{OUT=>"1.0${suf}"}];
|
||||
}
|
||||
else
|
||||
{
|
||||
push @Tests, ["auto-suf-si-$suf","--from=si --to=si 1$suf",
|
||||
{ERR=>"$prog: invalid suffix in input: '1${suf}'\n"},
|
||||
{EXIT=>2}];
|
||||
}
|
||||
}
|
||||
|
||||
# Prepend the command line argument and append a newline to end
|
||||
# of each expected 'OUT' string.
|
||||
my $t;
|
||||
|
||||
Test:
|
||||
foreach $t (@Tests)
|
||||
{
|
||||
# Don't fiddle with expected OUT string if there's a nonzero exit status.
|
||||
foreach my $e (@$t)
|
||||
{
|
||||
ref $e eq 'HASH' && exists $e->{EXIT} && $e->{EXIT}
|
||||
and next Test;
|
||||
}
|
||||
|
||||
foreach my $e (@$t)
|
||||
{
|
||||
ref $e eq 'HASH' && exists $e->{OUT}
|
||||
and $e->{OUT} .= "\n"
|
||||
}
|
||||
}
|
||||
|
||||
my $save_temps = $ENV{SAVE_TEMPS};
|
||||
my $verbose = $ENV{VERBOSE};
|
||||
|
||||
my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
|
||||
exit $fail;
|
Reference in New Issue
Block a user