#!/usr/bin/env bash

# test if the expansion rules from posix interpretation 888 are
# invariant under various transformations

# for the associative array tests to work, all of the `set --'
# commands in exp9.sub must provide the positional parameters
# in the same order as the order in which associative array key
# expansion will return them. e.g.: 
#   set "jkl" "def ghi" "abc"

do_diff() {
   # commands to append to `set' statements
   local set='/^set /s/$/; '"$1"'/'
   # replacements for $* and $@ in reference script
   local res='s|\$\*|'"$2"'|g' rea='s|\$\@|'"$3"'|g'
   local re="$res; $rea; $set"
   # run the reference test and the test with our substitutions
   # applied. change the commands in the *output* of the reference
   # reference test so they do not show up as changed lines but do
   # show up in the context.
   diff --show-function-line='IFS' --unified='3' \
	<(. <(echo set -v; cat exp9.sub) 2>&1 | sed "$re") \
        <(. <(echo set -v; sed "$re" exp9.sub) 2>&1)
}

# ${*Op}
for op in '' ':1' '#' '/' ',' '@E'; do
  do_diff "" \
	  "\${*$op}" "\${@$op}"
done
# ${array[*]Op}
for op in '' ':0' '#' '/' ',' '@E'; do
  do_diff 'a=("$@")' \
	  "\${a[*]$op}" "\${a[@]$op}"
done
# ${assoc[*]Op}
for op in '' ':0' '#' '/' ',' '@E'; do
  do_diff 'declare -A A=(); for i; { A[$i]="$i"; }' \
	  "\${A[*]$op}" "\${A[@]$op}"
done
# ${!assoc[*]}
do_diff 'declare -A A=(); for i; { A[$i]= ; }' \
	'${!A[*]}' '${!A[@]}'
# ${!indirect} to *
do_diff 'ind_s=* ind_a=@' \
	'${!ind_s}' '${!ind_a}'
# ${!indirect} to array[*]
do_diff 'a=("$@") ind_s=a[*] ind_a=a[@]' \
	'${!ind_s}' '${!ind_a}'
# nameref[*] to array
do_diff 'a=("$@"); declare -n ref=a' \
	'${ref[*]}' '${ref[@]}'
# nameref to array[*]
do_diff 'a=("$@"); declare -n ref_s=a[*] ref_a=a[@]' \
	'${ref_s}' '${ref_a}'
# ${!nameref[*]} to assoc
do_diff 'declare -A A=(); for i; { A[$i]="$i"; }; declare -n ref=A' \
	'${!ref[*]}' '${!ref[@]}'

