363 lines
7.9 KiB
YAML
363 lines
7.9 KiB
YAML
name: "Arithmetic"
|
|||
|
|
cases:
|
||
|
|
- name: "Empty expression"
|
||
|
|
stdin: |
|
||
|
|
echo $(())
|
||
|
|
|
||
|
|
- name: "Unquoted arithmetic"
|
||
|
|
stdin: |
|
||
|
|
echo $((1+1))
|
||
|
|
|
||
|
|
- name: "Arithmetic literals"
|
||
|
|
stdin: |
|
||
|
|
echo "$((0))"
|
||
|
|
echo "$((1))"
|
||
|
|
echo "$((10))"
|
||
|
|
echo "$((010))"
|
||
|
|
echo "$((0010))"
|
||
|
|
echo "$((0x10))"
|
||
|
|
echo "$((0x010))"
|
||
|
|
|
||
|
|
- name: "Arithmetic literals with explicit bases"
|
||
|
|
stdin: |
|
||
|
|
echo "$((2#1010))"
|
||
|
|
|
||
|
|
echo "$((8#16))"
|
||
|
|
|
||
|
|
echo "$((16#faf))"
|
||
|
|
echo "$((16#FAF))"
|
||
|
|
|
||
|
|
echo "$((36#vvv))"
|
||
|
|
echo "$((36#VVV))"
|
||
|
|
|
||
|
|
# Base 37: A-Z map to 36-61
|
||
|
|
echo "$((37#a))"
|
||
|
|
echo "$((37#a0))"
|
||
|
|
echo "$((37#A))"
|
||
|
|
|
||
|
|
# Base 62: a-z=10-35, A-Z=36-61
|
||
|
|
echo "$((62#A))"
|
||
|
|
echo "$((62#a))"
|
||
|
|
echo "$((62#Z))"
|
||
|
|
echo "$((62#z))"
|
||
|
|
|
||
|
|
# Base 63: @ = 62
|
||
|
|
echo "$((63#@))"
|
||
|
|
echo "$((63#@9))"
|
||
|
|
|
||
|
|
# Base 64: _ = 63
|
||
|
|
echo "$((64#_))"
|
||
|
|
echo "$((64#@))"
|
||
|
|
echo "$((64#_1))"
|
||
|
|
echo "$((64#zzz))"
|
||
|
|
|
||
|
|
- name: "Unary arithmetic operators with space"
|
||
|
|
stdin: |
|
||
|
|
echo "$(( - 1 ))"
|
||
|
|
echo "$(( + 1 ))"
|
||
|
|
echo "$(( ~ 10 ))"
|
||
|
|
echo "$(( ! 10 ))"
|
||
|
|
|
||
|
|
- name: "Parentheses"
|
||
|
|
stdin: |
|
||
|
|
echo "$(((10)))"
|
||
|
|
echo "$((((10))))"
|
||
|
|
echo "$(((((10)))))"
|
||
|
|
|
||
|
|
echo "$(( (10) ))"
|
||
|
|
echo "$(( (1+2) ))"
|
||
|
|
echo "$(( (1 + 2) ))"
|
||
|
|
|
||
|
|
echo "$(( ((1+2)) ))"
|
||
|
|
echo "$(( ((1 + 2)) ))"
|
||
|
|
|
||
|
|
echo "$(((1+2)*3))"
|
||
|
|
echo "$(((1 + 2) * 3))"
|
||
|
|
echo "$(( (1 + 2) * 3 ))"
|
||
|
|
|
||
|
|
echo "$((((1+2)*3)))"
|
||
|
|
echo "$(( ((1 + 2) * 3) ))"
|
||
|
|
echo "$(( ( (1 + 2) * 3 ) ))"
|
||
|
|
|
||
|
|
- name: "Basic quoted arithmetic"
|
||
|
|
stdin: |
|
||
|
|
echo " 1 + 1 == $((1+1))"
|
||
|
|
echo " 2 * 3 == $((2*3))"
|
||
|
|
echo " 9 / 3 == $((9/3))"
|
||
|
|
echo "10 % 3 == $((10%3))"
|
||
|
|
echo " 2 ** 3 == $((2**3))"
|
||
|
|
echo " 2 | 4 == $((2|4))"
|
||
|
|
echo " 2 & 4 == $((2&4))"
|
||
|
|
echo " 2 ^ 3 == $((2^3))"
|
||
|
|
echo " 1 && 1 == $((1&&1))"
|
||
|
|
echo " 1 && 0 == $((1&&0))"
|
||
|
|
echo " 1 || 0 == $((1||0))"
|
||
|
|
echo " 0 || 1 == $((1||0))"
|
||
|
|
echo " 1 , 2 == $((1,2))"
|
||
|
|
|
||
|
|
- name: "Unary operators"
|
||
|
|
stdin: |
|
||
|
|
echo " -1 == $((-1))"
|
||
|
|
echo " +1 == $((+1))"
|
||
|
|
echo " ~10 == $((~10))"
|
||
|
|
echo " !10 == $((!10))"
|
||
|
|
|
||
|
|
- name: "Conditional operator"
|
||
|
|
stdin: |
|
||
|
|
echo "1 ? 2 : 3 == $((1?2:3))"
|
||
|
|
echo "0 ? 2 : 3 == $((0?2:3))"
|
||
|
|
|
||
|
|
- name: "Arithmetic with spacing"
|
||
|
|
stdin: |
|
||
|
|
echo $(( 75 + 68 ))
|
||
|
|
|
||
|
|
- name: "Divide by zero"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
echo "1 / 0 == $((1/0))"
|
||
|
|
echo "Result: $?"
|
||
|
|
|
||
|
|
echo "1 % 0 == $((1%0))"
|
||
|
|
echo "Result: $?"
|
||
|
|
|
||
|
|
- name: "Shift arithmetic"
|
||
|
|
stdin: |
|
||
|
|
echo "32 >> 2 == $((32>>2))"
|
||
|
|
echo " 1 << 4 == $((1<<4))"
|
||
|
|
|
||
|
|
- name: Shift arithmetic in conditional"
|
||
|
|
stdin: |
|
||
|
|
(( 1 >> 1 )) && echo "1. true"
|
||
|
|
(( 1 << 1 )) && echo "2. true"
|
||
|
|
|
||
|
|
- name: "Variable references"
|
||
|
|
stdin: |
|
||
|
|
x=10
|
||
|
|
echo "x => $((x))"
|
||
|
|
echo "x + 1 => $((x+1))"
|
||
|
|
|
||
|
|
y=
|
||
|
|
echo "y => $((y))"
|
||
|
|
echo "y + 1 => $((y+1))"
|
||
|
|
|
||
|
|
z=notnumber
|
||
|
|
echo "z => $((z))"
|
||
|
|
echo "z + 1 => $((z+1))"
|
||
|
|
|
||
|
|
- name: "Complex variable references"
|
||
|
|
stdin: |
|
||
|
|
x=10
|
||
|
|
y=20
|
||
|
|
z=x+y
|
||
|
|
a=z+z
|
||
|
|
|
||
|
|
echo "z => $((z))"
|
||
|
|
echo "a => $((a))"
|
||
|
|
|
||
|
|
- name: "Nested expressions"
|
||
|
|
stdin: |
|
||
|
|
echo "1: $(($(echo -n 1; echo 2) + 37))"
|
||
|
|
|
||
|
|
op="+"
|
||
|
|
echo "2: $((10 ${op} 20))"
|
||
|
|
|
||
|
|
expr="13 * 7"
|
||
|
|
echo "3: $(($expr))"
|
||
|
|
|
||
|
|
- name: "Assignment arithmetic"
|
||
|
|
stdin: |
|
||
|
|
x=0
|
||
|
|
|
||
|
|
echo "x = 1 => $((x = 1))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x += 3 => $((x += 3))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x -= 1 => $((x -= 1))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x *= 2 => $((x *= 2))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x++ == $((x++))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "++x == $((++x))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x-- == $((x--))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "--x == $((--x))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x |= 3 => $((x |= 3))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x &= 12 => $((x &= 12))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x %= 8 => $((x %= 8))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
echo "x ^= 7 => $((x ^= 7))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
- name: "Assignment with references"
|
||
|
|
stdin: |
|
||
|
|
x=10+3
|
||
|
|
echo "y = x => $((y = x))"
|
||
|
|
echo "y is now $y"
|
||
|
|
|
||
|
|
- name: "Assignments in logical boolean expressions"
|
||
|
|
stdin: |
|
||
|
|
x=0
|
||
|
|
echo "0 && x+=1 => $(( 0 && (x+=1) ))"
|
||
|
|
echo "x: $x"
|
||
|
|
|
||
|
|
x=0
|
||
|
|
echo "1 && x+=1 => $(( 1 && (x+=1) ))"
|
||
|
|
echo "x: $x"
|
||
|
|
|
||
|
|
x=0
|
||
|
|
echo "0 || x+=1 => $(( 0 || (x+=1) ))"
|
||
|
|
echo "x: $x"
|
||
|
|
|
||
|
|
x=0
|
||
|
|
echo "1 || x+=1 => $(( 1 || (x+=1) ))"
|
||
|
|
echo "x: $x"
|
||
|
|
|
||
|
|
- name: "Array arithmetic"
|
||
|
|
stdin: |
|
||
|
|
a=(1 2 3)
|
||
|
|
declare -p a
|
||
|
|
echo "a[0]: $((a[0]))"
|
||
|
|
echo "a[2]: $((a[2]))"
|
||
|
|
echo "a[3]: $((a[3]))"
|
||
|
|
|
||
|
|
echo "b[2]: $((b[2]))"
|
||
|
|
|
||
|
|
echo "a[1]=4 => $((a[1]=4))"
|
||
|
|
echo "a[1]: $((a[1]))"
|
||
|
|
|
||
|
|
echo "a[1]+=1 => $((a[1]+=1))"
|
||
|
|
echo "a[1]: $((a[1]))"
|
||
|
|
|
||
|
|
echo "c[1] += 3 => $((c[1] += 3))"
|
||
|
|
|
||
|
|
- name: "Basic arithmetic comparison"
|
||
|
|
stdin: |
|
||
|
|
echo "0 < 1: $((0 < 1))"
|
||
|
|
echo "0 <= 1: $((0 <= 1))"
|
||
|
|
echo "0 == 1: $((0 == 1))"
|
||
|
|
echo "0 != 1: $((0 != 1))"
|
||
|
|
echo "0 > 1: $((0 > 1))"
|
||
|
|
echo "0 >= 1: $((0 >= 1))"
|
||
|
|
echo "0 < 0: $((0 < 0))"
|
||
|
|
echo "0 <= 0: $((0 <= 0))"
|
||
|
|
echo "0 == 0: $((0 == 0))"
|
||
|
|
echo "0 != 0: $((0 != 0))"
|
||
|
|
echo "0 > 0: $((0 > 0))"
|
||
|
|
echo "0 >= 0: $((0 >= 0))"
|
||
|
|
echo "1 < 0: $((1 < 0))"
|
||
|
|
echo "1 <= 0: $((1 <= 0))"
|
||
|
|
echo "1 == 0: $((1 == 0))"
|
||
|
|
echo "1 != 0: $((1 != 0))"
|
||
|
|
echo "1 > 0: $((1 > 0))"
|
||
|
|
echo "1 >= 0: $((1 >= 0))"
|
||
|
|
|
||
|
|
- name: "Legacy bracket arithmetic syntax"
|
||
|
|
stdin: |
|
||
|
|
x=5
|
||
|
|
x=$[x + 1]
|
||
|
|
echo "x after increment: $x"
|
||
|
|
echo "Direct: $[1 + 2]"
|
||
|
|
|
||
|
|
- name: "Legacy bracket arithmetic in extended test"
|
||
|
|
stdin: |
|
||
|
|
number=4
|
||
|
|
[[ $[number % 2] == 0 ]] && echo "even" || echo "odd"
|
||
|
|
number=5
|
||
|
|
[[ $[number % 2] == 0 ]] && echo "even" || echo "odd"
|
||
|
|
|
||
|
|
- name: "Legacy bracket arithmetic in double-quoted string"
|
||
|
|
stdin: |
|
||
|
|
echo "Quoted: result: $[2 * 3]"
|
||
|
|
|
||
|
|
- name: "Legacy bracket arithmetic complex expression"
|
||
|
|
stdin: |
|
||
|
|
echo "Complex: $[1 + 2 * 3 - 4 / 2 % 2]"
|
||
|
|
|
||
|
|
- name: "Legacy bracket arithmetic with array subscript"
|
||
|
|
stdin: |
|
||
|
|
arr=(10 20 30)
|
||
|
|
echo "Array elem: $[arr[1] + 5]"
|
||
|
|
|
||
|
|
- name: "Prefix increment/decrement with space before lvalue"
|
||
|
|
stdin: |
|
||
|
|
x=5
|
||
|
|
echo "++ x => $(( ++ x ))"
|
||
|
|
echo "x is now $x"
|
||
|
|
echo "-- x => $(( -- x ))"
|
||
|
|
echo "x is now $x"
|
||
|
|
|
||
|
|
# Also test in (( )) command form
|
||
|
|
y=10
|
||
|
|
(( ++ y ))
|
||
|
|
echo "y after ++ y: $y"
|
||
|
|
(( -- y ))
|
||
|
|
echo "y after -- y: $y"
|
||
|
|
|
||
|
|
- name: "INT64_MIN and wrapping arithmetic"
|
||
|
|
stdin: |
|
||
|
|
# INT64_MIN via unary minus of the literal
|
||
|
|
echo "$(( -9223372036854775808 ))"
|
||
|
|
|
||
|
|
# Wrapping negation of INT64_MIN
|
||
|
|
echo "$(( - (-9223372036854775808) ))"
|
||
|
|
|
||
|
|
# INT64_MIN % -1 should be 0 (not crash)
|
||
|
|
echo "$(( (-9223372036854775808) % (-1) ))"
|
||
|
|
|
||
|
|
# INT64_MIN / -1 wraps
|
||
|
|
echo "$(( (-9223372036854775808) / (-1) ))"
|
||
|
|
|
||
|
|
# Wrapping increment/decrement near boundaries
|
||
|
|
echo "$(( 9223372036854775807 + 1 ))" # wraps to INT64_MIN
|
||
|
|
|
||
|
|
- name: "Non-cyclic variable dereference chain"
|
||
|
|
stdin: |
|
||
|
|
a=b
|
||
|
|
b=c
|
||
|
|
c=42
|
||
|
|
echo "$((a))"
|
||
|
|
|
||
|
|
- name: "Self-referencing variable in arithmetic"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
a=a
|
||
|
|
echo "$(( a ))"
|
||
|
|
echo "exit: $?"
|
||
|
|
|
||
|
|
- name: "Recursive variable evaluation with depth limit"
|
||
|
|
ignore_stderr: true
|
||
|
|
stdin: |
|
||
|
|
# Recursive variables should not cause stack overflow
|
||
|
|
a=b
|
||
|
|
b=a
|
||
|
|
echo "$(( a ))"
|
||
|
|
echo "exit: $?"
|
||
|
|
|
||
|
|
- name: "Arithmetic with nameref variable"
|
||
|
|
known_failure: true
|
||
|
|
stdin: |
|
||
|
|
counter=10
|
||
|
|
declare -n ref=counter
|
||
|
|
echo "before: $counter"
|
||
|
|
(( ref++ ))
|
||
|
|
echo "after ++: $counter"
|
||
|
|
(( ref += 5 ))
|
||
|
|
echo "after +=5: $counter"
|
||
|
|
echo "expr: $(( ref * 2 ))"
|