-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathTest.sh
executable file
·221 lines (192 loc) · 5.31 KB
/
Test.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#!/bin/bash
# ====================
# 2019 Matúš Chovan
# ====================
# Variables from outside
source_path=""
test_filter=""
differences=0
cleanup=0
time_limit=1
# Inside variables
header="Simple C Program Tester for LINUX"
usage="Usage: ./TestLinux.sh <source_program.c> [OPTIONS...]"
help_format="%3s %-30s %s\n"
ferr="\e[1m\e[31m[-]\e[39m\e[0m"
fok="\e[1m\e[32m[+]\e[39m\e[0m"
finfo="\e[1m\e[34m[*]\e[39m\e[0m"
output_dir="build"
tests_dir="tests"
run_dir="runs"
exec="`pwd`/$output_dir/a.out"
source_name=""
use_rsync=1
let passed=0
let failed=0
let omitted=0
# Print usage
helpmenu() {
echo
echo $header
echo $usage
echo
printf "$help_format" "-h" "--help" "Display this menu"
printf "$help_format" "-f" "--filter NAME" "Run specific test with name NAME"
printf "$help_format" "-d" "--differences" "Display whole expected and actual output instead of only differences"
printf "$help_format" "-c" "--cleanup" "Delete generated outputs after finishing"
printf "$help_format" "-t" "--timeout TIME" "Set programs execution time limit in seconds. Program will be killed after time limit is exceeded."
echo
echo "Flags need to be typed separately. Ex: './Test.sh ... -dc' will not work. You have to type './Test.sh ... -d -c'"
}
# Compile src with gcc
compile() {
command -v gcc >> /dev/null
if [ $? -gt 0 ]; then
echo "$ferr GCC in not installed or not in PATH"
exit
fi
if [ ! -d "$output_dir" ]; then mkdir $output_dir; fi
echo -e "$finfo Compiling..."
gcc $source_path -o $exec -lm
}
# $1 => test directory path
test() {
test=${1##*/}
echo -e "$finfo Executing test case $test"
# Reset test's run folder
if [ -d "$run_dir/$source_name/$test" ]; then find "$run_dir/$source_name/$test" -type f -delete; fi
if [ $use_rsync -eq 1 ];then
rsync -r --exclude="expected.txt" "`pwd`/$tests_dir/$test/" "`pwd`/$run_dir/$source_name/$test/"
else
if [ ! -d "`pwd`/$run_dir/$source_name/$test/" ]; then mkdir "`pwd`/$run_dir/$source_name/$test/"; fi
find "`pwd`/$tests_dir/$test/" -mindepth 1 -path "`pwd`/$tests_dir/$test/expected.txt" -prune -o -exec cp '{}' "`pwd`/$run_dir/$source_name/$test/" \;
fi
# Run C program with redirected outputs in new spawned shell
(cd "$run_dir/$source_name/$test" && exec timeout "$time_limit"s $exec < "input.txt" > "output.txt" 2>"error.txt")
# Check if program failed (check status codes)
exit_code=$?
if [ $exit_code -eq 124 ]; then
echo -e "$ferr Allowed program runtime exceeded"
return
elif [ ! $exit_code == 0 ]; then
echo -e "$ferr Failed with exit code $exit_code"
return
fi
# Check program output with expected results
diff -ZB "$run_dir/$source_name/$test/output.txt" "$tests_dir/$test/expected.txt" >> /dev/null
result=$?
if [ $result -eq 0 ]; then
echo -e "$fok PASSED"
((passed++))
else
echo -e "$ferr FAILED"
((failed++))
if [ $differences -eq 0 ]; then
diff "$run_dir/$source_name/$test/output.txt" "$tests_dir/$test/expected.txt"
else
echo "##### actual #####"
cat "$run_dir/$source_name/$test/output.txt"
echo "---- expected ----"
cat "$run_dir/$source_name/$test/expected.txt"
echo "##################"
fi
fi
}
# Find all subdirectories in test/, pick the ones that
# match the filter and sort them
# Then run tests within these folders
runtests() {
echo -e "$finfo Running tests\n"
if [ ! -d "$run_dir" ]; then mkdir "$run_dir"; fi
if [ ! -d "$run_dir/$source_name" ]; then mkdir "$run_dir/$source_name"; fi
for tdir in `find ./$tests_dir -mindepth 1 -type d | grep "$test_filter" | sort`
do
echo "=============================="
if [ ! -f "$tdir/input.txt" ] || [ ! -f "$tdir/expected.txt" ]; then
echo -e "$ferr Skipping '${tdir##*/}', test files missing"
((omitted++))
continue
fi
test $tdir
done
echo
}
# Cleanup compiled files and copied files
cleanup() {
echo -e "$finfo Cleaning up"
rm "$exec"
if [ ! $cleanup -eq 0 ]; then find $run_dir -mindepth 1 -delete; fi
}
summary() {
echo
echo "===== SUMMARY ====="
echo "Total $((passed + failed + omitted))"
echo "Passed $passed"
echo "Failed $failed"
if [ $omitted -gt 0 ]; then echo "Omitted $omitted"; fi
}
# === MAIN ===
# Check for tests/ folder
if [ ! -d "$tests_dir" ]; then
echo -e "$ferr tests/ folder is nonexistent"
exit
fi
# Check if user is trying to display help
if [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
helpmenu
exit
fi
# Read and parse C program path
source_path="`pwd`/$1"
source_name=${source_path##*/}
if [ "${source_path#*.}" != "c" ]; then
echo -e "$ferr Input file was not provided or is not a c source code => $source_path"
echo "$usage"
exit
elif [ ! -f $source_path ]; then
echo -e "$ferr Input file '$source_path' does not exist"
exit
fi
shift
# Read and parse other flags
while [ ! $# -eq 0 ]
do
case "$1" in
--help | -h)
helpmenu
exit
;;
--filter | -f)
shift
test_filter="$1"
;;
--differences | -d)
differences=1
;;
--cleanup | -c)
cleanup=1
;;
--timeout | -t)
shift
time_limit="$1"
echo -e "$finfo Setting time limit to $time_limit seconds"
;;
esac
shift
done
# Check for rsync command
command -v rsync >> /dev/null
if [ $? -gt 0 ]; then use_rsync=0; fi
# Compile and check success
compile
sleep 0.5
if [ ! -f "$exec" ]; then
echo -e "$ferr Compilation error"
exit
else
echo -e "$fok Compilation success"
fi
# Run and clean
runtests
cleanup
summary