Merge nucleic/sleek-thistle-egret-fyej into dev
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
name: "Compound commands: arithmetic"
|
||||
cases:
|
||||
- name: "Basic arithmetic statements"
|
||||
stdin: |
|
||||
((0 == 0)) && echo "0 == 0"
|
||||
((0 != 0)) && echo "0 != 0"
|
||||
|
||||
- name: "Arithmetic statements with parens"
|
||||
stdin: |
|
||||
(( (0) )) && echo "0"
|
||||
(( (1) )) && echo "1"
|
||||
|
||||
- name: "Arithmetic statements with parens and operators"
|
||||
stdin: |
|
||||
(( (0) == 0 )) && echo "0 == 0"
|
||||
(( (1) != 0 )) && echo "1 != 0"
|
||||
@@ -0,0 +1,110 @@
|
||||
name: "Compound commands: arithmetic for"
|
||||
cases:
|
||||
- name: "Single-line arithmetic for loop"
|
||||
stdin: |
|
||||
for ((i = 0; i < 5; i++)); do echo $i; done
|
||||
echo "Result: $?"
|
||||
|
||||
- name: "Arithmetic for loop without separator"
|
||||
stdin: |
|
||||
for ((i = 0; i < 5; i++)) do echo $i; done
|
||||
echo "Result: $?"
|
||||
|
||||
- name: "Arithmetic for loop with empty condition"
|
||||
stdin: |
|
||||
for (( ; ; )); do
|
||||
echo "In loop; status: $?"
|
||||
break
|
||||
done
|
||||
echo "Result: $?"
|
||||
|
||||
- name: "Arithmetic for loop with ;;"
|
||||
known_failure: true
|
||||
stdin: |
|
||||
for ((;;)); do
|
||||
echo "In loop; status: $?"
|
||||
break
|
||||
done
|
||||
echo "Result: $?"
|
||||
|
||||
- name: "Break in arithmetic for loop"
|
||||
stdin: |
|
||||
for ((i = 0; i < 5; i++)); do
|
||||
echo $i
|
||||
break
|
||||
done
|
||||
echo "Result: $?"
|
||||
|
||||
- name: "Continue in arithmetic for loop"
|
||||
stdin: |
|
||||
for ((i = 0; i < 5; i++)); do
|
||||
continue
|
||||
echo "Should not print"
|
||||
done
|
||||
echo "Result: $?"
|
||||
|
||||
- name: "Arithmetic for with break in condition inside outer loop"
|
||||
stdin: |
|
||||
for j in 1 2 3; do
|
||||
echo "Outer iteration $j"
|
||||
for ((i = 0; break; i++)); do
|
||||
echo "Inner body"
|
||||
done
|
||||
echo "After inner for"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "Arithmetic for with continue in condition inside outer loop"
|
||||
stdin: |
|
||||
for j in 1 2 3; do
|
||||
echo "Outer iteration $j"
|
||||
for ((i = 0; continue; i++)); do
|
||||
echo "Inner body"
|
||||
done
|
||||
echo "After inner for"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "Arithmetic for with return in body"
|
||||
stdin: |
|
||||
f() {
|
||||
for ((i = 0; i < 5; i++)); do
|
||||
echo "Iteration $i"
|
||||
if [ $i -eq 2 ]; then
|
||||
return 42
|
||||
fi
|
||||
done
|
||||
echo "After for"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "Arithmetic for with exit in body"
|
||||
stdin: |
|
||||
for ((i = 0; i < 5; i++)); do
|
||||
echo "Iteration $i"
|
||||
if [ $i -eq 2 ]; then
|
||||
exit 42
|
||||
fi
|
||||
done
|
||||
echo "After for"
|
||||
|
||||
- name: "Arithmetic for with alternate syntax"
|
||||
stdin: |
|
||||
for ((i = 0; i < 5; i++)) {
|
||||
echo "Iteration $i"
|
||||
}
|
||||
|
||||
- name: "Arithmetic for with alternate syntax (one line)"
|
||||
stdin: |
|
||||
for ((i = 0; i < 5; i++)) { echo "Iteration $i"; }
|
||||
|
||||
- name: "Arithmetic for loop with nameref"
|
||||
known_failure: true
|
||||
stdin: |
|
||||
target=0
|
||||
declare -n ref=target
|
||||
for ((ref=1; ref<=3; ref++)); do
|
||||
echo "ref=$ref target=$target"
|
||||
done
|
||||
echo "final target=$target"
|
||||
@@ -0,0 +1,5 @@
|
||||
name: "Compound commands: brace"
|
||||
cases:
|
||||
- name: "Brace command"
|
||||
stdin: |
|
||||
{ echo 'hi'; }
|
||||
@@ -0,0 +1,185 @@
|
||||
name: "Compound commands: case"
|
||||
cases:
|
||||
- name: "Basic case statement with double semi"
|
||||
test_files:
|
||||
- path: "script.sh"
|
||||
contents: |
|
||||
case x in
|
||||
x) echo hi;;
|
||||
esac
|
||||
args: ["./script.sh"]
|
||||
|
||||
- name: "Basic catch-all pattern against multi-line input"
|
||||
stdin: |
|
||||
case "$(echo hi; echo there)" in
|
||||
"not-it") echo "did not work" ;;
|
||||
*) echo "caught it" ;;
|
||||
esac
|
||||
|
||||
- name: "One-line case statement with double semi"
|
||||
stdin: |
|
||||
case x in x) echo "hi";; esac
|
||||
|
||||
- name: "Interesting characters in cases"
|
||||
stdin: |
|
||||
case "{" in
|
||||
{) echo "curly brace" ;;
|
||||
*) echo "unhandled case" ;;
|
||||
esac
|
||||
|
||||
- name: "Case with case insensitive pattern"
|
||||
stdin: |
|
||||
shopt -s nocasematch
|
||||
case "A" in
|
||||
a) echo "matched" ;;
|
||||
*) echo "did not match" ;;
|
||||
esac
|
||||
|
||||
- name: "Interesting patterns in cases"
|
||||
stdin: |
|
||||
for word in "-a" "!b" "*c" "(d" "{e" ":f" "'g"; do
|
||||
case "${word}" in
|
||||
\!*) echo "starts with exclamation" ;;
|
||||
-*) echo "starts with hyphen" ;;
|
||||
\**) echo "starts with asterisk" ;;
|
||||
\(*) echo "starts with open parenthesis" ;;
|
||||
\{*) echo "starts with open curly brace" ;;
|
||||
:*) echo "starts with colon" ;;
|
||||
\'*) echo "starts with single quote" ;;
|
||||
*) echo "unhandled case" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
- name: "Empty case"
|
||||
stdin: |
|
||||
myfunc() {
|
||||
case abc in
|
||||
*b*) ;;
|
||||
*) return 33;;
|
||||
esac
|
||||
|
||||
echo "Dropped out"
|
||||
}
|
||||
|
||||
myfunc
|
||||
|
||||
- name: "Case with non-dsemi"
|
||||
stdin: |
|
||||
case "b" in
|
||||
a) echo "a";;
|
||||
b) echo "b"
|
||||
esac
|
||||
|
||||
- name: "Case with fall-through"
|
||||
stdin: |
|
||||
case "b" in
|
||||
a) echo "a";;
|
||||
b) echo "b";&
|
||||
c) echo "c";;
|
||||
d) echo "d";;
|
||||
esac
|
||||
|
||||
- name: "Case with resuming switch"
|
||||
stdin: |
|
||||
case "b" in
|
||||
a) echo "a";;
|
||||
b) echo "b";;&
|
||||
c) echo "c";;
|
||||
*) echo "*";;
|
||||
d) echo "d";;
|
||||
esac
|
||||
|
||||
- name: "Case status values"
|
||||
stdin: |
|
||||
function yield() {
|
||||
return $1
|
||||
}
|
||||
|
||||
case "a" in
|
||||
x) yield 10;;
|
||||
a) yield 11;;
|
||||
b) yield 12;;
|
||||
esac
|
||||
echo "1: $?"
|
||||
|
||||
case "a" in
|
||||
b) yield 10;;
|
||||
c) yield 11;;
|
||||
esac
|
||||
echo "2: $?"
|
||||
|
||||
case "a" in
|
||||
a) yield 10;&
|
||||
b) yield 11;;
|
||||
c) yield 12;;
|
||||
esac
|
||||
echo "3: $?"
|
||||
|
||||
case "a" in
|
||||
a) yield 10;;&
|
||||
*) yield 11;;
|
||||
x) yield 12;;
|
||||
esac
|
||||
echo "4: $?"
|
||||
|
||||
- name: "Case with reserved words"
|
||||
stdin: |
|
||||
case case in
|
||||
case) echo "saw case";;
|
||||
esac
|
||||
|
||||
- name: "Case with return in function"
|
||||
stdin: |
|
||||
f() {
|
||||
case "a" in
|
||||
a) echo "matched a"; return 42;;
|
||||
b) echo "matched b";;
|
||||
esac
|
||||
echo "After case"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "Case with exit"
|
||||
stdin: |
|
||||
case "a" in
|
||||
a) echo "matched a"; exit 42;;
|
||||
b) echo "matched b";;
|
||||
esac
|
||||
echo "After case"
|
||||
|
||||
- name: "Case with break in loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
case "$i" in
|
||||
1) echo "one";;
|
||||
2) echo "two"; break;;
|
||||
3) echo "three";;
|
||||
esac
|
||||
echo "After case iteration $i"
|
||||
done
|
||||
echo "After loop"
|
||||
|
||||
- name: "Case with continue in loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
case "$i" in
|
||||
1) echo "one";;
|
||||
2) echo "two"; continue;;
|
||||
3) echo "three";;
|
||||
esac
|
||||
echo "After case iteration $i"
|
||||
done
|
||||
echo "After loop"
|
||||
|
||||
- name: "Case with return and fall-through"
|
||||
stdin: |
|
||||
f() {
|
||||
case "a" in
|
||||
a) echo "matched a"; return 42;&
|
||||
b) echo "matched b";;
|
||||
esac
|
||||
echo "After case"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
@@ -0,0 +1,839 @@
|
||||
name: "Compound commands: coproc"
|
||||
|
||||
# NOTE: Coproc tests must defend against TWO race conditions caused by bash's
|
||||
# SIGCHLD handler:
|
||||
#
|
||||
# 1. The handler clears the COPROC array when the coproc child exits, so
|
||||
# ${COPROC[0]} can become empty before the parent captures it.
|
||||
# 2. The handler ALSO closes the underlying pipe FDs, so even after capturing
|
||||
# the integer FD, reading from it returns EOF immediately.
|
||||
#
|
||||
# We defend against both by:
|
||||
# (a) Having the coproc body block on `read -r _ < _sync` first, so it can't
|
||||
# exit before the parent dups the FD (no SIGCHLD can fire yet).
|
||||
# (b) Using `exec 9<&${COPROC[0]}` to dup the pipe to a fresh FD that bash
|
||||
# does NOT manage as part of the coproc, so it survives SIGCHLD cleanup.
|
||||
# (c) Then `echo x > _sync` releases the coproc to do its real work.
|
||||
#
|
||||
# We use explicit FD 9 (rather than `{fd}<&...` auto-assignment) for portability.
|
||||
|
||||
cases:
|
||||
#
|
||||
# Basic invocation
|
||||
#
|
||||
- name: "Unnamed coproc with brace group"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "hello from coproc"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Unnamed coproc with subshell"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc ( read -r _ < _sync; echo "hello from subshell coproc" )
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Named coproc with brace group"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc MYCOPROC { read -r _ < _sync; echo "named coproc"; }
|
||||
exec 9<&${MYCOPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Named coproc with subshell"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc MYSUB ( read -r _ < _sync; echo "named subshell coproc" )
|
||||
exec 9<&${MYSUB[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with simple command"
|
||||
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc cat
|
||||
rfd=${COPROC[0]}
|
||||
wfd=${COPROC[1]}
|
||||
echo "input line" >&$wfd
|
||||
exec {wfd}>&-
|
||||
read -r line <&$rfd
|
||||
echo "got: $line"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with multi-statement brace group"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo "line1"
|
||||
echo "line2"
|
||||
echo "line3"
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# COPROC and COPROC_PID variable validation via functional use
|
||||
#
|
||||
- name: "COPROC array read FD is functional"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "via read fd"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
read -r line <&9
|
||||
echo "got: $line"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Named coproc FDs are functional"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc MYPROC { read -r _ < _sync; echo "named fd test"; }
|
||||
exec 9<&${MYPROC[0]}
|
||||
echo x > _sync
|
||||
read -r line <&9
|
||||
echo "got: $line"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Reading from coproc stdout
|
||||
#
|
||||
- name: "Read coproc output with cat"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "output from coproc"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Read coproc output with read builtin"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "readline test"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
read -r line <&9
|
||||
echo "got: $line"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Read multiple lines from coproc"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo "first"
|
||||
echo "second"
|
||||
echo "third"
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Read multiple lines with read builtin"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo "line1"
|
||||
echo "line2"
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
{
|
||||
read -r first
|
||||
read -r second
|
||||
} <&9
|
||||
echo "first=$first"
|
||||
echo "second=$second"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Named coproc read"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc READER { read -r _ < _sync; echo "from named"; }
|
||||
exec 9<&${READER[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Writing to coproc stdin
|
||||
#
|
||||
- name: "Write to coproc stdin and read back"
|
||||
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc cat
|
||||
rfd=${COPROC[0]}
|
||||
wfd=${COPROC[1]}
|
||||
echo "hello coproc" >&$wfd
|
||||
exec {wfd}>&-
|
||||
read -r line <&$rfd
|
||||
echo "got: $line"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Bidirectional communication"
|
||||
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc {
|
||||
while read -r line; do
|
||||
echo "processed: $line"
|
||||
done
|
||||
}
|
||||
rfd=${COPROC[0]}
|
||||
wfd=${COPROC[1]}
|
||||
echo "msg1" >&$wfd
|
||||
echo "msg2" >&$wfd
|
||||
exec {wfd}>&-
|
||||
{
|
||||
read -r out1
|
||||
read -r out2
|
||||
} <&$rfd
|
||||
echo "$out1"
|
||||
echo "$out2"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Named coproc bidirectional"
|
||||
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc BIDIR {
|
||||
while read -r line; do
|
||||
echo "echo: $line"
|
||||
done
|
||||
}
|
||||
rfd=${BIDIR[0]}
|
||||
wfd=${BIDIR[1]}
|
||||
echo "test1" >&$wfd
|
||||
echo "test2" >&$wfd
|
||||
exec {wfd}>&-
|
||||
{
|
||||
read -r out1
|
||||
read -r out2
|
||||
} <&$rfd
|
||||
echo "$out1"
|
||||
echo "$out2"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Close write FD to signal EOF"
|
||||
skip: true # TODO(coproc): hangs - wait never completes after bidirectional coproc I/O
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc {
|
||||
count=0
|
||||
while read -r line; do
|
||||
count=$((count + 1))
|
||||
done
|
||||
echo "read $count lines"
|
||||
}
|
||||
rfd=${COPROC[0]}
|
||||
wfd=${COPROC[1]}
|
||||
echo "a" >&$wfd
|
||||
echo "b" >&$wfd
|
||||
echo "c" >&$wfd
|
||||
exec {wfd}>&-
|
||||
read -r result <&$rfd
|
||||
echo "$result"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Bidirectional with cat for EOF"
|
||||
skip: true # TODO(coproc): hangs - stdout pipe not fully closed after coproc exits
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc {
|
||||
while read -r line; do
|
||||
echo "processed: $line"
|
||||
done
|
||||
}
|
||||
rfd=${COPROC[0]}
|
||||
wfd=${COPROC[1]}
|
||||
echo "msg1" >&$wfd
|
||||
echo "msg2" >&$wfd
|
||||
exec {wfd}>&-
|
||||
cat <&$rfd
|
||||
wait
|
||||
echo "DONE"
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Coproc with compound command bodies
|
||||
#
|
||||
- name: "Coproc running a for loop"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
for i in 1 2 3; do
|
||||
echo "iteration $i"
|
||||
done
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc running a while loop"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
n=1
|
||||
while [ $n -le 3 ]; do
|
||||
echo "count $n"
|
||||
n=$((n + 1))
|
||||
done
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with conditionals"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
if true; then
|
||||
echo "true branch"
|
||||
else
|
||||
echo "false branch"
|
||||
fi
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with case statement"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
val="hello"
|
||||
case $val in
|
||||
hello) echo "matched hello";;
|
||||
*) echo "no match";;
|
||||
esac
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc body with pipeline"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo -e "banana\napple\ncherry" | sort
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc body with command substitution"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
result=$(echo "hello" | tr a-z A-Z)
|
||||
echo "$result"
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with arithmetic operations"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
a=5
|
||||
b=3
|
||||
echo $((a + b))
|
||||
echo $((a * b))
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Exit status and lifecycle
|
||||
#
|
||||
- name: "Coproc statement returns 0"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo done; }
|
||||
status=$?
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
echo "exit status: $status"
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with failing body returns 0 immediately"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc { exit 42; }
|
||||
echo "coproc start status: $?"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Wait with no args waits for coproc"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "coproc done"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
echo "after wait"
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Error cases
|
||||
#
|
||||
- name: "Invalid coproc name"
|
||||
ignore_stderr: true
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc 123bad { echo x; }
|
||||
echo "exit: $?"
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Coproc in different contexts
|
||||
#
|
||||
- name: "Coproc inside a function"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
start_coproc() {
|
||||
coproc { read -r _ < _sync; echo "from function coproc"; }
|
||||
}
|
||||
start_coproc
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc inside a conditional"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
if true; then
|
||||
coproc { read -r _ < _sync; echo "conditional coproc"; }
|
||||
fi
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc inside a loop body"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
for i in 1; do
|
||||
coproc { read -r _ < _sync; echo "loop coproc $i"; }
|
||||
done
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Named coproc inside a function"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
f() {
|
||||
coproc FUNCPROC { read -r _ < _sync; echo "named in func"; }
|
||||
}
|
||||
f
|
||||
exec 9<&${FUNCPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Multiple coprocs and variable lifecycle
|
||||
#
|
||||
- name: "Second unnamed coproc replaces first"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "first"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
exec 9<&-
|
||||
wait
|
||||
coproc { read -r _ < _sync; echo "second"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Sequential named coprocs with different names"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc PROC1 { read -r _ < _sync; echo "proc1"; }
|
||||
exec 9<&${PROC1[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
exec 9<&-
|
||||
wait
|
||||
coproc PROC2 { read -r _ < _sync; echo "proc2"; }
|
||||
exec 9<&${PROC2[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Environment and variable scope
|
||||
#
|
||||
- name: "Coproc inherits parent environment"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
export MY_VAR="inherited"
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "MY_VAR=$MY_VAR"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc inherits non-exported variables"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
LOCAL_VAR="visible"
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; echo "LOCAL_VAR=$LOCAL_VAR"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc cannot modify parent variables"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
PARENT_VAR="original"
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; PARENT_VAR="modified"; echo "in coproc: $PARENT_VAR"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
echo "in parent: $PARENT_VAR"
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc inherits functions"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
greet() { echo "hello $1"; }
|
||||
export -f greet
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; greet "world"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc inherits aliases"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
shopt -s expand_aliases
|
||||
alias myecho='echo ALIASED:'
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; myecho "test"; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Coproc with redirections in body
|
||||
#
|
||||
- name: "Coproc body with stderr redirection"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo "stdout msg"
|
||||
echo "stderr msg" >&2
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc body writing to a file"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo "file content" > /tmp/coproc_test_$$
|
||||
echo "wrote file"
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
cat /tmp/coproc_test_$$
|
||||
rm -f /tmp/coproc_test_$$
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Coproc with various data patterns
|
||||
#
|
||||
- name: "Coproc producing empty output"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc { read -r _ < _sync; true; }
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
echo "after empty coproc"
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc producing multiple lines of output"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||
echo "line $i"
|
||||
done
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
count=0
|
||||
while read -r line; do
|
||||
count=$((count + 1))
|
||||
done <&9
|
||||
echo "read $count lines"
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with multiline string output"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
cat <<'HEREDOC'
|
||||
first line
|
||||
second line
|
||||
third line
|
||||
HEREDOC
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
cat <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Coproc output transformation
|
||||
#
|
||||
- name: "Transform coproc output to uppercase"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo "hello"
|
||||
echo "world"
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
while read -r line; do
|
||||
echo "$line" | tr a-z A-Z
|
||||
done <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc output filtered with case"
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
mkfifo _sync
|
||||
coproc {
|
||||
read -r _ < _sync
|
||||
echo "apple"
|
||||
echo "banana"
|
||||
echo "avocado"
|
||||
echo "cherry"
|
||||
}
|
||||
exec 9<&${COPROC[0]}
|
||||
echo x > _sync
|
||||
while read -r line; do
|
||||
case $line in
|
||||
a*) echo "starts with a: $line";;
|
||||
esac
|
||||
done <&9
|
||||
wait
|
||||
args: ["./test.sh"]
|
||||
|
||||
#
|
||||
# Tests requiring wait with job specs (known failures)
|
||||
#
|
||||
- name: "Wait for specific coproc PID"
|
||||
known_failure: true # TODO(wait): wait with job specs not implemented
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc { echo "done"; }
|
||||
fd=${COPROC[0]}
|
||||
cat <&$fd
|
||||
wait $COPROC_PID
|
||||
echo "wait status: $?"
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Coproc with failing body - wait captures exit status"
|
||||
known_failure: true # TODO(wait): wait with job specs not implemented
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc { exit 42; }
|
||||
wait $COPROC_PID
|
||||
echo "exit status: $?"
|
||||
args: ["./test.sh"]
|
||||
|
||||
- name: "Wait for named coproc PID"
|
||||
known_failure: true # TODO(wait): wait with job specs not implemented
|
||||
test_files:
|
||||
- path: "test.sh"
|
||||
contents: |
|
||||
coproc MYPROC { echo "done"; }
|
||||
fd=${MYPROC[0]}
|
||||
cat <&$fd
|
||||
wait $MYPROC_PID
|
||||
echo "status: $?"
|
||||
args: ["./test.sh"]
|
||||
@@ -0,0 +1,195 @@
|
||||
name: "Compound commands: for"
|
||||
cases:
|
||||
- name: "Single-line for loop"
|
||||
stdin: |
|
||||
for f in 1 2 3; do echo $f; done
|
||||
|
||||
- name: "Multi-line for loop"
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
echo $f
|
||||
done
|
||||
|
||||
- name: "Empty for loop"
|
||||
stdin: |
|
||||
for f in; do echo $f; done
|
||||
|
||||
- name: "for loop without in"
|
||||
stdin: |
|
||||
set -- a b c
|
||||
|
||||
echo "Loop 1"
|
||||
for f; do echo $f; done
|
||||
|
||||
echo "Loop 2: no semicolon"
|
||||
for f do echo $f; done
|
||||
|
||||
- name: "for loop without in but spaces"
|
||||
stdin: |
|
||||
set -- a "b c" d
|
||||
|
||||
echo "Loop 1"
|
||||
for f; do echo $f; done
|
||||
|
||||
echo "Loop 2: no semicolon"
|
||||
for f do echo $f; done
|
||||
|
||||
- name: "Break in for loop"
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
echo $f
|
||||
break
|
||||
done
|
||||
|
||||
- name: "Break in nested for loop"
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
for g in a b c; do
|
||||
echo "f=$f g=$g"
|
||||
true && break
|
||||
done
|
||||
echo "Left inner loop"
|
||||
done
|
||||
|
||||
- name: "Break 1 in nested for loops"
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
for g in a b c; do
|
||||
echo "f=$f g=$g"
|
||||
break 1
|
||||
done
|
||||
done
|
||||
|
||||
- name: "Break 2 in nested for loops"
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
for g in a b c; do
|
||||
echo "f=$f g=$g"
|
||||
break 2
|
||||
done
|
||||
done
|
||||
|
||||
- name: "Break out of nested for/while loops"
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
while true; do
|
||||
echo "f=$f"
|
||||
break 2
|
||||
done
|
||||
done
|
||||
|
||||
- name: "Continue in for loop"
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
echo $f
|
||||
continue
|
||||
echo $f
|
||||
done
|
||||
|
||||
- name: "Continue with bad N"
|
||||
known_failure: true # Fails differently
|
||||
stdin: |
|
||||
for f in 1 2 3; do
|
||||
echo $f
|
||||
continue 0
|
||||
echo result: $?
|
||||
done
|
||||
|
||||
- name: "Continue in nested for loop"
|
||||
stdin: |
|
||||
for f in a b c; do
|
||||
for g in 1 2 3; do
|
||||
echo "f=$f g=$g"
|
||||
continue
|
||||
echo "Should not print"
|
||||
done
|
||||
echo "Left inner loop"
|
||||
done
|
||||
|
||||
- name: "Continue in nested for loop with explicit N=1"
|
||||
stdin: |
|
||||
for f in a b c; do
|
||||
for g in 1 2 3; do
|
||||
echo "f=$f g=$g"
|
||||
continue 1
|
||||
echo "Should not print"
|
||||
done
|
||||
echo "Left inner loop"
|
||||
done
|
||||
|
||||
- name: "Continue in nested for loop with explicit N=2"
|
||||
stdin: |
|
||||
for f in a b c; do
|
||||
for g in 1 2 3; do
|
||||
echo "f=$f g=$g"
|
||||
continue 2
|
||||
echo "Should not print"
|
||||
done
|
||||
echo "Left inner loop"
|
||||
done
|
||||
|
||||
- name: "Continue in nested for loop with too large N"
|
||||
known_failure: true
|
||||
stdin: |
|
||||
for f in a b c; do
|
||||
for g in 1 2 3; do
|
||||
echo "f=$f g=$g"
|
||||
continue 3
|
||||
echo "Should not print"
|
||||
done
|
||||
echo "Left inner loop"
|
||||
done
|
||||
|
||||
- name: "Multi-line for loop"
|
||||
test_files:
|
||||
- path: "script.sh"
|
||||
contents: |
|
||||
for f in 1 2 3; do
|
||||
echo $f
|
||||
done
|
||||
args: ["./script.sh"]
|
||||
|
||||
- name: "For loop piped"
|
||||
stdin: |
|
||||
for f in ab ac bd ef; do echo $f; done | grep b
|
||||
|
||||
- name: "For loop output redirection"
|
||||
stdin: |
|
||||
for f in a b c; do echo $f; done > ./out.txt
|
||||
|
||||
- name: "For reserved word handling"
|
||||
stdin: |
|
||||
for for in for; do echo $for; done
|
||||
|
||||
- name: "For with return in body"
|
||||
stdin: |
|
||||
f() {
|
||||
for i in 1 2 3; do
|
||||
echo "Iteration $i"
|
||||
if [ "$i" = "2" ]; then
|
||||
return 42
|
||||
fi
|
||||
done
|
||||
echo "After for"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "For with exit in body"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Iteration $i"
|
||||
if [ "$i" = "2" ]; then
|
||||
exit 42
|
||||
fi
|
||||
done
|
||||
echo "After for"
|
||||
|
||||
- name: "For loop with nameref variable"
|
||||
stdin: |
|
||||
target=""
|
||||
declare -n ref=target
|
||||
for ref in a b c; do
|
||||
echo "loop: target=$target"
|
||||
done
|
||||
echo "final: target=$target"
|
||||
@@ -0,0 +1,99 @@
|
||||
name: "Compound commands: if"
|
||||
cases:
|
||||
- name: "Basic if"
|
||||
stdin: |
|
||||
if false; then echo 1; else echo 2; fi
|
||||
if false; then echo 3; elif false; then echo 4; else echo 5; fi
|
||||
if true; then echo 6; else echo 7; fi
|
||||
if false; then echo 8; elif true; then echo 10; else echo 11; fi
|
||||
|
||||
- name: "Multi-line if"
|
||||
test_files:
|
||||
- path: "script.sh"
|
||||
contents: |
|
||||
if false; then
|
||||
echo 1
|
||||
else
|
||||
echo 2
|
||||
fi
|
||||
|
||||
if false; then
|
||||
echo 3
|
||||
elif false; then
|
||||
echo 4
|
||||
else
|
||||
echo 5
|
||||
fi
|
||||
|
||||
if true; then
|
||||
echo 6
|
||||
else
|
||||
echo 7
|
||||
fi
|
||||
|
||||
if false; then
|
||||
echo 8
|
||||
elif true; then
|
||||
echo 10
|
||||
else
|
||||
echo 11
|
||||
fi
|
||||
args: ["./script.sh"]
|
||||
|
||||
- name: "If with return in condition"
|
||||
stdin: |
|
||||
f() {
|
||||
if return 42; then
|
||||
echo "Then branch"
|
||||
else
|
||||
echo "Else branch"
|
||||
fi
|
||||
echo "After if"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "If with exit in condition"
|
||||
stdin: |
|
||||
if exit 42; then
|
||||
echo "Then branch"
|
||||
else
|
||||
echo "Else branch"
|
||||
fi
|
||||
echo "After if"
|
||||
|
||||
- name: "If with return in elif condition"
|
||||
stdin: |
|
||||
f() {
|
||||
if false; then
|
||||
echo "Then branch"
|
||||
elif return 42; then
|
||||
echo "Elif then branch"
|
||||
else
|
||||
echo "Else branch"
|
||||
fi
|
||||
echo "After if"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "If with break in condition inside loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
if break; then
|
||||
echo "Then branch"
|
||||
fi
|
||||
echo "After if"
|
||||
done
|
||||
echo "After loop"
|
||||
|
||||
- name: "If with continue in condition inside loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Iteration $i"
|
||||
if continue; then
|
||||
echo "Then branch"
|
||||
fi
|
||||
echo "After if"
|
||||
done
|
||||
echo "After loop"
|
||||
@@ -0,0 +1,10 @@
|
||||
name: "Select statement"
|
||||
cases:
|
||||
- name: "basic"
|
||||
known_failure: true # TODO(select): select statement not implemented
|
||||
stdin: |
|
||||
echo "1" | select opt in a b c; do
|
||||
echo "selected: $opt"
|
||||
break
|
||||
done
|
||||
echo "after select"
|
||||
@@ -0,0 +1,38 @@
|
||||
name: "Compound commands: subshell"
|
||||
cases:
|
||||
- name: "Basic subshell usage"
|
||||
stdin: |
|
||||
(echo hi)
|
||||
|
||||
- name: "Subshells in sequence"
|
||||
ignore_stderr: true
|
||||
stdin: |
|
||||
(echo hi)(echo there)
|
||||
|
||||
- name: "Subshell env usage"
|
||||
stdin: |
|
||||
(subshell_var=value && echo "subshell_var: ${subshell_var}")
|
||||
echo "subshell_var: ${subshell_var}"
|
||||
|
||||
- name: "Subshell output redirection"
|
||||
stdin: |
|
||||
(echo Hello; echo world) >out.txt
|
||||
echo "Dumping out.txt..."
|
||||
cat out.txt
|
||||
|
||||
- name: "Piped subshell usage"
|
||||
stdin: |
|
||||
(echo hi) | wc -l
|
||||
|
||||
- name: "Breaks in subshell"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo $i
|
||||
(for i in 1 2 3; do break 2; done)
|
||||
done
|
||||
|
||||
- name: "Exec in subshell"
|
||||
stdin: |
|
||||
echo "Before subshell"
|
||||
(exec cat <<<"Hello from exec in subshell")
|
||||
echo "After subshell"
|
||||
@@ -0,0 +1,101 @@
|
||||
name: "Compound commands: until"
|
||||
cases:
|
||||
- name: "Single-line until loop"
|
||||
stdin: |
|
||||
until true; do echo 'In loop'; done
|
||||
|
||||
- name: "Arithmetic in until loop"
|
||||
incompatible_configs: ["sh"]
|
||||
stdin: |
|
||||
i=5
|
||||
until ((i == 0)); do echo $i; i=$((i - 1)); done
|
||||
|
||||
- name: "Until with return in condition"
|
||||
stdin: |
|
||||
f() {
|
||||
until return 42; do
|
||||
echo "Body"
|
||||
done
|
||||
echo "After until"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "Until with exit in condition"
|
||||
stdin: |
|
||||
until exit 42; do
|
||||
echo "Body"
|
||||
done
|
||||
echo "After until"
|
||||
|
||||
- name: "Until with break in condition inside outer loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Outer iteration $i"
|
||||
until break; do
|
||||
echo "Until body"
|
||||
done
|
||||
echo "After until"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "Until with break 2 in condition inside outer loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Outer iteration $i"
|
||||
until break 2; do
|
||||
echo "Until body"
|
||||
done
|
||||
echo "After until"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "Until with continue 2 in condition inside outer loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Outer iteration $i"
|
||||
until continue 2; do
|
||||
echo "Until body"
|
||||
done
|
||||
echo "After until"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "Until with continue in condition inside outer loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Outer iteration $i"
|
||||
until continue; do
|
||||
echo "Until body"
|
||||
done
|
||||
echo "After until"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "Until with return in body"
|
||||
stdin: |
|
||||
f() {
|
||||
i=0
|
||||
until [ $i -ge 3 ]; do
|
||||
echo "Iteration $i"
|
||||
if [ $i -eq 1 ]; then
|
||||
return 42
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
echo "After until"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "Until with exit in body"
|
||||
stdin: |
|
||||
i=0
|
||||
until [ $i -ge 3 ]; do
|
||||
echo "Iteration $i"
|
||||
if [ $i -eq 1 ]; then
|
||||
exit 42
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
echo "After until"
|
||||
@@ -0,0 +1,127 @@
|
||||
name: "Compound commands: while"
|
||||
cases:
|
||||
- name: "Single-line while loop"
|
||||
stdin: |
|
||||
while false; do echo 'In loop'; done
|
||||
|
||||
- name: "break in while loop"
|
||||
stdin: |
|
||||
while true; do
|
||||
echo 'In loop'
|
||||
break
|
||||
done
|
||||
|
||||
- name: "break 2 in nested loops"
|
||||
stdin: |
|
||||
while false; do
|
||||
echo 'Starting inner loop'
|
||||
while true; do
|
||||
echo 'In loop'
|
||||
break 2
|
||||
done
|
||||
echo 'Finished inner loop'
|
||||
done
|
||||
|
||||
- name: "Arithmetic in while loop"
|
||||
stdin: |
|
||||
i=5
|
||||
while ((i > 0)); do echo $i; i=$((i - 1)); done
|
||||
|
||||
- name: "Alternative arithmetic in while loop"
|
||||
stdin: |
|
||||
c=0
|
||||
limit=4
|
||||
while [ $c -lt $limit ]; do
|
||||
case "$c" in
|
||||
0)
|
||||
echo "0"
|
||||
;;
|
||||
1)
|
||||
echo "1"
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
((c++))
|
||||
done
|
||||
echo "Done"
|
||||
|
||||
- name: "While with return in condition"
|
||||
stdin: |
|
||||
f() {
|
||||
while return 42; do
|
||||
echo "Body"
|
||||
done
|
||||
echo "After while"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "While with exit in condition"
|
||||
stdin: |
|
||||
while exit 42; do
|
||||
echo "Body"
|
||||
done
|
||||
echo "After while"
|
||||
|
||||
- name: "While with break in condition inside outer loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Outer iteration $i"
|
||||
while break; do
|
||||
echo "While body"
|
||||
done
|
||||
echo "After while"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "While with break 2 in condition inside outer loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Outer iteration $i"
|
||||
while break 2; do
|
||||
echo "While body"
|
||||
done
|
||||
echo "After while"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "While with continue 2 in condition inside outer loop"
|
||||
stdin: |
|
||||
for i in 1 2 3; do
|
||||
echo "Outer iteration $i"
|
||||
while continue 2; do
|
||||
echo "While body"
|
||||
done
|
||||
echo "After while"
|
||||
done
|
||||
echo "After outer loop"
|
||||
|
||||
- name: "While with return in body"
|
||||
stdin: |
|
||||
f() {
|
||||
i=0
|
||||
while [ $i -lt 3 ]; do
|
||||
echo "Iteration $i"
|
||||
if [ $i -eq 1 ]; then
|
||||
return 42
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
echo "After while"
|
||||
}
|
||||
f
|
||||
echo "Exit code: $?"
|
||||
|
||||
- name: "While with exit in body"
|
||||
stdin: |
|
||||
i=0
|
||||
while [ $i -lt 3 ]; do
|
||||
echo "Iteration $i"
|
||||
if [ $i -eq 1 ]; then
|
||||
exit 42
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
echo "After while"
|
||||
Reference in New Issue
Block a user