Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/tests/bin/sh Paranoia: add a new test case testing that $(...



details:   https://anonhg.NetBSD.org/src/rev/542f7e9d5b71
branches:  trunk
changeset: 824386:542f7e9d5b71
user:      kre <kre%NetBSD.org@localhost>
date:      Sat Jun 03 15:15:49 2017 +0000

description:
Paranoia:   add a new test case testing that $(( )) results get split
by IFS just the same as any other expansion (split when they should be,
and not when they shouldn't).

Good thing I did ... this discovered a regression in the new expand
code (from an hour or three ago) where quoted arith expansions are
being split, and shouldn't be.  (on the other hand, when they should
be split, they are being split correctly, so that's good...)

No need to worry too much about this, in real life (as opposed to
torture tests) no-one ever puts digits in IFS, and a $(( )) expansion
only ever contains digits, so in practice, splitting never happens,
whether because it is quoted, or just becaue there is nothing to split.

The FreeBSD shell does it correctly (they do word splitting using a
totally different mechanism than we do) - I will find where I missed
testing for quoted expansions later tonight.  Until that happens,
expect a test failure from t_fsplit:split_arith

While here add more comments in the other test casess (one had a comment
already) that our shell parses incorrectly (this is a parsing problem,
not an expansion problem, and the bug has existed forever .. and is
shared by bash).

That is, in an expression like "${var:-word}" the whole thing (including
word) is quoted by the double quotes, and in "${var:-"word"}" the
expansion is quoted, but 'word' is not, the 2nd " (the one before 'w')
ends the opening quote, and the third (before }) turns quoting on
again (it is required that there be an even number of unquoted quotes inside
a ${} expression, so things like "${var:-"word} are simply invalid.)
Another way of saying this, is that if the { is quoted (for which the
only way is using " to get to this kind of expansion at all) the }
must also be quoted (" quoted).  There is no quote nesting here.

This also means that in "${var:-'word'}" the single quotes are just
characters, they are quoted by the "" that surround them, just as in
"a 'string' containing quotes", but "${var:-"'word'"}} is valid and
contains a single quoted word.

Note that this is different than the patetrn-match/trim expansions
( ${var%pattern} etc) where any surrounding quotes do not affect the
pattern, and all forms of quoting can be used in it - but it always
parses as a pattern, and is never subject to filename expansion, so
a '*' in it that is to mean "match any string" does not need special
quoting to avoid it expanding to file names, regardless of whether
the ${var%*} is quoted or not, but a * that is to be matched as a
character literally does need to be quoted.

I will probably file a PR about this bug sometime, but as it is
very old, and doesn't every seem to bother anyone (and is shared by
bash) there isn't any big hurry to open yet another verry messy can
of excrement to fix it...

This does mean that the FreeBSD shell "fails" some of our tests.
(The test is wrong, their shell is correct.)

diffstat:

 tests/bin/sh/t_fsplit.sh |  77 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 2 deletions(-)

diffs (136 lines):

diff -r 8d083298c60b -r 542f7e9d5b71 tests/bin/sh/t_fsplit.sh
--- a/tests/bin/sh/t_fsplit.sh  Sat Jun 03 14:51:15 2017 +0000
+++ b/tests/bin/sh/t_fsplit.sh  Sat Jun 03 15:15:49 2017 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: t_fsplit.sh,v 1.5 2017/06/03 10:27:05 kre Exp $
+# $NetBSD: t_fsplit.sh,v 1.6 2017/06/03 15:15:49 kre Exp $
 #
 # Copyright (c) 2007-2016 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -33,7 +33,7 @@
 # the "${x-" and "}" were absent from the input line.
 #
 # So: sh -c 'set ${x-a b c}; echo $#' should give 3.
-# and: sh -c 'set -- ${x-}' echo $#' shold give 0
+# and: sh -c 'set -- ${x-}' echo $#' should give 0
 #
 
 # the implementation of "sh" to test
@@ -79,6 +79,8 @@
        then
                  atf_fail "TEST ${TEST} '$1' failed ($STATUS)"
        fi
+
+       return 0
 }
 
 atf_test_case for
@@ -209,8 +211,11 @@
                'za bz zcz'
        check 'x=BOGUS; for i in ${x+"a ${x+b c}" d};   do echo "z${i}z"; done'\
                'za b cz zdz'
+
+       # also incorrect:        uuuu qqqqqq uuu q uuu
        check 'x=BOGUS; for i in ${x+"a ${x+"b c"}" d}; do echo "z${i}z"; done'\
                'za b cz zdz'
+
        check 'x=BOGUS; for i in ${x+a ${x+"b c"} d};   do echo "z${i}z"; done'\
                'zaz zb cz zdz'
        check 'x=BOGUS; for i in ${x+a ${x+b c} d};     do echo "z${i}z"; done'\
@@ -234,8 +239,12 @@
                'zaqbz zcz'
        check 'IFS=q; for i in ${x-"aq${x-bqc}"qd};   do echo "z${i}z"; done' \
                'zaqbqcz zdz'
+
+       # this is another almost certainly incorrect expectation
+       #                        uu qqqqqq uuu q uu     (quoted/unquoted)
        check 'IFS=q; for i in ${x-"aq${x-"bqc"}"qd}; do echo "z${i}z"; done' \
                'zaqbqcz zdz'
+
        check 'IFS=q; for i in ${x-aq${x-"bqc"}qd};  do echo "z${i}z"; done' \
                'zaz zbqcz zdz'
 }
