summaryrefslogtreecommitdiffstats
path: root/tests/expr
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 16:58:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 16:58:41 +0000
commite1908ae95dd4c9d19ee4dfabfc8bf8a7f85943fe (patch)
treef5cc731bedcac0fb7fe14d952e4581e749f8bb87 /tests/expr
parentInitial commit. (diff)
downloadcoreutils-upstream.tar.xz
coreutils-upstream.zip
Adding upstream version 9.4.upstream/9.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/expr')
-rwxr-xr-xtests/expr/expr-multibyte.pl226
-rwxr-xr-xtests/expr/expr.pl238
2 files changed, 464 insertions, 0 deletions
diff --git a/tests/expr/expr-multibyte.pl b/tests/expr/expr-multibyte.pl
new file mode 100755
index 0000000..4d763d6
--- /dev/null
+++ b/tests/expr/expr-multibyte.pl
@@ -0,0 +1,226 @@
+#!/usr/bin/perl
+# Exercise expr with multibyte input
+
+# Copyright (C) 2017-2023 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 <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+
+my $limits = getlimits ();
+my $UINTMAX_OFLOW = $limits->{UINTMAX_OFLOW};
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'expr';
+
+my $locale = $ENV{LOCALE_FR_UTF8};
+! defined $locale || $locale eq 'none'
+ and CuSkip::skip "$ME: this test requires FR-UTF8 locale\n";
+
+
+=pod
+ἔκφρασις (ekphrasis) - "expression" in Ancient Greek.
+=cut
+my $expression = "\x{1F14}\x{3BA}\x{3C6}\x{3C1}\x{3B1}\x{3C3}\x{3B9}\x{3C2}";
+
+
+## NOTE about tests locales:
+## Tests starting with 'mb' will have {ENV=>"LC_ALL=$locale"}
+## added to them automatically - results are multibyte-aware.
+## Tests starting with 'sb' have the same input but will be
+## run under C locale and will be treated as single-bytes.
+## This enables interleaving C/UTF8 tests
+## (for easier comparison of expected results).
+
+my @Tests =
+ (
+ ### length expressions ###
+
+ # sanity check
+ ['mb-l1', 'length abcdef', {OUT=>"6"}],
+ ['st-l1', 'length abcdef', {OUT=>"6"}],
+
+ # A single multibyte character in the beginning of the string
+ # \xCE\xB1 is UTF-8 for "U+03B1 GREEK SMALL LETTER ALPHA"
+ ['mb-l2', "length \xCE\xB1bcdef", {OUT=>"6"}],
+ ['st-l2', "length \xCE\xB1bcdef", {OUT=>"7"}],
+
+ # A single multibyte character in the middle of the string
+ # \xCE\xB4 is UTF-8 for "U+03B4 GREEK SMALL LETTER DELTA"
+ ['mb-l3', "length abc\xCE\xB4ef", {OUT=>"6"}],
+ ['st-l3', "length abc\xCE\xB4ef", {OUT=>"7"}],
+
+ # A single multibyte character in the end of the string
+ ['mb-l4', "length fedcb\xCE\xB1", {OUT=>"6"}],
+ ['st-l4', "length fedcb\xCE\xB1", {OUT=>"7"}],
+
+ # A invalid multibyte sequence
+ ['mb-l5', "length \xB1aaa", {OUT=>"4"}],
+ ['st-l5', "length \xB1aaa", {OUT=>"4"}],
+
+ # An incomplete multibyte sequence at the end of the string
+ ['mb-l6', "length aaa\xCE", {OUT=>"4"}],
+ ['st-l6', "length aaa\xCE", {OUT=>"4"}],
+
+ # An incomplete multibyte sequence at the end of the string
+ ['mb-l7', "length $expression", {OUT=>"8"}],
+ ['st-l7', "length $expression", {OUT=>"17"}],
+
+
+
+ ### index expressions ###
+
+ # sanity check
+ ['mb-i1', 'index abcdef fb', {OUT=>"2"}],
+ ['st-i1', 'index abcdef fb', {OUT=>"2"}],
+
+ # Search for a single-octet
+ ['mb-i2', "index \xCE\xB1bc\xCE\xB4ef b", {OUT=>"2"}],
+ ['st-i2', "index \xCE\xB1bc\xCE\xB4ef b", {OUT=>"3"}],
+ ['mb-i3', "index \xCE\xB1bc\xCE\xB4ef f", {OUT=>"6"}],
+ ['st-i3', "index \xCE\xB1bc\xCE\xB4ef f", {OUT=>"8"}],
+
+ # Search for multibyte character.
+ # In the C locale, the search string is treated as two octets.
+ # the first of them (\xCE) matches the first octet of the input string.
+ ['mb-i4', "index \xCE\xB1bc\xCE\xB4ef \xCE\xB4", {OUT=>"4"}],
+ ['st-i4', "index \xCE\xB1bc\xCE\xB4ef \xCE\xB4", {OUT=>"1"}],
+
+ # Invalid multibyte sequence in the input string, treated as a single octet.
+ ['mb-i5', "index \xCEbc\xCE\xB4ef \xCE\xB4", {OUT=>"4"}],
+ ['st-i5', "index \xCEbc\xCE\xB4ef \xCE\xB4", {OUT=>"1"}],
+
+ # Invalid multibyte sequence in the search string, treated as a single octet.
+ # In multibyte locale, there should be no match, expr returns and prints
+ # zero, and terminates with exit-code 1 (as per POSIX).
+ ['mb-i6', "index \xCE\xB1bc\xCE\xB4ef \xB4", {OUT=>"0"}, {EXIT=>1}],
+ ['st-i6', "index \xCE\xB1bc\xCE\xB4ef \xB4", {OUT=>"6"}],
+
+ # Edge-case: invalid multibyte sequence BOTH in the input string
+ # and in the search string: expr should find a match.
+ ['mb-i7', "index \xCE\xB1bc\xB4ef \xB4", {OUT=>"4"}],
+
+
+ ### substr expressions ###
+
+ # sanity check
+ ['mb-s1', 'substr abcdef 2 3', {OUT=>"bcd"}],
+ ['st-s1', 'substr abcdef 2 3', {OUT=>"bcd"}],
+
+ ['mb-s2', "substr \xCE\xB1bc\xCE\xB4ef 1 1", {OUT=>"\xCE\xB1"}],
+ ['st-s2', "substr \xCE\xB1bc\xCE\xB4ef 1 1", {OUT=>"\xCE"}],
+
+ ['mb-s3', "substr \xCE\xB1bc\xCE\xB4ef 3 2", {OUT=>"c\xCE\xB4"}],
+ ['st-s3', "substr \xCE\xB1bc\xCE\xB4ef 3 2", {OUT=>"bc"}],
+
+ ['mb-s4', "substr \xCE\xB1bc\xCE\xB4ef 4 1", {OUT=>"\xCE\xB4"}],
+ ['st-s4', "substr \xCE\xB1bc\xCE\xB4ef 4 1", {OUT=>"c"}],
+
+ ['mb-s5', "substr \xCE\xB1bc\xCE\xB4ef 4 2", {OUT=>"\xCE\xB4e"}],
+ ['st-s5', "substr \xCE\xB1bc\xCE\xB4ef 4 2", {OUT=>"c\xCE"}],
+
+ ['mb-s6', "substr \xCE\xB1bc\xCE\xB4ef 6 1", {OUT=>"f"}],
+ ['st-s6', "substr \xCE\xB1bc\xCE\xB4ef 6 1", {OUT=>"\xB4"}],
+
+ ['mb-s7', "substr \xCE\xB1bc\xCE\xB4ef 7 1", {OUT=>""}, {EXIT=>1}],
+ ['st-s7', "substr \xCE\xB1bc\xCE\xB4ef 7 1", {OUT=>"e"}],
+
+ # Invalid multibyte sequences
+ ['mb-s8', "substr \xCE\xB1bc\xB4ef 3 3", {OUT=>"c\xB4e"}],
+ ['st-s8', "substr \xCE\xB1bc\xB4ef 3 3", {OUT=>"bc\xB4"}],
+
+
+ ### match expressions ###
+
+ # sanity check
+ ['mb-m1', 'match abcdef ab', {OUT=>"2"}],
+ ['st-m1', 'match abcdef ab', {OUT=>"2"}],
+ ['mb-m2', 'match abcdef "\(ab\)"', {OUT=>"ab"}],
+ ['st-m2', 'match abcdef "\(ab\)"', {OUT=>"ab"}],
+
+ # The regex engine should match the '.' to the first multibyte character.
+ ['mb-m3', "match \xCE\xB1bc\xCE\xB4ef .bc", {OUT=>"3"}],
+ ['st-m3', "match \xCE\xB1bc\xCE\xB4ef .bc", {OUT=>"0"}, {EXIT=>1}],
+
+ # The opposite of the previous test: two dots should only match
+ # the two octets in single-byte locale.
+ ['mb-m4', "match \xCE\xB1bc\xCE\xB4ef ..bc", {OUT=>"0"}, {EXIT=>1}],
+ ['st-m4', "match \xCE\xB1bc\xCE\xB4ef ..bc", {OUT=>"4"}],
+
+ # Match with grouping - a single dot should return the two octets
+ ['mb-m5', "match \xCE\xB1bc\xCE\xB4ef '\\(.b\\)c'", {OUT=>"\xCE\xB1b"}],
+ ['st-m5', "match \xCE\xB1bc\xCE\xB4ef '\\(.b\\)c'", {OUT=>""}, {EXIT=>1}],
+
+ # Invalid multibyte sequences - regex should not match in multibyte locale
+ # (POSIX requirement)
+ ['mb-m6', "match \xCEbc\xCE\xB4ef '\\(.\\)'", {OUT=>""}, {EXIT=>1}],
+ ['st-m6', "match \xCEbc\xCE\xB4ef '\\(.\\)'", {OUT=>"\xCE"}],
+
+
+ # Character classes: in the multibyte case, the regex engine understands
+ # there is a single multibyte character in the brackets.
+ # In the single byte case, the regex engine sees two octets in the character
+ # class ('\xCE' and '\xB1') - and it matches the first one.
+ ['mb-m7', "match \xCE\xB1bc\xCE\xB4e '\\([\xCE\xB1]\\)'", {OUT=>"\xCE\xB1"}],
+ ['st-m7', "match \xCE\xB1bc\xCE\xB4e '\\([\xCE\xB1]\\)'", {OUT=>"\xCE"}],
+
+ );
+
+
+# Append a newline to end of each expected 'OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} .= "\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+
+# Force multibyte locale in all tests.
+#
+# NOTE about the ERR_SUBST:
+# The error tests above (e1/e2/e3/e4) expect error messages in C locale
+# having single-quote character (ASCII 0x27).
+# In UTF-8 locale, the error messages will use:
+# 'LEFT SINGLE QUOTATION MARK' (U+2018) (UTF8: 0xE2 0x80 0x98)
+# 'RIGHT SINGLE QUOTATION MARK' (U+2019) (UTF8: 0xE2 0x80 0x99)
+# So we replace them with ascii single-quote and the results will
+# match the expected error string.
+if ($locale ne 'C')
+ {
+ my @new;
+ foreach my $t (@Tests)
+ {
+ my ($tname) = @$t;
+ if ($tname =~ /^mb/)
+ {
+ push @$t, ({ENV => "LC_ALL=$locale"},
+ {ERR_SUBST => "s/\xe2\x80[\x98\x99]/'/g"});
+ }
+ }
+ }
+
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/expr/expr.pl b/tests/expr/expr.pl
new file mode 100755
index 0000000..f4863b1
--- /dev/null
+++ b/tests/expr/expr.pl
@@ -0,0 +1,238 @@
+#!/usr/bin/perl
+# Basic tests for "expr".
+
+# Copyright (C) 2001-2023 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 <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+my $prog = 'expr';
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my $mb_locale = $ENV{LOCALE_FR_UTF8};
+! defined $mb_locale || $mb_locale eq 'none'
+ and $mb_locale = 'C';
+
+my $big = '98782897298723498732987928734';
+my $big_p1 = '98782897298723498732987928735';
+my $big_sum = '197565794597446997465975857469';
+my $big_prod = '9758060798730154302876482828124348356960410232492450771490';
+
+my @Tests =
+ (
+ ['a', '5 + 6', {OUT => '11'}],
+ ['b', '5 - 6', {OUT => '-1'}],
+ ['c', '5 \* 6', {OUT => '30'}],
+ ['d', '100 / 6', {OUT => '16'}],
+ ['e', '100 % 6', {OUT => '4'}],
+ ['f', '3 + -2', {OUT => '1'}],
+ ['g', '-2 + -2', {OUT => '-4'}],
+
+ # Verify option processing.
+ # Added when option processing broke in the 7.0 beta release
+ ['opt1', '-- -11 + 12', {OUT => '1'}],
+ ['opt2', '-11 + 12', {OUT => '1'}],
+ ['opt3', '-- -1 + 2', {OUT => '1'}],
+ ['opt4', '-1 + 2', {OUT => '1'}],
+ # This evoked a syntax error diagnostic before 2.0.12.
+ ['opt5', '-- 2 + 2', {OUT => '4'}],
+
+ ['paren1', '\( 100 % 6 \)', {OUT => '4'}],
+ ['paren2', '\( 100 % 6 \) - 8', {OUT => '-4'}],
+ ['paren3', '9 / \( 100 % 6 \) - 8', {OUT => '-6'}],
+ ['paren4', '9 / \( \( 100 % 6 \) - 8 \)', {OUT => '-2'}],
+ ['paren5', '9 + \( 100 % 6 \)', {OUT => '13'}],
+
+ # Before 2.0.12, this would output '1'.
+ ['0bang', '00 \< 0!', {OUT => '0'}, {EXIT => 1}],
+
+ # In 5.1.3 and earlier, these would exit with status 0.
+ ['00', '00', {OUT => '00'}, {EXIT => 1}],
+ ['minus0', '-0', {OUT => '-0'}, {EXIT => 1}],
+
+ # In 5.1.3 and earlier, these would report errors.
+ ['andand', '0 \& 1 / 0', {OUT => '0'}, {EXIT => 1}],
+ ['oror', '1 \| 1 / 0', {OUT => '1'}, {EXIT => 0}],
+
+ # In 5.1.3 and earlier, this would output the empty string.
+ ['orempty', '"" \| ""', {OUT => '0'}, {EXIT => 1}],
+
+
+ # This erroneously succeeded and output '3' before 2.0.12.
+ ['fail-a', '3 + -', {ERR => "$prog: non-integer argument\n"},
+ {EXIT => 2}],
+
+ # This erroneously succeeded before 5.3.1.
+ ['bigcmp', '-- -2417851639229258349412352 \< 2417851639229258349412352',
+ {OUT => '1'}, {EXIT => 0}],
+
+ # In 5.94 and earlier, anchors incorrectly matched newlines.
+ ['anchor', "'a\nb' : 'a\$'", {OUT => '0'}, {EXIT => 1}],
+
+ # In 8.32, \( ... \) that did not match caused memory errors.
+ ['emptysub', '"a" : "\\(b\\)*"', {OUT => ''}, {EXIT => 1}],
+
+ # These tests are taken from grep/tests/bre.tests.
+ ['bre1', '"abc" : "a\\(b\\)c"', {OUT => 'b'}],
+ ['bre2', '"a(" : "a("', {OUT => '2'}],
+ ['bre3', '_ : "a\\("',
+ {ERR => "$prog: Unmatched ( or \\(\n"}, {EXIT => 2}],
+ ['bre4', '_ : "a\\(b"',
+ {ERR => "$prog: Unmatched ( or \\(\n"}, {EXIT => 2}],
+ ['bre5', '"a(b" : "a(b"', {OUT => '3'}],
+ ['bre6', '"a)" : "a)"', {OUT => '2'}],
+ ['bre7', '_ : "a\\)"',
+ {ERR => "$prog: Unmatched ) or \\)\n"}, {EXIT => 2}],
+ ['bre8', '_ : "\\)"',
+ {ERR => "$prog: Unmatched ) or \\)\n"}, {EXIT => 2}],
+ ['bre9', '"ab" : "a\\(\\)b"', {OUT => ''}, {EXIT => 1}],
+ ['bre10', '"a^b" : "a^b"', {OUT => '3'}],
+ ['bre11', '"a\$b" : "a\$b"', {OUT => '3'}],
+ ['bre12', '"" : "\\($\\)\\(^\\)"', {OUT => ''}, {EXIT => 1}],
+ ['bre13', '"b" : "a*\\(^b\$\\)c*"', {OUT => 'b'}],
+ ['bre14', '"X|" : "X\\(|\\)" : "(" "X|" : "X\\(|\\)" ")"', {OUT => '1'}],
+ ['bre15', '"X*" : "X\\(*\\)" : "(" "X*" : "X\\(*\\)" ")"', {OUT => '1'}],
+ ['bre16', '"abc" : "\\(\\)"', {OUT => ''}, {EXIT => 1}],
+ ['bre17', '"{1}a" : "\\(\\{1\\}a\\)"', {OUT => '{1}a'}],
+ ['bre18', '"X*" : "X\\(*\\)" : "^*"', {OUT => '1'}],
+ ['bre19', '"{1}" : "^\\{1\\}"', {OUT => '3'}],
+ ['bre20', '"{" : "{"', {OUT => '1'}],
+ ['bre21', '"abbcbd" : "a\\(b*\\)c\\1d"', {OUT => ''}, {EXIT => 1}],
+ ['bre22', '"abbcbbbd" : "a\\(b*\\)c\\1d"', {OUT => ''}, {EXIT => 1}],
+ ['bre23', '"abc" : "\\(.\\)\\1"', {OUT => ''}, {EXIT => 1}],
+ ['bre24', '"abbccd" : "a\\(\\([bc]\\)\\2\\)*d"', {OUT => 'cc'}],
+ ['bre25', '"abbcbd" : "a\\(\\([bc]\\)\\2\\)*d"',
+ {OUT => ''}, {EXIT => 1}],
+ ['bre26', '"abbbd" : "a\\(\\(b\\)*\\2\\)*d"', {OUT => 'bbb'}],
+ ['bre27', '"aabcd" : "\\(a\\)\\1bcd"', {OUT => 'a'}],
+ ['bre28', '"aabcd" : "\\(a\\)\\1bc*d"', {OUT => 'a'}],
+ ['bre29', '"aabd" : "\\(a\\)\\1bc*d"', {OUT => 'a'}],
+ ['bre30', '"aabcccd" : "\\(a\\)\\1bc*d"', {OUT => 'a'}],
+ ['bre31', '"aabcccd" : "\\(a\\)\\1bc*[ce]d"', {OUT => 'a'}],
+ ['bre32', '"aabcccd" : "\\(a\\)\\1b\\(c\\)*cd\$"', {OUT => 'a'}],
+ ['bre33', '"a*b" : "a\\(*\\)b"', {OUT => '*'}],
+ ['bre34', '"ab" : "a\\(**\\)b"', {OUT => ''}, {EXIT => 1}],
+ ['bre35', '"ab" : "a\\(***\\)b"', {OUT => ''}, {EXIT => 1}],
+ ['bre36', '"*a" : "*a"', {OUT => '2'}],
+ ['bre37', '"a" : "**a"', {OUT => '1'}],
+ ['bre38', '"a" : "***a"', {OUT => '1'}],
+ ['bre39', '"ab" : "a\\{1\\}b"', {OUT => '2'}],
+ ['bre40', '"ab" : "a\\{1,\\}b"', {OUT => '2'}],
+ ['bre41', '"aab" : "a\\{1,2\\}b"', {OUT => '3'}],
+ ['bre42', '_ : "a\\{1"',
+ {ERR => "$prog: Unmatched \\{\n"}, {EXIT => 2}],
+ ['bre43', '_ : "a\\{1a"',
+ {ERR => "$prog: Unmatched \\{\n"}, {EXIT => 2}],
+ ['bre44', '_ : "a\\{1a\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2}],
+ ['bre45', '"a" : "a\\{,2\\}"', {OUT => '1'}],
+ ['bre46', '"a" : "a\\{,\\}"', {OUT => '1'}],
+ ['bre47', '_ : "a\\{1,x\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2}],
+ ['bre48', '_ : "a\\{1,x"',
+ {ERR => "$prog: Unmatched \\{\n"}, {EXIT => 2}],
+ ['bre49', '_ : "a\\{32768\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2},
+ # Map AIX-6's different diagnostic to the one we expect:
+ {ERR_SUBST =>
+ 's,Regular expression too big,Invalid content of \\\\{\\\\},'},
+ ],
+ ['bre50', '_ : "a\\{1,0\\}"',
+ {ERR => "$prog: Invalid content of \\{\\}\n"}, {EXIT => 2}],
+ ['bre51', '"acabc" : ".*ab\\{0,0\\}c"', {OUT => '2'}],
+ ['bre52', '"abcac" : "ab\\{0,1\\}c"', {OUT => '3'}],
+ ['bre53', '"abbcac" : "ab\\{0,3\\}c"', {OUT => '4'}],
+ ['bre54', '"abcac" : ".*ab\\{1,1\\}c"', {OUT => '3'}],
+ ['bre55', '"abcac" : ".*ab\\{1,3\\}c"', {OUT => '3'}],
+ ['bre56', '"abbcabc" : ".*ab\{2,2\}c"', {OUT => '4'}],
+ ['bre57', '"abbcabc" : ".*ab\{2,4\}c"', {OUT => '4'}],
+ ['bre58', '"aa" : "a\\{1\\}\\{1\\}"', {OUT => '1'}],
+ ['bre59', '"aa" : "a*\\{1\\}"', {OUT => '2'}],
+ ['bre60', '"aa" : "a\\{1\\}*"', {OUT => '2'}],
+ ['bre61', '"acd" : "a\\(b\\)?c\\1d"', {OUT => ''}, {EXIT => 1}],
+ ['bre62', '-- "-5" : "-\\{0,1\\}[0-9]*\$"', {OUT => '2'}],
+
+ ['fail-c', {ERR => "$prog: missing operand\n"
+ . "Try '$prog --help' for more information.\n"},
+ {EXIT => 2}],
+
+ ['bignum-add', "$big + 1", {OUT => $big_p1}],
+ ['bignum-add2', "$big + $big_p1", {OUT => $big_sum}],
+ ['bignum-sub', "$big_p1 - 1", {OUT => $big}],
+ ['bignum-sub2', "$big_sum - $big", {OUT => $big_p1}],
+ ['bignum-mul', "$big_p1 '*' $big", {OUT => $big_prod}],
+ ['bignum-div', "$big_prod / $big", {OUT => $big_p1}],
+
+
+ # Test syntax error messages
+ ['se0', '9 9',
+ {ERR => "$prog: syntax error: unexpected argument '9'\n"}, {EXIT => 2}],
+ ['se1', "2 a", {EXIT=>2},
+ {ERR=>"$prog: syntax error: unexpected argument 'a'\n"}],
+ ['se2', "2 '+'", {EXIT=>2},
+ {ERR=>"$prog: syntax error: missing argument after '+'\n"}],
+ ['se3', "2 :", {EXIT=>2},
+ {ERR=>"$prog: syntax error: missing argument after ':'\n"}],
+ ['se4', "length", {EXIT=>2},
+ {ERR=>"$prog: syntax error: missing argument after 'length'\n"}],
+ ['se5', "'(' 2 ", {EXIT=>2},
+ {ERR=>"$prog: syntax error: expecting ')' after '2'\n"}],
+ ['se6', "'(' 2 a", {EXIT=>2},
+ {ERR=>"$prog: syntax error: expecting ')' instead of 'a'\n"}],
+ );
+
+# Append a newline to end of each expected 'OUT' string.
+my $t;
+foreach $t (@Tests)
+ {
+ my $arg1 = $t->[1];
+ my $e;
+ foreach $e (@$t)
+ {
+ $e->{OUT} .= "\n"
+ if ref $e eq 'HASH' and exists $e->{OUT};
+ }
+ }
+
+# Try multibyte locale in most tests.
+#
+if ($mb_locale ne 'C')
+ {
+ # Duplicate each test vector, appending "-mb" to the test name and
+ # inserting {ENV => "LC_ALL=$mb_locale"} in the copy, so that we
+ # provide coverage for the distro-added multi-byte code paths.
+ my @new;
+ foreach my $t (@Tests)
+ {
+ # Don't add the quote varying tests to the multi-byte set
+ $t->[0] =~ /^se/
+ and next;
+
+ my @new_t = @$t;
+ my $test_name = shift @new_t;
+
+ push @new, ["$test_name-mb", @new_t, {ENV => "LC_ALL=$mb_locale"}];
+ }
+ push @Tests, @new;
+ }
+
+my $save_temps = $ENV{SAVE_TEMPS};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;