448 lines
11 KiB
Bash
448 lines
11 KiB
Bash
#!/bin/bash
|
|
cd $(dirname $0)
|
|
|
|
# COLORS
|
|
RED="\e[0;31m"
|
|
GREEN="\e[0;32m"
|
|
YELLOW="\e[0;33m"
|
|
BLUE="\e[0;34m"
|
|
MAGENTA="\e[0;35m"
|
|
CYAN="\e[0;36m"
|
|
WHITE="\e[0;37m"
|
|
|
|
B_RED="\e[1;31m"
|
|
B_GREEN="\e[1;32m"
|
|
B_YELLOW="\e[1;33m"
|
|
B_BLUE="\e[1;34m"
|
|
B_MAGENTA="\e[1;35m"
|
|
B_CYAN="\e[1;36m"
|
|
B_WHITE="\e[1;37m"
|
|
|
|
ENDCO="\e[0m"
|
|
|
|
# copy the executable to current directory
|
|
MINISHELL_DIR="../"
|
|
make -C $MINISHELL_DIR &>/dev/null
|
|
cp $MINISHELL_DIR/minishell .
|
|
|
|
# globale variables
|
|
CURRENT_D="$(pwd)"
|
|
VPATH=" $CURRENT_D/
|
|
$CURRENT_D/tests/
|
|
$CURRENT_D/tests/defaults/
|
|
"
|
|
DEFAULT_DIR="$CURRENT_D/tests/defaults/"
|
|
DEFAULT_DIR_USAGE="./tests/defaults/"
|
|
UNIT_TEST=0
|
|
SUCCESS_TEST=0
|
|
TOTAL_TEST=0
|
|
TOTAL_SUCCESS=0
|
|
LINE_NUMBER=0
|
|
CMD_NBR=0
|
|
# options
|
|
ERROR=0
|
|
VALGR=0
|
|
OMMIT=0
|
|
LIST_FILES=""
|
|
DEFAULT_FILES=""
|
|
DEFAULT_FILES_USAGE=""
|
|
VALGRIND_OUTPUT_REF=""
|
|
ARGS_MAIN=$@
|
|
mkdir -p ./logs
|
|
echo "" > ./logs/bash_log.txt
|
|
echo "" > ./logs/minishell_log.txt
|
|
echo "" > ./logs/valgrind.log
|
|
BASH_LOG="$CURRENT_D/logs/bash_log.txt"
|
|
MINISHELL_LOG="$CURRENT_D/logs/minishell_log.txt"
|
|
|
|
# check ROOT access :
|
|
ROOT=$( whoami )
|
|
if [ "$ROOT" == "root" ]
|
|
then
|
|
ROOT=1
|
|
else
|
|
ROOT=0
|
|
fi
|
|
|
|
|
|
# default list of files to be use
|
|
DEFAULT_FILES="$( find $DEFAULT_DIR -type f ! -iname ".*" -iname "*.sh" )"
|
|
DEFAULT_FILES_USAGE="$( find $DEFAULT_DIR_USAGE -type f ! -iname ".*" -iname "*.sh" )"
|
|
|
|
# move project to a temp file
|
|
mkdir -p tmp
|
|
cd tmp
|
|
|
|
# handle sigint signal
|
|
function handler_sigint
|
|
{
|
|
cd $CURRENT_D
|
|
rm -r $CURRENT_D/tmp/
|
|
exit 0
|
|
}
|
|
trap 'handler_sigint' 2
|
|
|
|
# print usage
|
|
function print_usage
|
|
{
|
|
echo -en $GREEN"usage :\n"
|
|
echo -en $CYAN"bash unitest.sh [option] [files list ...]\n"
|
|
echo -en $GREEN"or (to test signals and ctrl-d) :\n"
|
|
echo -en $CYAN"sudo bash unitest.sh [option] [files list ...]\n"
|
|
echo -en $GREEN"\n[options]\n"
|
|
echo -en $CYAN"-help : print usage\n"
|
|
echo -en $CYAN" -e : print tests commands\n"
|
|
echo -en $CYAN" -v : test valgrin, don't compare with bash\n"
|
|
echo -en $CYAN" -o : ommit following files\n"
|
|
echo -en $GREEN"\n[files list ...] if empty, defaults files will be used :\n"
|
|
echo -en $CYAN"$DEFAULT_FILES_USAGE"
|
|
echo -en $ENDCO"\n"
|
|
echo ""
|
|
}
|
|
|
|
# function to find the path of a file in argument
|
|
function find_path
|
|
{
|
|
file_ori="$file"
|
|
for x in $VPATH
|
|
do
|
|
file="${file_ori/#/$x}"
|
|
file="${file%.sh}"
|
|
file="${file/%/.sh}"
|
|
if [ -e "$file" ]
|
|
then
|
|
break
|
|
fi
|
|
done
|
|
}
|
|
|
|
# check for arguments, like options or files list
|
|
# if no file in arguments, default file list is used
|
|
function parse_arguments
|
|
{
|
|
LIST_FILES="$DEFAULT_FILES"
|
|
if [ $# -gt 0 ]
|
|
then
|
|
if [ "$1" == "-help" ]
|
|
then
|
|
print_usage
|
|
cd $CURRENT_D
|
|
rm -r $CURRENT_D/tmp/
|
|
exit 0
|
|
else
|
|
LIST_FILES=""
|
|
for (( i = 1 ; i <= "$#" ; i++ ))
|
|
do
|
|
# the ! is for indirect parameter expansion
|
|
# $i expand in integers 1,2,3...
|
|
# $1,$2,$3... expand in arguments of process call
|
|
file="${!i}"
|
|
if [ "$file" = "-e" ]
|
|
then
|
|
ERROR=1
|
|
if [ $# -eq 1 ]
|
|
then
|
|
LIST_FILES="$DEFAULT_FILES"
|
|
break
|
|
fi
|
|
elif [ "$file" = "-v" ]
|
|
then
|
|
VALGR=1
|
|
if [ $# -eq 1 ]
|
|
then
|
|
LIST_FILES="$DEFAULT_FILES"
|
|
break
|
|
fi
|
|
elif [ "$file" = "-o" ]
|
|
then
|
|
OMMIT=1
|
|
LIST_FILES="$DEFAULT_FILES"
|
|
else
|
|
find_path
|
|
if [ -e "$file" ]
|
|
then
|
|
if [ $OMMIT -eq 1 ]
|
|
then
|
|
LIST_FILES="$( echo "$LIST_FILES" | grep -v "$file")"
|
|
else
|
|
if [ -n "$LIST_FILES" ]
|
|
then
|
|
LIST_FILES+=$'\n'
|
|
fi
|
|
LIST_FILES+="$file"
|
|
fi
|
|
else
|
|
print_usage
|
|
echo " <$file> is not a valid file or option, see usage above"
|
|
exit 0
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# if print option, print next command
|
|
# receive parameters : $1 text presenting command, $2 command itself, $3 color for text
|
|
function print_command
|
|
{
|
|
text=$1
|
|
cmd=$2
|
|
color=$3
|
|
indent="$(for (( i=1; i<=${#text}; i++ )); do echo -n ' '; done)"
|
|
echo -en $color"$text"$YELLOW
|
|
echo -n "${cmd//$'\n'/$'\n'$indent}"
|
|
echo -e $ENDCO
|
|
}
|
|
|
|
# compare the execution output and mark and print the success or failure
|
|
# receive parameters : $1 bash execution output, $2 minishell execution output, $3 commands
|
|
function compare_output
|
|
{
|
|
bash_output="$1"
|
|
minishell_output="$2"
|
|
sent_commands="$3"
|
|
if [ "$bash_output" = "$minishell_output" ]
|
|
then
|
|
(( SUCCESS_TEST++ ))
|
|
(( TOTAL_SUCCESS++ ))
|
|
else
|
|
# print failed commands in case of option -e
|
|
if [ $ERROR -eq 1 ] && [ $VALGR -eq 0 ]
|
|
then
|
|
failure_cmd="FAILURE line $(( $LINE_NUMBER - 1 )), command : "
|
|
print_command "$failure_cmd" "$3" "$MAGENTA"
|
|
fi
|
|
# print simple log
|
|
echo -e $B_WHITE"\n\n$3\n-----------"$ENDCO >>$BASH_LOG
|
|
echo "$bash_output" >> $BASH_LOG
|
|
echo -e $B_WHITE"\n\n$3\n-----------"$ENDCO >>$MINISHELL_LOG
|
|
echo "$minishell_output" >> $MINISHELL_LOG
|
|
fi
|
|
}
|
|
|
|
# WIP
|
|
# function that send the command to fd-0
|
|
function send_command
|
|
{
|
|
# find pid of programm (in a loop in case it didn't start already)
|
|
PID=""
|
|
while [ -z "$PID" ]
|
|
do
|
|
PID="$( pidof minishell )"
|
|
done
|
|
|
|
#VAR="\4"
|
|
#kill -s INT `pidof minishell`
|
|
while read -r line
|
|
do
|
|
printf "${line}\n" | ./tiocsti >/proc/"$PID"/fd/0
|
|
#printf "$VAR" | ./tiocsti >/proc/"$PID"/fd/0
|
|
done < <(echo "$CONCAT")
|
|
|
|
# kill the process when programm is done
|
|
FINISH=0
|
|
while [ ! "$FINISH" -eq 1 ]
|
|
do
|
|
kill -0 "$PID" 2>/dev/null
|
|
FINISH=$( echo $? )
|
|
done
|
|
}
|
|
|
|
# function test minishell in classic script mode and handle signals and ctrl-d
|
|
function test_minishell_signals
|
|
{
|
|
# in this order, so that it's not the minishell or bash that goes in background
|
|
bash_execution=$( send_command & bash 2>/dev/null )
|
|
rm -rf $CURRENT_D/tmp/*
|
|
minishell_execution=$( send_command & $CURRENT_D/minishell 2>/dev/null )
|
|
rm -rf $CURRENT_D/tmp/*
|
|
}
|
|
|
|
# function test minishell in classic script mode, but cannot handle signals and ctrl-d
|
|
function test_minishell_script
|
|
{
|
|
bash_execution=$( bash <<<"$commands" 2>/dev/null )
|
|
rm -rf $CURRENT_D/tmp/*
|
|
minishell_execution=$( $CURRENT_D/minishell <<<"$commands" 2>/dev/null )
|
|
rm -rf $CURRENT_D/tmp/*
|
|
}
|
|
|
|
# function test minishell in classic script mode, but cannot handle signals and ctrl-d
|
|
function test_minishell_valgrind
|
|
{
|
|
valgrind="valgrind --suppressions=../valgrind_readline.supp --leak-check=full --show-reachable=yes --track-fds=yes --track-origins=yes"
|
|
minishell_execution=$( $valgrind $CURRENT_D/minishell <<<"$commands" 2>../logs/valgrind.log )
|
|
valgrind_output="$( cat ../logs/valgrind.log | grep -e "ERROR SUMMARY: " -e "definitely lost: " -e "indirectly lost: " -e "possibly lost: " -e "still reachable: " -e "FILE DESCRIPTORS: " )"
|
|
valgrind_output="$( cut -c 13- <<< "$valgrind_output" )"
|
|
|
|
valgrind_error="$( echo "$valgrind_output" | grep [1-9] )"
|
|
if [ -n "$valgrind_error" ]
|
|
then
|
|
echo -e $B_RED"line: $LINE_NUMBER, command: "$YELLOW$commands$ENDCO
|
|
echo "$valgrind_output"
|
|
fi
|
|
|
|
rm -rf $CURRENT_D/tmp/*
|
|
}
|
|
|
|
# function that will launch the command in bash and minishell and compare them
|
|
# receive parameters : $1 commands to execute, $2 name of the file
|
|
function test_minishell
|
|
{
|
|
commands="$1"
|
|
in_file="$2"
|
|
bash_execution=""
|
|
minishell_execution=""
|
|
|
|
# execute commands, and logs results
|
|
if [ $ROOT -eq 1 ]
|
|
then
|
|
test_minishell_signals
|
|
elif [ $VALGR -eq 1 ]
|
|
then
|
|
test_minishell_valgrind
|
|
else
|
|
test_minishell_script
|
|
fi
|
|
|
|
# for env, special treatment
|
|
if [ "${in_file: -6}" == "env.sh" ]
|
|
then
|
|
bash_execution="$( echo "$bash_execution" | sort | grep -v -e "LINES=" -e "COLUMNS=" -e "_=" -e"LESSCLOSE=" -e "LESSOPEN=" -e "SHLVL=" )"
|
|
minishell_execution="$( echo "$minishell_execution" | sort | grep -v -e "LINES=" -e "COLUMNS=" -e "_=" -e"LESSCLOSE=" -e "LESSOPEN=" -e "SHLVL=" )"
|
|
fi
|
|
|
|
if [ "$VALGR" -eq 0 ]
|
|
then
|
|
compare_output "$bash_execution" "$minishell_execution" "$commands"
|
|
fi
|
|
}
|
|
|
|
# function to print the results
|
|
# receive parameters : $1 file name, $2 numerator, $3 denominator
|
|
function print_results
|
|
{
|
|
the_file="$1"
|
|
successful_test="$2"
|
|
num_of_test="$3"
|
|
echo -en $B_WHITE"results for "$the_file" : "$ENDCO
|
|
if [ "$successful_test" -eq 0 ]
|
|
then
|
|
if [ "$num_of_test" -eq 0 ]
|
|
then
|
|
echo -en $B_WHITE "$successful_test" $ENDCO
|
|
else
|
|
echo -en $B_RED "$successful_test" $ENDCO
|
|
fi
|
|
elif [ "$successful_test" -eq "$num_of_test" ]
|
|
then
|
|
echo -en $B_GREEN "$successful_test" $ENDCO
|
|
else
|
|
echo -en $B_MAGENTA "$successful_test" $ENDCO
|
|
fi
|
|
echo -e $B_WHITE"/ "$num_of_test""$ENDCO
|
|
}
|
|
|
|
# function that read the commands of each file
|
|
# receive parameters : $1 file name, $2 last line number
|
|
function read_commands
|
|
{
|
|
file="$1"
|
|
last_line="$2"
|
|
command_test=""
|
|
while read -r line
|
|
do
|
|
(( LINE_NUMBER++ ))
|
|
# concatenate the commands
|
|
if [ -n "$line" ]
|
|
then
|
|
# if line start with # skip it
|
|
if [ "${line:0:1}" != "#" ]
|
|
then
|
|
if [ "$command_test" == "" ]
|
|
then
|
|
command_test="$line"
|
|
else
|
|
command_test+=$'\n'
|
|
command_test+="$line"
|
|
fi
|
|
# if last line of file, execute here or else next loop will loose it
|
|
if [ $LINE_NUMBER -eq $last_line ]
|
|
then
|
|
(( UNIT_TEST++ ))
|
|
(( TOTAL_TEST++ ))
|
|
test_minishell "$command_test" "$file"
|
|
fi
|
|
fi
|
|
# execute (concatenated) commands
|
|
elif [ -z "$line" ] && [ -n "$command_test" ]
|
|
then
|
|
(( UNIT_TEST++ ))
|
|
(( TOTAL_TEST++ ))
|
|
test_minishell "$command_test" "$file"
|
|
command_test=""
|
|
fi
|
|
done < $file
|
|
}
|
|
|
|
# the main loop: go through the files and call the compare func on each commands
|
|
# parse tests files line by line, grouping lines non-separated by an empty line
|
|
# if line start with # it's ignore
|
|
function read_files
|
|
{
|
|
for i in $LIST_FILES
|
|
do
|
|
filename=$i
|
|
echo -e "\n"$B_YELLOW"test file : ${filename##*/}"$ENDCO
|
|
LINE_NUMBER=0
|
|
last_line_number=$(wc -l < $filename)
|
|
UNIT_TEST=0
|
|
SUCCESS_TEST=0
|
|
# write name of file in log files
|
|
echo -en $B_YELLOW "\n\n\nfile: ${filename##*/}\n" $ENDCO >>$BASH_LOG
|
|
echo -en $B_YELLOW "\n\n\nfile: ${filename##*/}\n" $ENDCO >>$MINISHELL_LOG
|
|
read_commands "$filename" "$last_line_number"
|
|
# '##' print from the right untill... '*/' s slash
|
|
if [ "$VALGR" -eq 0 ]
|
|
then
|
|
print_results ${filename##*/} $SUCCESS_TEST $UNIT_TEST
|
|
fi
|
|
done
|
|
}
|
|
|
|
# print the total results
|
|
function print_total_result
|
|
{
|
|
if [ -n "$LIST_FILES" ]
|
|
then
|
|
echo ""
|
|
print_results "all" $TOTAL_SUCCESS $TOTAL_TEST
|
|
fi
|
|
}
|
|
|
|
# ask to show the diff
|
|
# -rsn1 will stop read after first key pressed
|
|
function show_diff
|
|
{
|
|
if [ $TOTAL_SUCCESS -lt $TOTAL_TEST ]
|
|
then
|
|
read -rsn1 -p 'if you want to see the diff, press "y"' DIFF
|
|
if [[ "${DIFF,,}" == y ]]
|
|
then
|
|
diff -y --width=100 --color=always "$BASH_LOG" "$MINISHELL_LOG"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# execute script :
|
|
parse_arguments $ARGS_MAIN
|
|
read_files
|
|
if [ "$VALGR" -eq 0 ]
|
|
then
|
|
print_total_result
|
|
show_diff
|
|
fi
|
|
cd $CURRENT_D
|
|
rm -r $CURRENT_D/tmp/
|