name: "Builtins: test"
cases:
  - name: "test: = operator"
    stdin: |
      shopt -u nocasematch
      test "ab" = "ab" && echo "ab = ab"
      test "ab" = "AB" && echo "ab = AB"
      test "ab" = "cd" && echo "ab = cd"
      test "ab" = "a?" && echo "ab = a?"

      shopt -s nocasematch
      test "ab" = "ab" && echo "ab = ab"
      test "ab" = "AB" && echo "ab = AB"
      test "ab" = "cd" && echo "ab = cd"
      test "ab" = "a?" && echo "ab = a?"

  - name: "test: == operator"
    stdin: |
      shopt -u nocasematch
      test "ab" == "ab" && echo "ab == ab"
      test "ab" == "AB" && echo "ab == AB"
      test "ab" == "cd" && echo "ab == cd"
      test "ab" == "a?" && echo "ab == a?"

      shopt -s nocasematch
      test "ab" == "ab" && echo "ab == ab"
      test "ab" == "AB" && echo "ab == AB"
      test "ab" == "cd" && echo "ab == cd"
      test "ab" == "a?" && echo "ab == a?"

  - name: "test: files refer to same device and inode"
    stdin: |
      [ /bin/sh -ef /bin/sh ] && echo "-ef correctly identified device and inode numbers"

      [ ! /etc/os-release -ef /bin/sh ] && echo "-ef correctly identified device and inode numbers that do not match"

  - name: "test: file is newer"
    stdin: |
      touch -d "2 hours ago" bar
      touch foo

      [ foo -nt bar ] && echo "-nt correctly identified newer file"
      [ foo -nt foo ] && echo "-nt incorrectly identified file as newer than itself"
      [ foo -nt file_no_exists ] && echo "-nt correctly identified when file2 does not exist"

  - name: "test: file is older"
    stdin: |
      touch -d "2 hours ago" foo
      touch bar

      [ foo -ot bar ] && echo "-ot correctly identified older file"
      [ foo -ot foo ] && echo "-ot incorrectly identified file as older than itself"
      [ file_no_exists -ot foo ] && echo "-ot correctly identified when file1 does not exist"

  - name: "test: parens"
    stdin: |
      test \( "a" = "a" \) && echo "Parens work"

  - name: "test: -- string"
    stdin: |
      test --
      echo "Result(test): $?"

      [ -- ]
      echo "Result([): $?"

  - name: "test: invalid operators"
    ignore_stderr: true
    stdin: |
      test - -
      echo "Result: $?"

  # String operators
  - name: "test: != operator"
    stdin: |
      test "ab" != "cd" && echo "ab != cd"
      test "ab" != "ab" && echo "ab != ab"
      test "" != "x" && echo "empty != x"

  - name: "test: -z operator (zero length)"
    stdin: |
      test -z "" && echo "-z empty"
      test -z "x" && echo "-z x"
      unset VAR
      test -z "$VAR" && echo "-z unset"

  - name: "test: -n operator (non-zero length)"
    stdin: |
      test -n "x" && echo "-n x"
      test -n "" && echo "-n empty"
      VAR="hello"
      test -n "$VAR" && echo "-n set"

  - name: "test: < operator (string sort before)"
    stdin: |
      test "a" \< "b" && echo "a < b"
      test "b" \< "a" && echo "b < a"
      test "abc" \< "abd" && echo "abc < abd"
      test "a" \< "a" && echo "a < a"

  - name: "test: > operator (string sort after)"
    stdin: |
      test "b" \> "a" && echo "b > a"
      test "a" \> "b" && echo "a > b"
      test "abd" \> "abc" && echo "abd > abc"
      test "a" \> "a" && echo "a > a"

  # Arithmetic comparison operators
  - name: "test: -eq operator"
    stdin: |
      test 5 -eq 5 && echo "5 -eq 5"
      test 5 -eq 6 && echo "5 -eq 6"
      test -1 -eq -1 && echo "-1 -eq -1"
      test 0 -eq 0 && echo "0 -eq 0"

  - name: "test: -ne operator"
    stdin: |
      test 5 -ne 6 && echo "5 -ne 6"
      test 5 -ne 5 && echo "5 -ne 5"
      test -1 -ne 1 && echo "-1 -ne 1"

  - name: "test: -lt operator"
    stdin: |
      test 3 -lt 5 && echo "3 -lt 5"
      test 5 -lt 3 && echo "5 -lt 3"
      test 5 -lt 5 && echo "5 -lt 5"
      test -2 -lt -1 && echo "-2 -lt -1"

  - name: "test: -le operator"
    stdin: |
      test 3 -le 5 && echo "3 -le 5"
      test 5 -le 5 && echo "5 -le 5"
      test 6 -le 5 && echo "6 -le 5"
      test -2 -le -2 && echo "-2 -le -2"

  - name: "test: -gt operator"
    stdin: |
      test 5 -gt 3 && echo "5 -gt 3"
      test 3 -gt 5 && echo "3 -gt 5"
      test 5 -gt 5 && echo "5 -gt 5"
      test -1 -gt -2 && echo "-1 -gt -2"

  - name: "test: -ge operator"
    stdin: |
      test 5 -ge 3 && echo "5 -ge 3"
      test 5 -ge 5 && echo "5 -ge 5"
      test 3 -ge 5 && echo "3 -ge 5"
      test -1 -ge -1 && echo "-1 -ge -1"

  # File existence and type operators
  - name: "test: -e operator (file exists)"
    stdin: |
      touch testfile
      test -e testfile && echo "-e existing file"
      test -e nonexistent && echo "-e nonexistent"
      mkdir testdir
      test -e testdir && echo "-e existing dir"

  - name: "test: -a operator (file exists, deprecated)"
    stdin: |
      touch testfile
      test -a testfile && echo "-a existing file"
      test -a nonexistent && echo "-a nonexistent"

  - name: "test: -f operator (regular file)"
    stdin: |
      touch testfile
      test -f testfile && echo "-f regular file"
      mkdir testdir
      test -f testdir && echo "-f directory"
      test -f nonexistent && echo "-f nonexistent"

  - name: "test: -d operator (directory)"
    stdin: |
      mkdir testdir
      test -d testdir && echo "-d directory"
      touch testfile
      test -d testfile && echo "-d regular file"
      test -d nonexistent && echo "-d nonexistent"

  - name: "test: -h and -L operators (symbolic link)"
    stdin: |
      touch target
      ln -s target symlink
      test -h symlink && echo "-h symlink"
      test -L symlink && echo "-L symlink"
      test -h target && echo "-h regular file"
      test -L target && echo "-L regular file"
      test -h nonexistent && echo "-h nonexistent"

  - name: "test: -p operator (named pipe/FIFO)"
    stdin: |
      touch testfile
      test -p testfile && echo "-p regular file"
      test -p nonexistent && echo "-p nonexistent"

  - name: "test: -S operator (socket)"
    stdin: |
      touch testfile
      test -S testfile && echo "-S regular file"
      test -S nonexistent && echo "-S nonexistent"

  - name: "test: -b operator (block device)"
    stdin: |
      touch testfile
      test -b testfile && echo "-b regular file"
      test -b nonexistent && echo "-b nonexistent"
      # Block devices exist in /dev but may vary by system

  - name: "test: -c operator (character device)"
    stdin: |
      touch testfile
      test -c testfile && echo "-c regular file"
      test -c nonexistent && echo "-c nonexistent"

  # File permission operators
  - name: "test: -r operator (readable)"
    stdin: |
      touch testfile
      test -r testfile && echo "-r readable"
      test -r nonexistent && echo "-r nonexistent"

  - name: "test: -w operator (writable)"
    stdin: |
      touch testfile
      test -w testfile && echo "-w writable"
      test -w nonexistent && echo "-w nonexistent"

  - name: "test: -x operator (executable)"
    stdin: |
      touch testfile
      test -x testfile && echo "-x executable"

  - name: "test: -s operator (size greater than zero)"
    stdin: |
      echo "content" > nonempty
      test -s nonempty && echo "-s nonempty"
      touch empty
      test -s empty && echo "-s empty"
      test -s nonexistent && echo "-s nonexistent"

  # Variable and option operators
  - name: "test: -v operator (variable is set)"
    stdin: |
      VAR="hello"
      test -v VAR && echo "-v set variable"
      unset VAR
      test -v VAR && echo "-v unset variable"
      VAR=""
      test -v VAR && echo "-v empty variable"

  - name: "test: -R operator (nameref variable)"
    stdin: |
      VAR="value"
      declare -n REF=VAR
      test -R REF && echo "-R nameref"
      test -R VAR && echo "-R regular var"
      unset REF VAR

  - name: "test: -o operator (shell option)"
    stdin: |
      set -e
      test -o errexit && echo "-o errexit enabled"
      set +e
      test -o errexit && echo "-o errexit disabled"
      test -o nonexistentoption && echo "-o nonexistent"

  # Logical operators
  - name: "test: ! operator (negation)"
    stdin: |
      test ! "a" = "b" && echo "! a=b"
      test ! "a" = "a" && echo "! a=a"
      test ! -e nonexistent && echo "! -e nonexistent"
      test ! -e / && echo "! -e /"

  - name: "test: -a operator (logical AND)"
    stdin: |
      test "a" = "a" -a "b" = "b" && echo "true -a true"
      test "a" = "a" -a "b" = "c" && echo "true -a false"
      test "a" = "b" -a "c" = "c" && echo "false -a true"
      test "a" = "b" -a "c" = "d" && echo "false -a false"

  - name: "test: -o operator (logical OR)"
    stdin: |
      test "a" = "a" -o "b" = "b" && echo "true -o true"
      test "a" = "a" -o "b" = "c" && echo "true -o false"
      test "a" = "b" -o "c" = "c" && echo "false -o true"
      test "a" = "b" -o "c" = "d" && echo "false -o false"

  - name: "test: complex logical expressions"
    stdin: |
      test \( "a" = "a" -o "b" = "c" \) -a "d" = "d" && echo "complex 1"
      test ! \( "a" = "b" \) && echo "complex 2"
      test "a" = "a" -a \( "b" = "b" -o "c" = "d" \) && echo "complex 3"

  # Edge cases
  - name: "test: single argument (non-empty string is true)"
    stdin: |
      test "hello" && echo "non-empty is true"
      test "" && echo "empty is true"
      test "0" && echo "zero string is true"

  - name: "test: no arguments"
    stdin: |
      test
      echo "no args: $?"

  - name: "test: special characters in strings"
    stdin: |
      test "hello world" = "hello world" && echo "spaces match"
      test "a	b" = "a	b" && echo "tabs match"
      test 'a"b' = 'a"b' && echo "quotes match"
      test "a'b" = "a'b" && echo "single quotes match"

  - name: "test: arithmetic comparison with spaces/tabs in operand"
    stdin: |
      # Leading/trailing spaces
      test 0 -eq ' 0'
      echo "leading space: $?"

      test 0 -eq '0 '
      echo "trailing space: $?"

      test 0 -eq ' 0 '
      echo "both spaces: $?"

      # Tabs
      test 0 -eq '	0'
      echo "leading tab: $?"

      test 0 -eq '0	'
      echo "trailing tab: $?"

  - name: "test: arithmetic comparison with newline in operand"
    min_oracle_version: "5.3"
    stdin: |
      # Newline trimming seems to have changed in or around bash 5.3
      test 0 -eq ' 0
      '
      echo "newline trailing: $?"

  - name: "test: -t operator with whitespace in fd"
    stdin: |
      # -t operator should trim whitespace before parsing fd number
      # These should all behave identically (false since not a terminal)
      test -t 0
      r1=$?
      test -t ' 0'
      r2=$?
      test -t '0 '
      r3=$?
      test -t ' 0 '
      r4=$?

      # All should have the same result
      [ $r1 -eq $r2 ] && [ $r2 -eq $r3 ] && [ $r3 -eq $r4 ] && echo "All -t results match"