@@ -251,7 +260,11 @@
        TEST=0
        # Some quote propagation checks
        check 'set "${x-a b c}";   echo $#' 1
+
+       # this is another almost certainly incorrect expectation
+       #           qqqq uuu qqq        (quoted/unquoted)  $1 is a $# is 2
        check 'set "${x-"a b" c}"; echo $1' 'a b c'
+
        check 'for i in "${x-a b c}"; do echo "z${i}z"; done' 'za b cz'
 }
 
@@ -356,6 +369,65 @@
        check 'IFS=2; set ${x-${#long}};   :      ; echo "$@" "$#"' '1 8 2'
 }
 
+atf_test_case split_arith
+split_arith_head() {
+       atf_set "descr" "Checks that field splitting works when expanding" \
+                       "the results from arithmetic"
+}
+split_arith_body() {
+       TEST=0
+
+       # Check that we apply IFS to $(( expr ))
+
+       # Note: we do not check the actual arithmetic operations here
+       # (there is a separate test just for that) so we just enter
+       # the "answer" inside $(( )) ... also makes it easier to visualise
+
+       check 'IFS=5; echo $(( 123456789 ))'    '1234 6789'
+       check 'IFS=5; echo "$(( 123456789 ))"'  '123456789'
+       check 'IFS=37; echo $(( 123456789 ))'   '12 456 89'
+       check 'IFS=37; echo "$(( 123456789 ))"' '123456789'
+       check 'IFS=159; echo $(( 123456789 ))'  ' 234 678'
+
+       check 'IFS=5; set -- $(( 123456789 )); echo $#: $1 $2 $3 $4' \
+               '2: 1234 6789'
+       check 'IFS=5; set -- "$(( 123456789 ))"; echo $#: $1 $2 $3 $4' \
+               '1: 1234 6789'          # go ahead: explain it!
+       check 'IFS=5; set -- "$(( 123456789 ))"; echo "$#: $1 $2 $3 $4"' \
+               '1: 123456789   '       # ah!
+
+       check 'IFS=37; set -- $(( 123456789 )); echo $#: $1 $2 $3 $4' \
+               ' : 12 456 89'          # Tricky!
+       check 'IFS=5; set -- $(( 123456789 )); echo $#: $*' \
+               '2: 1234 6789'
+       check 'IFS=47; set -- $(( 123456789 )); echo $#: $*' \
+               '3: 123 56 89'
+       check 'IFS=5; set -- $(( 123456789 )); echo "$#: $*"' \
+               '2: 123456789'
+       check 'IFS=37; set -- $(( 123456789 )); echo "$#: $*"' \
+               '3: 123456389'  # [sic]
+       check 'IFS=5; set -- $(( 123456789 )); echo $#: $@' \
+               '2: 1234 6789'
+       check 'IFS=47; set -- $(( 123456789 )); echo $#: $@' \
+               '3: 123 56 89'
+       check 'IFS=5; set -- $(( 123456789 )); echo "$#: $@"' \
+               '2: 1234 6789'
+       check 'IFS=37; set -- $(( 123456789 )); echo "$#: $*"' \
+               '3: 123456389'  # [sic]
+
+       check 'IFS=1; set -- $(( 1111 )); echo "$#:" $*'        '4:   '
+       check 'IFS=" 1"; set -- $(( 1231231231 )); echo "$#: $*"' \
+               '4:  23 23 23'
+       check 'IFS="1 "; set -- $(( 1231231231 )); echo "$#: $*"' \
+               '4: 123123123'
+
+       check 'IFS=5; echo 5$(( 123456789 ))5'          '51234 67895'
+       check 'IFS=37; echo 73$(( 123456789 ))37'       '7312 456 8937'
+       check 'IFS=159; echo 11$(( 123456789 ))95'      '11 234 678 95'
+       check 'IFS="159 "; echo 11$(( 123456789 ))95'   '11 234 678 95'
+       check 'IFS="159 "; echo 11$(( 11234567899 ))95' '11  234 678  95'
+}
+
 atf_init_test_cases() {
        atf_add_test_case for
        atf_add_test_case default_val
@@ -365,4 +437,5 @@
        atf_add_test_case dollar_at
        atf_add_test_case ifs
        atf_add_test_case var_length
+       atf_add_test_case split_arith
 }



Home | Main Index | Thread Index | Old Index