Files
sausage/userland/brush/source/brush-shell/tests/cases/compat/builtins/set.yaml
T
2026-11-11 22:04:16 +00:00

383 lines
13 KiB
YAML

name: "Builtins: set"
cases:
- name: "set with no args"
stdin: |
MYVARIABLE=VALUE
set > set-output.txt
grep MYVARIABLE set-output.txt
# Remove set-output.txt to avoid it being byte-for-byte compared.
rm set-output.txt
- name: "Basic set usage"
stdin: |
set a b c d
echo ${*}
- name: "set with options"
stdin: |
function dumpopts {
# Dump the options
echo "[Options: $1]"
echo "set options: " $-
shopt -p -o pipefail
}
set -e -u -o pipefail
dumpopts enabled
echo '*: ' $*
set +e +u +o pipefail
dumpopts disabled
echo '*: ' $*
- name: "set with multiple combined options"
stdin: |
function dumpopts {
# Dump the options
echo "[Options: $1]"
echo "set options: " $-
shopt -p -o pipefail
}
set -euo pipefail
dumpopts enabled
echo '$*: ' $*
set +euo pipefail
dumpopts disabled
echo '$*: ' $*
- name: "set clearing args"
stdin: |
set a b c
echo ${*}
set a
echo ${*}
- name: "set with -"
stdin: |
set - a b c
echo "args: " ${*}
set -
echo "args: " ${*}
- name: "set with --"
stdin: |
set -- a b c
echo "args: " ${*}
set --
echo "args: " ${*}
- name: "set with option-looking args"
stdin: |
set -- a -v
echo ${*}
set - a -v
echo ${*}
set a -v
echo ${*}
set -- a +x
echo ${*}
set - a +x
echo ${*}
set a +x
echo ${*}
- name: "function-local set"
known_failure: true
stdin: |
function f() {
local -
set -x
echo "In func"
}
echo "Before func"
f
echo "After func"
- name: "set output quotes values"
stdin: |
q1="a'b"; q2="a''b"; q3="'"; q4="''"; q5="'a"; q6="a'"
set > set-output.txt
grep -E '^q[0-9]=' set-output.txt
# Remove set-output.txt to avoid it being byte-for-byte compared.
rm set-output.txt
- name: "set output leaves an empty value unquoted"
known_failure: true # TODO(escape): brush renders this as q1='' instead of q1=
stdin: |
q1=""
set > set-output.txt
grep -E '^q[0-9]=' set-output.txt
# Remove set-output.txt to avoid it being byte-for-byte compared.
rm set-output.txt
- name: "set quotes values starting with # or ~"
stdin: |
x="~" y="#z" z="a=~" w="a~"
set | grep -E "^(w|x|y|z)="
- name: "set leaves commas unquoted, like bash"
stdin: |
x="a,b" y="{a,b}" z=","
set | grep -E "^(x|y|z)="
- name: "set and declare -p leave commas in associative array keys unquoted, like bash"
stdin: |
declare -A m=([a,b]=1 [c]=2)
set | grep "^m="
declare -p m
- name: "set applies -o and +o in the order given"
stdin: |
set -o noglob +o noglob; echo "1 $-"
set +o noglob -o noglob; echo "2 $-"; set +f
set -o noglob -o noclobber +o noglob; echo "3 $-"; set +fC
- name: "set applies letters and -o names in the order given"
stdin: |
set -f +o noglob; echo "1 $-"
set -o noglob +f; echo "2 $-"; set +f
set +o noglob -f; echo "3 $-"; set +f
set -eo pipefail +e; echo "4 $-"; shopt -po pipefail; set +o pipefail
- name: "set -o alone after a name lists the options it just set"
stdin: |
set -o noglob -o | grep noglob
set +o noglob +o | grep noglob
- name: "set stops at an unknown option name"
ignore_stderr: true
stdin: |
set -- q
set -o nosuch -f a b; echo "$? $- [$*]"
- name: "set - turns off -x and -v"
ignore_stderr: true
stdin: |
set -x -v; set -; echo "1 $-"
set -x; set -e -; echo "2 $-"; set +e
set -x -v; set -- a; set +xv; echo "3 $- [$*]"
- name: "set -o with an unknown option name"
stdin: |
strip() { sed -E 's/\x1b\[[0-9;]*m//g; s/^[^ ]*: line [0-9]+: //; s/^error: //'; }
set -o bogus 2>&1 | strip
echo "set -o: ${PIPESTATUS[0]}"
set +o bogus 2>&1 | strip
echo "set +o: ${PIPESTATUS[0]}"
- name: "set takes the letters after -o as more options"
stdin: |
set -oe | tail -1
set -oe >/dev/null; echo "$-"
set +oe | tail -1
set +oe >/dev/null; echo "$-"
- name: "set rejects an option it doesn't have"
ignore_stderr: true
stdin: |
set -Z; echo "set -Z: $?"
set +Z; echo "set +Z: $?"
- name: "set accepts -r and +r"
stdin: |
set +r; echo "+r: $?"
set -r; echo "-r: $?"
- name: "set -r turns on restricted mode"
known_failure: true # TODO(set): brush accepts -r but doesn't restrict the shell or show r in $-
stdin: |
set -r; echo "status: $?"
[[ $- == *r* ]] && echo "restricted"
cd / 2>/dev/null; echo "cd: $?"
- name: "set skips a lone +"
known_failure: true # TODO(set): a lone + is taken as the first operand; needs winnow-args to skip it among the options
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set a b; set +; echo "$# $*"
set + | wc -l
set + x y; echo "$# $*"
set + -e; opts; echo "$# $*"; set +e
set -e + z; opts; echo "$# $*"; set +e
set + + -u; opts; set +u
set + -- w; echo "$# $*"
set -- +; echo "$# $*"
set - +; echo "$# $*"
set v + -e; opts; echo "$# $*"
- name: "set rejects an unknown letter after a lone + with status 1"
known_failure: true # TODO(set): brush fails with status 2
ignore_stderr: true
stdin: |
set + -Z; echo "status: $?"
- name: "set applies the options before a lone + when a later one is unknown"
known_failure: true # TODO(set): a lone + is taken as the first operand
ignore_stderr: true
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -f + -Z; echo "status: $?"; opts; set +f
set -f -u + -Z; echo "status: $?"; opts; set +fu
set a b; set -f + -Z c; echo "status: $?"; opts; echo "$# $*"; set +f
# Without a lone +, an unknown letter stops set before any option applies.
set -f -Z; echo "status: $?"; opts
- name: "set applies the options after a lone + up to an unknown one"
known_failure: true # TODO(set): a lone + is taken as the first operand
ignore_stderr: true
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set + -u -Z; echo "status: $?"; opts; set +u
set + -uZ; echo "status: $?"; opts; set +u
set + -Zu; echo "status: $?"; opts
- name: "set -o and +o list the options as they stand at that point"
stdin: |
set -eo | grep '^errexit'
set -oe | grep '^errexit'
set -o errexit -o | grep '^errexit'
set -o -o errexit | grep '^errexit'
set +o -e | grep ' errexit$'
set -e +o | grep ' errexit$'
set -u -o -u | grep '^nounset'
set -o '' | grep '^errexit'
set +o '' | grep ' errexit$'
set +o -o | grep -E '^(set [-+]o errexit|errexit)'
- name: "set -o takes an empty word as its first operand"
known_failure: true # TODO(set): brush takes the empty word as -o's name and applies the options after it
stdin: |
set a; set -o '' -e >/dev/null; echo "$- $# [$*]"
set -o '' x >/dev/null; echo "$# [$*]"
- name: "set applies -x and +x in command-line order"
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -e +e; opts
set +e -e; opts; set +e
set -u +eu -e; opts; set +e
set -eux +eux; opts
set -e -e +e +e -e; opts; set +e
set -B +B; opts; set +B -B; opts
set -C +C -C; opts; set +C
: > zzglob; set -f +f; echo zzg*; set +f -f; echo zzg*; set +f
set -e +u; opts; set +e
- name: "set applies -o and +o in order with the letter options"
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -o errexit +e; opts
set +e -o errexit; opts; set +e
# shopt -po fails for an option that is off; || keeps errexit from ending the case.
set -eo pipefail +o pipefail; opts; shopt -po pipefail || :; set +e
set +o pipefail -o pipefail +o pipefail; shopt -po pipefail
set -o pipefail +o pipefail -o pipefail; shopt -po pipefail; set +o pipefail
set -o nounset -o errexit +o nounset; opts; set +e
set +o errexit +o nounset -eu; opts; set +eu
set -a -o allexport +a; opts
set -uo nounset +u; opts
set -x +o xtrace; opts
- name: "set -o or +o with no name, then more options or operands"
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -o -e >/dev/null; opts; set +e
set +o -u >/dev/null; opts; set +u
set -oe >/dev/null; opts; set +e
set -o -- a b >/dev/null; echo "$# $*"
set -o >/dev/null -- c; echo "$# $*"
- name: "set stops at an unknown option name among other options and operands"
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -o nosuch -u 2>/dev/null; echo "status: $?"; opts
set -u -o nosuch 2>/dev/null; echo "status: $?"; opts; set +u
# set fails here with errexit on; || keeps it from ending the case.
set -o errexit +o nosuch -o nounset 2>/dev/null || echo "status: $?"; opts; set +e
set a b; set -o nosuch c d 2>/dev/null; echo "$# $*"
set -o nosuch -- e f 2>/dev/null; echo "$# $*"
set -o nosuch -o 2>/dev/null; echo "listed nothing"
- name: "set rejects an unknown letter before applying any option"
ignore_stderr: true
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -e -Z; echo "status: $?"; opts
set -eZ; echo "status: $?"; opts
set -Ze -u; echo "status: $?"; opts
set -o errexit -Z; echo "status: $?"; opts
set -o -Z | head -1; opts
set -ex+u; echo "status: $?"; opts
set a b; set -Z c; echo "$# $*"
- name: "set - turns off -x and -v and ends the options"
stdin: |
opts() { local o r=; for o in v x; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
{ set -x; set -; } 2>/dev/null; opts
{ set -xv; set - a; } 2>/dev/null; opts; echo "$# $*"
{ set -x -e - b; } 2>/dev/null; opts; echo "$# $*"; set +e
{ set -x - -e; } 2>/dev/null; opts; echo "$# $*"
{ set -x - -; } 2>/dev/null; opts; echo "$# $*"
- name: "set takes options only before its operands"
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -- -x; opts; echo "$# $*"
set x -e; opts; echo "$# $*"
set -e a -u; opts; echo "$# $*"; set +e
set -e -- -a; opts; echo "$# $*"; set +e
set -o errexit x -o nounset; opts; echo "$# $*"; set +e
set +o errexit nosuch; echo "status: $?"; echo "$# $*"
set - -Z; echo "$# $*"
set -- -- a; echo "$# $*"
set - -- a; echo "$# $*"
set -- - a; echo "$# $*"
set x -- y; echo "$# $*"
set x - y; echo "$# $*"
set ''; echo "$#"
set -e ''; opts; echo "$#"; set +e
- name: "set leaves the positional parameters alone without operands"
stdin: |
set a b c
set -e; echo "$#"; set +e
set -o errexit; echo "$#"; set +e
set -o >/dev/null; echo "$#"
set +o >/dev/null; echo "$#"
set -; echo "$#"
set -e -; echo "$#"; set +e
set --; echo "$#"
- name: "set -o in the middle of a bundle takes the next word"
known_failure: true # TODO(set): brush lists the options and takes the next word as an operand
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -ou nounset; echo "status: $?"; opts; echo "$#"; set +u
set -oe nounset; echo "status: $?"; opts; echo "$#"; set +eu
- name: "set -o takes no name that starts with + or is a lone - or +"
known_failure: true # TODO(set): brush takes the word as the option name and fails
stdin: |
opts() { local o r=; for o in a e f u x B C; do case $- in *"$o"*) r+=$o ;; esac; done; echo "[$r]"; }
set -e; set -o +e >/dev/null; echo "status: $?"; opts
set -o - >/dev/null; echo "status: $?"
set -o + a >/dev/null; echo "status: $?"; echo "$# $*"
set +o +o errexit >/dev/null; echo "status: $?"; opts; set +e
- name: "set -o vi and -o emacs turn each other off"
known_failure: true # TODO(set): brush leaves both on
stdin: |
set -o vi -o emacs; set -o | grep -E '^(vi|emacs) '
set -o emacs -o vi; set -o | grep -E '^(vi|emacs) '