Home | History | Annotate | Line # | Download | only in sh
t_shift.sh revision 1.3
      1 # $NetBSD: t_shift.sh,v 1.3 2024/09/21 20:48:50 kre Exp $
      2 #
      3 # Copyright (c) 2016 The NetBSD Foundation, Inc.
      4 # All rights reserved.
      5 #
      6 # Redistribution and use in source and binary forms, with or without
      7 # modification, are permitted provided that the following conditions
      8 # are met:
      9 # 1. Redistributions of source code must retain the above copyright
     10 #    notice, this list of conditions and the following disclaimer.
     11 # 2. Redistributions in binary form must reproduce the above copyright
     12 #    notice, this list of conditions and the following disclaimer in the
     13 #    documentation and/or other materials provided with the distribution.
     14 #
     15 # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     16 # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     17 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     18 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     19 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     20 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     21 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     23 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     24 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     25 # POSSIBILITY OF SUCH DAMAGE.
     26 #
     27 # the implementation of "sh" to test
     28 : ${TEST_SH:="/bin/sh"}
     29 
     30 atf_test_case basic_shift_test
     31 basic_shift_test_head() {
     32 	atf_set "descr" "Test correct operation of valid shifts"
     33 }
     34 basic_shift_test_body() {
     35 
     36 	for a in			\
     37 	  "one-arg::0:one-arg"		\
     38 	  "one-arg:--:0:one-arg"	\
     39 	  "one-arg:1:0:one-arg"		\
     40 	  "one-arg:-- 1:0:one-arg"	\
     41 	  "one-arg:-- 0:1 one-arg"	\
     42 	  "a b c::2 b c:a"		\
     43 	  "a b c:1:2 b c:a"		\
     44 	  "a b c:2:1 c:a:b"		\
     45 	  "a b c:3:0:a:b:c"		\
     46 	  "a b c:0:3 a b c"		\
     47 	  "a b c d e f g h i j k l m n o p:1:15 b c d e f g h i j k l m n o p"\
     48 	  "a b c d e f g h i j k l m n o p:9:7 j k l m n o p:a:b:c:g:h:i"     \
     49 	  "a b c d e f g h i j k l m n o p:13:3 n o p:a:b:c:d:k:l:m"	      \
     50 	  "a b c d e f g h i j k l m n o p:16:0:a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p"
     51 	do
     52 		oIFS="${IFS}"
     53 		IFS=:; set -- $a
     54 		IFS="${oIFS}"
     55 
     56 		init="$1"; n="$2"; res="$3"; shift 3
     57 
     58 		not=
     59 		for b
     60 		do
     61 			not="${not} -o not-match:$b"
     62 		done
     63 
     64 		atf_check -s exit:0 -o "match:${res}" ${not} -e empty \
     65 			${TEST_SH} -c "set -- ${init}; shift $n;"' echo "$# $*"'
     66 	done
     67 
     68 	atf_check -s exit:0 -o match:complete -o not-match:ERR -e empty \
     69 		${TEST_SH} -c \
     70     'set -- a b c d e;while [ $# -gt 0 ];do shift||echo ERR;done;echo complete'
     71 }
     72 
     73 atf_test_case basic_rotate
     74 basic_rotate_head() {
     75 	atf_set "descr" "Test correct operation of valid rotates"
     76 }
     77 basic_rotate_body() {
     78 
     79 	for a in			\
     80 	  "one-arg:-0:1 one-arg"	\
     81 	  "one-arg:-1:1 one-arg"	\
     82 	  "one-arg:-- -1:1 one-arg"	\
     83 	  "a b c:-1:3 c a b"		\
     84 	  "a b c:-2:3 b c a"		\
     85 	  "a b c:-3:3 a b c"		\
     86 	  "a b c:-- -3:3 a b c"		\
     87 	  "a b c:-0:3 a b c"		\
     88 	  "a b c d e f g h i j k l m n o:-1:15 o a b c d e f g h i j k l m n" \
     89 	  "a b c d e f g h i j k l m n o:-2:15 n o a b c d e f g h i j k l m" \
     90 	  "a b c d e f g h i j k l m n o:-9:15 g h i j k l m n o a b c d e f" \
     91 	  "a b c d e f g h i j k l m n o:-13:15 c d e f g h i j k l m n o a b" \
     92 	  "a b c d e f g h i j k l m n o:-14:15 b c d e f g h i j k l m n o a" \
     93 	  "a b c d e f g h i j k l m n o:-15:15 a b c d e f g h i j k l m n o"
     94 	do
     95 		oIFS="${IFS}"
     96 		IFS=:; set -- $a
     97 		IFS="${oIFS}"
     98 
     99 		init="$1"; n="$2"; res="$3"; shift 3
    100 
    101 		atf_check -s exit:0 -o "match:${res}" -e empty \
    102 			${TEST_SH} -c "set -- ${init}; shift $n;"' echo "$# $*"'
    103 	done
    104 }
    105 
    106 atf_test_case excessive_shift
    107 excessive_shift_head() {
    108 	atf_set "descr" "Test acceptable operation of shift too many"
    109 }
    110 # In:
    111 #
    112 #	http://pubs.opengroup.org/onlinepubs/9699919799
    113 #		/utilities/V3_chap02.html#tag_18_26_01
    114 #
    115 # (that URL should be one line, with the /util... immediately after ...9799)
    116 #
    117 # POSIX says of shift (in the "EXIT STATUS" paragraph):
    118 #
    119 #  If the n operand is invalid or is greater than "$#", this may be considered
    120 #  a syntax error and a non-interactive shell may exit; if the shell does not
    121 #  exit in this case, a non-zero exit status shall be returned.
    122 #  Otherwise, zero shall be returned.
    123 #
    124 # NetBSD's sh treats it as an error and exits (if non-interactive, as here),
    125 # other shells do not.
    126 #
    127 # Either behaviour is acceptable - so the test allows for both
    128 # (and checks that if the shell does not exit, "shift" returns status != 0)
    129 
    130 excessive_shift_body() {
    131 	for a in				\
    132 		"one-arg:2"			\
    133 		"one-arg:4"			\
    134 		"one-arg:13"			\
    135 		"one two:3"			\
    136 		"one two:7"			\
    137 		"one two three four five:6"	\
    138 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:16"	\
    139 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:17"	\
    140 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:30"	\
    141 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:9999"
    142 	do
    143 		oIFS="${IFS}"
    144 		IFS=:; set -- $a
    145 		IFS="${oIFS}"
    146 
    147 		atf_check -s not-exit:0 -o match:OK -o not-match:ERR \
    148 			-e ignore ${TEST_SH} -c \
    149 			"set -- $1 ;"'echo OK:$#-'"$2;shift $2 && echo ERR"
    150 	done
    151 }
    152 
    153 atf_test_case excessive_rotate
    154 excessive_rotate_head() {
    155 	atf_set "descr" "Test acceptable operation of rotate too many"
    156 }
    157 
    158 excessive_rotate_body() {
    159 	for a in				\
    160 		"one-arg:2"			\
    161 		"one-arg:4"			\
    162 		"one-arg:13"			\
    163 		"one two:3"			\
    164 		"one two:7"			\
    165 		"one two three four five:6"	\
    166 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:16"	\
    167 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:17"	\
    168 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:30"	\
    169 		"I II III IV V VI VII VIII IX X XI XII XIII XIV XV:9999"
    170 	do
    171 		oIFS="${IFS}"
    172 		IFS=:; set -- $a
    173 		IFS="${oIFS}"
    174 
    175 		atf_check -s not-exit:0 -o match:OK -o not-match:ERR \
    176 			-e ignore ${TEST_SH} -c \
    177 			"set -- $1 ;echo OK:$#:-$2; shift -$2 && echo ERR"
    178 	done
    179 }
    180 
    181 atf_test_case function_shift
    182 function_shift_head() {
    183 	atf_set "descr" "Test that shift in a function does not affect outside"
    184 }
    185 function_shift_body() {
    186 	: # later...
    187 }
    188 
    189 atf_test_case non_numeric_shift
    190 non_numeric_shift_head() {
    191 	atf_set "descr" "Test that non-numeric args to shift are detected"
    192 }
    193 
    194 # from the DESCRIPTION section at the URL mentioned with the excessive_shift
    195 # test:
    196 #
    197 #	The value n shall be an unsigned decimal integer ...
    198 #
    199 # That is not hex (octal will be treated as if it were decimal, a leading 0
    200 # will simply be ignored - we test for this by giving an "octal" value that
    201 # would be OK if parsed as octal, but not if parsed (correctly) as decimal)
    202 #
    203 # Obviously total trash like roman numerals or alphabetic strings are out.
    204 #
    205 # Also no signed values (no + or -) and not a string that looks kind of like
    206 # a number,  but only if you're generous
    207 #
    208 # But as the EXIT STATUS section quoted above says, with an invalid 'n'
    209 # the shell has the option of exiting, or returning status != 0, so
    210 # again this test allows both.
    211 
    212 non_numeric_shift_body() {
    213 
    214 	# there are 9 args set, 010 is 8 if parsed octal, 10 decimal
    215 	for a in a I 0x12 010 5V ' ' '' +1 ' 1'
    216 	do
    217 		atf_check -s not-exit:0 -o empty -e ignore ${TEST_SH} -c \
    218 			"set -- a b c d e f g h i; shift '$a' && echo ERROR"
    219 		atf_check -s not-exit:0 -o empty -e ignore ${TEST_SH} -c \
    220 			"set -- a b c d e f g h i; shift -- '$a' && echo ERROR"
    221 	done
    222 }
    223 
    224 atf_test_case too_many_args
    225 too_many_args_head() {
    226 	# See PR bin/50896
    227 	atf_set "descr" "Test that sh detects invalid extraneous args to shift"
    228 }
    229 # This is a syntax error, a non-interactive shell (us) must exit $? != 0
    230 too_many_args_body() {
    231 	# This tests the bug in PR bin/50896 is fixed
    232 
    233 	for a in "1 1" "1 0" "1 2 3" "1 foo" "1 --" "-- 1 2" "-1 2"
    234 	do
    235 		atf_check -s not-exit:0 -o empty -e not-empty ${TEST_SH} -c \
    236 			" set -- a b c d; shift ${a} ; echo FAILED "
    237 	done
    238 }
    239 
    240 atf_init_test_cases() {
    241 	atf_add_test_case basic_shift_test
    242 	atf_add_test_case excessive_shift
    243 	atf_add_test_case function_shift
    244 	atf_add_test_case non_numeric_shift
    245 	atf_add_test_case too_many_args
    246 	atf_add_test_case basic_rotate
    247 	atf_add_test_case excessive_rotate
    248 }
    249