mirror of
https://codeberg.org/la-chouette/minishell.git
synced 2025-12-06 07:28:09 +01:00
502 lines
7.8 KiB
Bash
Executable file
502 lines
7.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
set -uo pipefail
|
|
|
|
declare -i FAILED=0
|
|
declare -i SUCCEDED=0
|
|
declare -i TODO=0
|
|
declare -i RAN=0
|
|
NAME=""
|
|
EXTRAENV=""
|
|
MINISHELL=$PWD/minishell
|
|
|
|
report_header()
|
|
{
|
|
echo "++++++++++++++++++++++++++++++++++++++++++++++++++++"
|
|
echo $NAME
|
|
echo "++++++++++++++++++++++++++++++++++++++++++++++++++++"
|
|
echo "++++ test input:"
|
|
}
|
|
|
|
failed_report()
|
|
{
|
|
NAME="failed: $NAME"
|
|
report_header
|
|
cat /tmp/input.minishell
|
|
echo "++++ Got output:"
|
|
cat /tmp/got.minishell
|
|
echo "++++ But expected:"
|
|
cat /tmp/expected.minishell
|
|
echo "++++ Diff:"
|
|
echo "(red is got, green is expected)"
|
|
diff --color=always /tmp/got.minishell /tmp/expected.minishell
|
|
echo "++++ Run this to debug:"
|
|
cat < /tmp/input.minishell > /tmp/input.failed.$FAILED.minishell
|
|
echo "cat /tmp/input.failed.$FAILED.minishell | ./minishell"
|
|
}
|
|
|
|
todo_report()
|
|
{
|
|
NAME="todo: $NAME"
|
|
report_header
|
|
cat /tmp/input.minishell
|
|
echo "++++ Got output:"
|
|
cat /tmp/got.minishell
|
|
echo "++++ But test was marked as todo."
|
|
echo "++++ Run this to debug:"
|
|
cat < /tmp/input.minishell > /tmp/input.todo.$TODO.minishell
|
|
echo "cat /tmp/input.todo.$TODO.minishell | ./minishell"
|
|
}
|
|
|
|
failed()
|
|
{
|
|
echo -n "F"
|
|
FAILED+=1
|
|
failed_report >> report.txt
|
|
}
|
|
|
|
succeded()
|
|
{
|
|
echo -n "."
|
|
SUCCEDED+=1
|
|
}
|
|
|
|
assert()
|
|
{
|
|
diff -q /tmp/got.minishell /tmp/expected.minishell > /dev/null && succeded || failed
|
|
}
|
|
|
|
when_run()
|
|
{
|
|
cat > /tmp/input.minishell
|
|
rm -rf /tmp/dir.minishell
|
|
mkdir -p /tmp/dir.minishell
|
|
pushd /tmp/dir.minishell > /dev/null
|
|
env $EXTRAENV $MINISHELL &> /tmp/got.minishell < /tmp/input.minishell
|
|
popd > /dev/null
|
|
EXTRAENV=""
|
|
RAN+=1
|
|
NAME=$1
|
|
}
|
|
|
|
expecting()
|
|
{
|
|
cat > /tmp/expected.minishell
|
|
assert
|
|
}
|
|
|
|
todo()
|
|
{
|
|
echo -n "t"
|
|
TODO+=1
|
|
todo_report >> report.txt
|
|
}
|
|
|
|
setup()
|
|
{
|
|
rm -f report.txt
|
|
}
|
|
|
|
finalize()
|
|
{
|
|
echo
|
|
echo "$RAN tests ran. $SUCCEDED succeded, $FAILED failed, $TODO todo."
|
|
if [ $SUCCEDED -eq $RAN ];
|
|
then
|
|
echo "All integration tests passed!"
|
|
else
|
|
echo "cat report.txt"
|
|
echo "to see details of failed/todo tests"
|
|
fi
|
|
exit $FAILED
|
|
}
|
|
|
|
setup
|
|
|
|
when_run <<EOF "empty inputs returns nothing"
|
|
|
|
EOF
|
|
expecting <<EOF
|
|
EOF
|
|
|
|
when_run <<EOF "simple commands are run"
|
|
echo no files:
|
|
ls -a
|
|
touch t
|
|
echo single file:
|
|
ls -a
|
|
EOF
|
|
expecting <<EOF
|
|
no files:
|
|
.
|
|
..
|
|
single file:
|
|
.
|
|
..
|
|
t
|
|
EOF
|
|
|
|
when_run <<EOF "unknown commands"
|
|
qwertyuiop
|
|
poiuytrewq
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: qwertyuiop: command not found
|
|
minishell: poiuytrewq: command not found
|
|
EOF
|
|
|
|
when_run <<EOF "pwd works"
|
|
pwd
|
|
pwd hello
|
|
pwd hello there
|
|
pwd -O
|
|
pwd -O hello
|
|
pwd there -O hello
|
|
EOF
|
|
expecting <<EOF
|
|
/tmp/dir.minishell
|
|
/tmp/dir.minishell
|
|
/tmp/dir.minishell
|
|
/tmp/dir.minishell
|
|
/tmp/dir.minishell
|
|
/tmp/dir.minishell
|
|
EOF
|
|
|
|
when_run <<EOF "pwd works in any directory, can cd to absolute paths"
|
|
mkdir test
|
|
cd /tmp/dir.minishell/test
|
|
pwd
|
|
mkdir hi
|
|
cd /tmp/dir.minishell/test/hi
|
|
pwd
|
|
cd /tmp/dir.minishell/test
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
/tmp/dir.minishell/test
|
|
/tmp/dir.minishell/test/hi
|
|
/tmp/dir.minishell/test
|
|
EOF
|
|
|
|
when_run <<EOF "cd will print error when going into a directory with no access"
|
|
mkdir test
|
|
chmod -x test
|
|
cd test
|
|
pwd
|
|
chmod +x test
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: cd: Permission denied
|
|
/tmp/dir.minishell
|
|
EOF
|
|
|
|
EXTRAENV="HOME=/tmp/dir.minishell/fakehome"
|
|
when_run <<EOF "cd with no arguments goes to \$HOME"
|
|
mkdir fakehome
|
|
cd
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
/tmp/dir.minishell/fakehome
|
|
EOF
|
|
|
|
EXTRAENV="-u HOME"
|
|
when_run <<EOF "cd with no arguments, with HOME unset, prints error message and does nothing"
|
|
cd
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: cd: HOME not set
|
|
/tmp/dir.minishell
|
|
EOF
|
|
|
|
when_run <<EOF "cd with empty argument"
|
|
cd ""
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
/tmp/dir.minishell
|
|
EOF
|
|
|
|
EXTRAENV="HOME="
|
|
when_run <<EOF "cd with no arguments and HOME equal to empty string"
|
|
cd
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
/tmp/dir.minishell
|
|
EOF
|
|
|
|
when_run <<EOF "cd with simple relative paths"
|
|
mkdir test
|
|
cd test
|
|
pwd
|
|
cd ..
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
/tmp/dir.minishell/test
|
|
/tmp/dir.minishell
|
|
EOF
|
|
|
|
when_run <<EOF "cd with complicated relative paths"
|
|
mkdir -p test/hello/there
|
|
mkdir -p test/hi/there
|
|
mkdir -p test/hello/world
|
|
cd test/hello/there
|
|
pwd
|
|
cd ../../hi
|
|
pwd
|
|
cd ../hi/../hi/../hi/../hi
|
|
pwd
|
|
cd ../hi/../hi/../hi/../hi/../../test/hello/world
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
/tmp/dir.minishell/test/hello/there
|
|
/tmp/dir.minishell/test/hi
|
|
/tmp/dir.minishell/test/hi
|
|
/tmp/dir.minishell/test/hello/world
|
|
EOF
|
|
|
|
when_run <<EOF "cd print error when given too many arguments"
|
|
cd hello there
|
|
pwd
|
|
cd . ..
|
|
pwd
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: cd: too many arguments
|
|
/tmp/dir.minishell
|
|
minishell: cd: too many arguments
|
|
/tmp/dir.minishell
|
|
EOF
|
|
|
|
EXTRAENV="VAR=value hello=bye"
|
|
when_run <<"EOF" "variable substitution works"
|
|
echo $VAR $hello
|
|
EOF
|
|
expecting <<EOF
|
|
value bye
|
|
EOF
|
|
|
|
when_run <<"EOF" "export works with single variable"
|
|
export var=testvalue
|
|
echo var=$var
|
|
export var="Another Test Value"
|
|
echo var=$var
|
|
EOF
|
|
expecting <<EOF
|
|
var=testvalue
|
|
var=Another Test Value
|
|
EOF
|
|
|
|
when_run <<"EOF" "export works with multiple variables"
|
|
export name="Sir Reginald Pikedevant" greeting="Well met," counter=27 "question=How many fingers am I holding up?"
|
|
echo $greeting $name
|
|
echo $question
|
|
echo Umm, $counter?
|
|
EOF
|
|
expecting <<EOF
|
|
Well met, Sir Reginald Pikedevant
|
|
How many fingers am I holding up?
|
|
Umm, 27?
|
|
EOF
|
|
|
|
EXTRAENV=-i
|
|
when_run <<EOF "export with strange inputs"
|
|
export ENV=$(which env)
|
|
export PATH=$PATH
|
|
export var
|
|
echo status=\$?
|
|
echo var=[\$var]
|
|
export blue=
|
|
echo status=\$?
|
|
echo blue=[\$blue]
|
|
\$ENV -u PATH -u ENV env
|
|
EOF
|
|
expecting <<EOF
|
|
status=0
|
|
var=[]
|
|
status=0
|
|
blue=[]
|
|
blue=
|
|
EOF
|
|
|
|
when_run <<"EOF" "export with invalid identifiers"
|
|
export = 123=456 hello=hi 456=789
|
|
echo status=$?
|
|
echo hello=$hello
|
|
EOF
|
|
expecting <<"EOF"
|
|
minishell: export: `=': not a valid identifier
|
|
minishell: export: `123=456': not a valid identifier
|
|
minishell: export: `456=789': not a valid identifier
|
|
status=1
|
|
hello=hi
|
|
EOF
|
|
|
|
when_run <<EOF "empty command is not found"
|
|
""
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: : command not found
|
|
EOF
|
|
|
|
when_run <<EOF "exit status of last command is preserved"
|
|
echo \$?
|
|
ls nonexist
|
|
echo \$?
|
|
echo hi
|
|
echo \$?
|
|
EOF
|
|
expecting <<EOF
|
|
0
|
|
ls: cannot access 'nonexist': No such file or directory
|
|
2
|
|
hi
|
|
0
|
|
EOF
|
|
|
|
when_run <<EOF "exit works"
|
|
$MINISHELL
|
|
exit
|
|
echo \$?
|
|
EOF
|
|
expecting <<EOF
|
|
0
|
|
EOF
|
|
|
|
when_run <<EOF "exit works with custom exit code"
|
|
$MINISHELL
|
|
exit 99
|
|
echo \$?
|
|
EOF
|
|
expecting <<EOF
|
|
99
|
|
EOF
|
|
|
|
when_run <<EOF "exit works with extreme exit codes"
|
|
$MINISHELL
|
|
exit 1234567890
|
|
echo \$?
|
|
$MINISHELL
|
|
exit -1234567890
|
|
echo \$?
|
|
EOF
|
|
expecting <<EOF
|
|
210
|
|
46
|
|
EOF
|
|
|
|
when_run <<EOF "exit works with nan input"
|
|
$MINISHELL
|
|
exit not-a-number
|
|
echo \$?
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: exit: not-a-number: numeric argument required
|
|
2
|
|
EOF
|
|
|
|
when_run <<EOF "exit works with too many arguments"
|
|
$MINISHELL
|
|
exit 1 2
|
|
echo \$?
|
|
exit
|
|
echo \$?
|
|
$MINISHELL
|
|
exit not-a-number 3
|
|
echo \$?
|
|
$MINISHELL
|
|
exit 3 not-a-number
|
|
echo \$?
|
|
exit
|
|
echo \$?
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: exit: too many arguments
|
|
1
|
|
0
|
|
minishell: exit: not-a-number: numeric argument required
|
|
2
|
|
minishell: exit: too many arguments
|
|
1
|
|
0
|
|
EOF
|
|
|
|
when_run <<EOF "echo basic tests"
|
|
echo hello world
|
|
echo "Hello World"
|
|
EOF
|
|
expecting <<EOF
|
|
hello world
|
|
Hello World
|
|
EOF
|
|
|
|
when_run <<EOF "echo -n tests"
|
|
echo -n hello world
|
|
echo
|
|
echo -nnnnnnnnnnnnnnnn hello world
|
|
echo
|
|
echo -nnnntnnnnnnnnnnnn hello world
|
|
echo hi -n hello
|
|
echo -n -n -nnn -n goodbye
|
|
echo
|
|
EOF
|
|
expecting <<EOF
|
|
hello world
|
|
hello world
|
|
-nnnntnnnnnnnnnnnn hello world
|
|
hi -n hello
|
|
goodbye
|
|
EOF
|
|
|
|
when_run <<EOF "echo - n"
|
|
echo - n hi
|
|
EOF
|
|
expecting <<EOF
|
|
- n hi
|
|
EOF
|
|
|
|
EXTRAENV="-i"
|
|
when_run <<EOF "env works"
|
|
echo this should be empty:
|
|
env
|
|
echo
|
|
export var=VALUE hi=hello bye=goodbye
|
|
echo this contains some values
|
|
env
|
|
unset var bye
|
|
echo some vars were unset
|
|
env
|
|
EOF
|
|
expecting <<EOF
|
|
this should be empty:
|
|
|
|
this contains some values
|
|
var=VALUE
|
|
hi=hello
|
|
bye=goodbye
|
|
some vars were unset
|
|
hi=hello
|
|
EOF
|
|
|
|
EXTRAENV="-i"
|
|
when_run <<EOF "env ignores additional arguments"
|
|
export var=VALUE hi=hello bye=goodbye
|
|
env -i name="The Other" ls
|
|
EOF
|
|
expecting <<EOF
|
|
minishell: env: ignoring arguments
|
|
var=VALUE
|
|
hi=hello
|
|
bye=goodbye
|
|
EOF
|
|
|
|
when_run <<EOF "quoted parentheses are not operators"
|
|
echo unclosed '('
|
|
EOF
|
|
todo
|
|
|
|
finalize
|