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 ))"
