#!/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" # 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 function print_next_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 } # function that will launch the command in bash and minishell and compare them function test_minishell { # execute commands in bash, and logs results bash_execution=$( echo "$@" | bash -i 2>/dev/null ) rm -rf $CURRENT_D/tmp/* minishell_execution=$( echo "$@" | $CURRENT_D/minishell 2>/dev/null ) rm -rf $CURRENT_D/tmp/* # for env, special treatment 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=" )" #compare output if [ "$bash_execution" = "$minishell_execution" ] then (( SUCCESS_TEST++ )) (( TOTAL_SUCCESS++ )) # if uncommented, print all commands in case of option -p # if [ $PRINT -eq 1 ] # then # success_cmd="success line $(( $LINE_NUMBER - 1 )), command : " # print_next_command "$success_cmd" "$@" "$CYAN" # fi else if [ $PRINT -eq 1 ] then failure_cmd="FAILURE line $(( $LINE_NUMBER - 1 )), command : " print_next_command "$failure_cmd" "$@" "$MAGENTA" fi # print simple log echo -e $B_WHITE"\n\n$@\n-----------"$ENDCO >>$BASH_LOG echo "$bash_execution" >> $BASH_LOG echo -e $B_WHITE"\n\n$@\n-----------"$ENDCO >>$MINISHELL_LOG echo "$minishell_execution" >> $MINISHELL_LOG fi } # function to print the results # receive parameters : file name, numerator, denominator function print_results { echo -en $B_WHITE"results for $1 : "$ENDCO if [ $2 -eq 0 ] then echo -en $B_RED $2 $ENDCO elif [ $2 -eq $3 ] then echo -en $B_GREEN $2 $ENDCO else echo -en $B_MAGENTA $2 $ENDCO fi echo -e $B_WHITE"/ $3"$ENDCO } # function that read the commands of each file function read_commands { 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_number ] then (( UNIT_TEST++ )) (( TOTAL_TEST++ )) test_minishell "$command_test" fi fi # execute (concatenated) commands elif [ -z "$line" ] && [ -n "$command_test" ] then (( UNIT_TEST++ )) (( TOTAL_TEST++ )) test_minishell "$command_test" command_test="" fi done < $filename } # 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 : $i"$ENDCO command_test="" 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 print_results $i $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/