#!/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="../minishell" make -C ../ &>/dev/null cp $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 PRINT=0 LIST_FILES="" DEFAULT_FILES="" DEFAULT_FILES_USAGE="" ARGS_MAIN=$@ mkdir -p ./logs echo "" > ./logs/bash_log.txt echo "" > ./logs/minishell_log.txt 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 | tail -n+2 )" DEFAULT_FILES_USAGE="$( find $DEFAULT_DIR_USAGE | tail -n+2 )" # 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"\n[options]\n" echo -en $CYAN"help : print usage\n" echo -en $CYAN" -p : print tests commands\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" = "-p" ] then PRINT=1 if [ $# -eq 1 ] then LIST_FILES="$DEFAULT_FILES" break else continue fi fi find_path if [ -e "$file" ] then if [ -n "$LIST_FILES" ] then LIST_FILES+=$'\n' fi LIST_FILES+="$file" else print_usage echo " <$file> is not a valid file or option, see usage above" exit 0 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 function compare_output { bash_output="$1" minishell_output="$2" if [ "$bash_output" = "$minishell_output" ] then (( SUCCESS_TEST++ )) (( TOTAL_SUCCESS++ )) else # print failed commands in case of option -p if [ $PRINT -eq 1 ] then failure_cmd="FAILURE line $(( $LINE_NUMBER - 1 )), command : " print_command "$failure_cmd" "$@" "$MAGENTA" fi # print simple log echo -e $B_WHITE"\n\n$@\n-----------"$ENDCO >>$BASH_LOG echo "$bash_output" >> $BASH_LOG echo -e $B_WHITE"\n\n$@\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 script mode, it cannot handle signals and ctrl-d function test_minishell_interactif { # 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 script mode, it cannot handle signals and ctrl-d # receive parameters : $1 commands to execute, $2 name of the file function test_minishell_script { bash_execution=$( echo "$commands" | bash 2>/dev/null ) rm -rf $CURRENT_D/tmp/* minishell_execution=$( echo "$commands" | $CURRENT_D/minishell 2>/dev/null ) 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_interactif 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=" )" minishell_execution="$( echo "$minishell_execution" | sort | grep -v -e "LINES=" -e "COLUMNS=" -e "_=" -e"LESSCLOSE=" -e "LESSOPEN=" )" fi compare_output "$bash_execution" "$minishell_execution" } # 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 print_results ${filename##*/} $SUCCESS_TEST $UNIT_TEST 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 print_total_result show_diff cd $CURRENT_D rm -r $CURRENT_D/tmp/