name: "Builtins: declare"
common_test_files:
  - path: "helpers.sh"
    contents: |
      stable_print_assoc_array() {
          # TODO(nameref): enable use of nameref when implemented; for now
          # we assume the name of the array is assoc_array
          # local -n assoc_array=$1
          local key

          for key in $(printf "%s\n" "${!assoc_array[@]}" | sort -n); do
              echo "\"${key}\" => ${assoc_array[${key}]}"
          done
      }

cases:
  - name: "Display vars"
    stdin: |
      declare myvar=something
      declare -p myvar

      myarr=(a b c)
      declare -p myarr

  - name: "Display vars with interesting chars"
    stdin: |
      (testvar="\"abc\"" && declare -p testvar && declare | grep testvar=)
      echo "-------------------------"
      (testvar="a b c" && declare -p testvar && declare | grep testvar=)
      echo "-------------------------"
      (testvar="'" && declare -p testvar && declare | grep testvar=)

  - name: "Display vars with interesting chars 2"
    min_oracle_version: 5.2 # some sequences render differently in older shell versions
    stdin: |
      (testvar=$'a\nb' && declare -p testvar && declare | grep testvar=)
      echo "-------------------------"
      (testvar=$'\x03' && declare -p testvar && declare | grep testvar=)
      echo "-------------------------"
      (testvar=$'\x08' && declare -p testvar && declare | grep testvar=)
      echo "-------------------------"
      (testvar=$(printf '\033[34mabc\033[0m') && declare -p testvar && declare | grep testvar=)

  - name: "Declare integer"
    stdin: |
      declare -i num=10
      declare -p num

      echo $num
      num+=10
      echo $num

      declare +i num
      declare -p num

      echo $num
      num+=10
      echo $num

  - name: "Declare integer with non-integer string"
    stdin: |
      declare -i var=value
      declare -p var

  - name: "Update integer with non-integer string"
    stdin: |
      declare -i var=10
      declare -p var

      var=value
      declare -p var

  - name: "Update integer array with non-integer string"
    stdin: |
      declare -ai arr=()
      declare -p arr

      arr[0]="value"
      declare -p arr

  - name: "Update integer array with non-integer string"
    stdin: |
      declare -Ai arr=()
      declare -p arr

      arr['key']="value"
      declare -p arr

  - name: "Declare readonly variable"
    ignore_stderr: true
    stdin: |
      declare -r var="readonly"
      declare -p var

      echo $var

      var="change"
      echo "change result: $?"
      echo "var: ${var}"

      declare +r var
      echo "+r result: $?"
      declare -p var

  - name: "Declare array"
    stdin: |
      declare -a arr=("element1" "element2" "element3")
      declare -p arr
      echo "[0]: ${arr[0]}"
      echo "[1]: ${arr[0]}"
      echo "[2]: ${arr[0]}"
      echo "[3]: ${arr[0]}"
      echo "STAR: ${arr[*]}"
      echo "AT: ${arr[*]}"

  - name: "Declare associative array"
    stdin: |
      declare -A arr=(["x1"]=1 ["x2"]=2)
      declare -p arr
      echo "[x]: ${arr[x1]}"
      echo "[y]: ${arr[x2]}"
      echo "[z]: ${arr[x3]}"
      echo "STAR: ${arr[*]}"
      echo "AT: ${arr[*]}"

  - name: "Declare and export variable"
    stdin: |
      declare -x myexportedvar="exported variable"
      env | grep myexportedvar

  - name: "Declare and export unset variable"
    stdin: |
      declare -x myunsetexportedvar
      env | grep myunsetexportedvar
      set | grep myunsetexportedvar=

  - name: "Re-declaring variable"
    stdin: |
      var="value"
      declare var
      echo "var: ${var}"

  - name: "Declaring without value"
    stdin: |
      [[ -v var ]] && echo "1: Variable is set"
      declare var
      declare -p var
      [[ -v var ]] && echo "2: Variable is set"
      declare var2=""
      declare -p var2
      [[ -v var2 ]] && echo "3: Variable is set"

  - name: "Displaying local vars"
    stdin: |
      function test {
          echo "Dumping local variables (should be empty)"
          local -p

          local -i int_var=10
          local -A assoc_array=(["x1"]=1 ["x2"]=2)
          local -a array=(a b c)
          local -r ro_var="readonly"
          local -t traced="value"

          echo "Dump all variables"
          local -p
      }

      test

  - name: "Using local to detect function presence"
    stdin: |
      function test {
        local something 2>/dev/null && echo "In function"
      }

      local something 2>/dev/null || echo "Not in function"

      test

  - name: "Displaying function names"
    stdin: |
      echo "Dumping function names"
      declare -F
      declare -p -F

      function test {
        :
      }

      echo "Dumping function names again"
      declare -F
      declare -p -F

      echo "Dumping test"
      declare -F test
      declare -p -F test

  - name: "Displaying functions"
    stdin: |
      echo "Dumping functions"
      declare -f
      declare -p -f

      function test {
        :
      }

      echo "Dumping functions again"
      declare -f
      declare -p -f

      echo "Dumping test"
      declare -f test
      declare -p -f test

  - name: "Displaying non-existent functions"
    stdin: |
      declare -f not_a_function
      echo "Result (-f): $?"

      declare -F not_a_function
      echo "Result (-F): $?"

  - name: "Valid conversions"
    stdin: |
      declare -a arr1=(a b c)
      declare -a arr1
      echo "Conversion result: $?"
      declare -p arr1

      declare -A arr2=(["x1"]=1 ["x2"]=2)
      declare -A arr2
      echo "Conversion result: $?"
      declare -p arr2

      declare scalar1="value"
      declare -a scalar1
      echo "Conversion result: $?"
      declare -p scalar1

      declare scalar2="value"
      declare -A scalar2
      echo "Conversion result: $?"
      declare -p scalar2

  - name: "Bad conversions"
    ignore_stderr: true
    stdin: |
      declare -a arr1=(a b c)
      declare -A arr1
      echo "Conversion result: $?"
      declare -p arr1

      declare -A arr2=(["x1"]=1 ["x2"]=2)
      declare -a arr2
      echo "Conversion result: $?"
      declare -p arr2

  - name: "Declare -p using invalid forms"
    ignore_stderr: true
    stdin: |
      declare arr=(a b c)
      declare -p arr[0]
      echo "Result: $?"
      declare -p arr[0]=1
      echo "Result: $?"

      declare scalar=x
      echo "Result: $?"
      declare -p scalar=y
      echo "Result: $?"

  - name: "Updating value"
    stdin: |
      declare var="value"
      declare -p var
      declare var="changed"
      declare -p var

  - name: "Updating value attributes"
    stdin: |
      declare -ix var=10
      declare -p var
      declare +ix var
      declare -p var

  - name: "Updating array"
    stdin: |
      declare arr=(a b c)
      declare -p arr
      declare arr=(d e)
      declare -p arr
      declare arr=10
      declare -p arr

      declare arr2=a
      declare -p arr2
      declare -A arr2=(["key"]="value")
      declare -p arr2

  - name: "Updating causing conversion"
    stdin: |
      source helpers.sh

      declare assoc_array="scalar-value"
      declare -p assoc_array

      declare -A assoc_array["key"]="key-value"
      stable_print_assoc_array assoc_array

  - name: "Uppercase attribute"
    stdin: |
      declare var=value

      declare -u var
      declare -p var

      var="abcd"
      declare -p var

      declare another="abcd"
      declare -u another
      another+=efg
      declare -p another

  - name: "Lowercase attribute"
    stdin: |
      declare var=value

      declare -l var
      declare -p var

      var="AbCd"
      declare -p var

      declare another="ABCD"
      declare -l another
      another+=EFG
      declare -p another

  - name: "Capitalize attribute"
    stdin: |
      declare var=value

      declare -c var
      declare -p var

      var="aBcD eFg"
      declare -p var

      declare another="aBcD"
      declare -c another
      another+=eFg
      declare -p another

  - name: "Declare invalid identifiers"
    ignore_stderr: true
    stdin: |
      declare 1=x && echo "Set 1"
      declare @=10 && echo "Set @"

  - name: "Nameref declare -p shows nameref attribute"
    stdin: |
      target="hello"
      declare -n ref=target
      declare -p ref
      declare -p target

  - name: "Nameref declare -n with initial value"
    known_failure: true
    stdin: |
      target="original"
      declare -n ref=target
      echo "ref: $ref"
      echo "target: $target"

  - name: "Nameref remove attribute with +n"
    known_failure: true
    stdin: |
      target="value"
      declare -n ref=target
      echo "as nameref: $ref"
      declare +n ref
      echo "after +n: ref=$ref"
      declare -p ref

  - name: "Nameref to array via declare"
    known_failure: true
    stdin: |
      arr=(one two three)
      declare -n ref=arr
      echo "ref[0]: ${ref[0]}"
      echo "ref[1]: ${ref[1]}"
      echo "ref[@]: ${ref[@]}"
      echo "ref[*]: ${ref[*]}"

  - name: "Nameref array modification via declare"
    known_failure: true
    stdin: |
      arr=(a b c)
      declare -n ref=arr
      ref[1]="modified"
      echo "arr[1]: ${arr[1]}"
      echo "ref[1]: ${ref[1]}"

  - name: "Nameref to associative array via declare"
    known_failure: true
    stdin: |
      declare -A assoc=(["key1"]="val1" ["key2"]="val2")
      declare -n ref=assoc
      echo "ref[key1]: ${ref[key1]}"
      echo "ref[key2]: ${ref[key2]}"

  - name: "Nameref array iteration in function via local -n"
    known_failure: true
    stdin: |
      print_array() {
          local -n arr=$1
          echo "count: ${#arr[@]}"
          for elem in "${arr[@]}"; do
              echo "elem: $elem"
          done
      }

      myarr=(first second third)
      print_array myarr

  - name: "Nameref get keys via declare"
    known_failure: true
    stdin: |
      declare -A assoc=(["a"]=1 ["b"]=2 ["c"]=3)
      declare -n ref=assoc
      echo "keys (sorted): $(printf '%s\n' ${!ref[@]} | sort | tr '\n' ' ')"
      echo "count: ${#ref[@]}"

  - name: "Nameref array length via declare"
    known_failure: true
    stdin: |
      arr=(one two three four five)
      declare -n ref=arr
      echo "length: ${#ref[@]}"
      echo "first element length: ${#ref[0]}"

  - name: "Nameref declare -n filter"
    stdin: |
      regular="plain"
      declare -n ref1=regular
      declare -n ref2=regular
      not_a_ref="also plain"
      declare -p -n 2>/dev/null | sort
