#!/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" # globale variables MINISHELL="../minishell" TEST_DIR="./tests/" DEFAULT_DIR="./tests/defaults/" UNIT_TEST=0 SUCCESS_TEST=0 TOTAL_TEST=0 TOTAL_SUCCESS=0 LINE_NUMBER=0 LIST_FILES="" DEFAULT_FILES="" ARGS_MAIN=$@ mkdir -p ./logs echo "" > ./logs/bash_log.txt echo "" > ./logs/minishell_log.txt FILES_BEFORE="$(ls .)" BASH_LOG="./logs/bash_log.txt" MINISHELL_LOG="./logs/minishell_log.txt" # copy the executable to current directory cp $MINISHELL . # to delete the files created during the script function delete_files { files_after="$(ls .)" diff_files="$(comm -3 <(echo "$FILES_BEFORE") <(echo "$files_after"))" while read -r line_diff do rm -rf "$line_diff" done < <(echo "$diff_files") } # handle sigint signal function handler_sigint { delete_files exit 0 } trap 'handler_sigint' 2 # default list of files to be use DEFAULT_FILES="$( find $DEFAULT_DIR | tail -n+2 )" # print usage function print_usage { echo -en $GREEN"usage : " echo -en $CYAN"bash unitest.sh [help] [files list ...]\n" echo -en $GREEN"\n[help]\n" echo -en $CYAN"print usage\n" echo -en $GREEN"\n[files list ...] if empty, defaults files will be used :\n" echo -en $CYAN"$DEFAULT_FILES" echo -en $ENDCO"\n" echo "" } # 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 delete_files 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%.sh}" file="${file/%/.sh}" if ! [ -e "$file" ] then file="${!i/#/$TEST_DIR}" file="${file%.sh}" file="${file/%/.sh}" fi if ! [ -e "$file" ] then file="${!i/#/$DEFAULT_DIR}" file="${file%.sh}" file="${file/%/.sh}" fi 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 2>/dev/null ) minishell_execution=$( echo "$@" | ./minishell 2>/dev/null ) #compare output if [ "$bash_execution" = "$minishell_execution" ] then (( SUCCESS_TEST++ )) (( TOTAL_SUCCESS++ )) else error_cmd="ERROR line $(( $LINE_NUMBER - 1 )), command : " print_next_command "$error_cmd" "$@" "$CYAN" # 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 delete_files