This repository has been archived by the owner on Oct 28, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgrade-cassini.sh
executable file
·217 lines (179 loc) · 5.4 KB
/
grade-cassini.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
#!/bin/bash
#enable -f sleep sleep
# trap 'trap "exit $?" SIGTERM && kill -- -$$' EXIT
# trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM
CASSINI=./cassini
PIPESDIR=./run/pipes
PIPESDIR_MAIN="$PIPESDIR"
PIPESDIR_ALT=./run/pipes-alt
PATTERN=cassini-grading-
TMP1=$(mktemp)
TMP2=$(mktemp)
REQUEST_PIPE=saturnd-request-pipe
REPLY_PIPE=saturnd-reply-pipe
TIMEOUT=3
usage() { echo "Usage: $0 <tests-directory>" 1>&2; exit 1; }
echo
echo '============================= grade-cassini.sh =============================='
echo
TESTSDIR="$1"
if [ -z "$TESTSDIR" ]; then
usage
fi
if ! command -v timeout >/dev/null 2>&1
then
echo "The command timeout (from package coreutils) is missing"
exit 1
fi
if ! find "$TESTSDIR" -maxdepth 1 -name "${PATTERN}*" | grep . >/dev/null 2>&1
then
echo "The tests have not been generated"
exit 1
fi
if [ ! -x "$CASSINI" ]
then
echo "The compiled executable $CASSINI is not present"
exit 1
fi
if [ ! -d "$PIPESDIR" ]; then mkdir -p "$PIPESDIR"; fi
if [ ! -p "$PIPESDIR/$REQUEST_PIPE" ]; then mkfifo "$PIPESDIR/$REQUEST_PIPE"; chmod 600 "$PIPESDIR/$REQUEST_PIPE"; fi
if [ ! -p "$PIPESDIR/$REPLY_PIPE" ]; then mkfifo "$PIPESDIR/$REPLY_PIPE"; chmod 600 "$PIPESDIR/$REPLY_PIPE"; fi
if [ ! -d "$PIPESDIR_ALT" ]; then mkdir -p "$PIPESDIR_ALT"; fi
if [ ! -p "$PIPESDIR_ALT/$REQUEST_PIPE" ]; then mkfifo "$PIPESDIR_ALT/$REQUEST_PIPE"; chmod 600 "$PIPESDIR_ALT/$REQUEST_PIPE"; fi
if [ ! -p "$PIPESDIR_ALT/$REPLY_PIPE" ]; then mkfifo "$PIPESDIR_ALT/$REPLY_PIPE"; chmod 600 "$PIPESDIR_ALT/$REPLY_PIPE"; fi
normalize_output() {
sed 's/://g;s/[[:blank:]]+/ /g;s/^ //g;s/ $//g;/^$/d' | sort -n -k1,1
# TODO : maybe find a way of normalizing each timing field ?
}
print_failed() {
printf "=============================== Test n°%d failed =============================\n" "$NB_TESTS"
}
run_test() {
CURDIR="$1"
CHECK_REQUEST_BEFORE_REPLY="$2"
ARGS=()
ARGS_ESC=()
while read ARG; do
ARGS+=("$ARG")
if [[ ! "$ARG" =~ ^[-0-9A-Za-z.,_/]+$ ]]; then
PATTERN="'"
REPLACEMENT="'\\''"
ARG_ESC="'${ARG//$PATTERN/$REPLACEMENT}'"
ARGS_ESC+=("$ARG_ESC")
else
ARGS_ESC+=("$ARG")
fi
done < "$CURDIR/arguments"
if [ "$CHECK_REQUEST_BEFORE_REPLY" = "--strict" ]; then
{
PIDS=()
trap 'trap - SIGTERM; kill ${PIDS[@]}; exit 1' SIGTERM
exec 4> "$TMP1"
exec 3< "$PIPESDIR/$REQUEST_PIPE"
timeout $TIMEOUT dd bs=1 count=2 <& 3 >& 4
timeout $TIMEOUT dd if="$CURDIR/reply" > "$PIPESDIR/$REPLY_PIPE" &
PIDS+=("$!")
timeout $TIMEOUT dd <& 3 >& 4
} 2>/dev/null &
PID1=$!
else
{
PIDS=()
trap 'trap - SIGTERM; kill ${PIDS[@]}; exit 1' SIGTERM
timeout $TIMEOUT dd < "$PIPESDIR/$REQUEST_PIPE" > "$TMP1" &
PIDS+=("$!")
timeout $TIMEOUT dd if="$CURDIR/reply" > "$PIPESDIR/$REPLY_PIPE"
wait
} 2>/dev/null &
PID1=$!
fi
timeout $TIMEOUT $CASSINI -p "$PIPESDIR" "${ARGS[@]}" > "$TMP2" 2>/dev/null
RES=$?
timeout $TIMEOUT wait "$PID1" 2>/dev/null
kill "$PID1" 2>/dev/null
CMD="$CASSINI -p '$PIPESDIR' ${ARGS_ESC[@]}"
# TODO: use printf instead of echo
if [ $RES -eq 124 ]; then
print_failed
echo -e "Command:\n"; echo "$CMD"
echo -e "\nTimed out (after $TIMEOUT seconds)"
if [ "$CHECK_REQUEST_BEFORE_REPLY" = "--strict" ]; then
printf "Note: the reason may be that $CASSINI tried to open the reply pipe before sending the request\n"
fi
return 1;
fi
if ! [ -s "$TMP1" ]; then
print_failed
echo -e "Command:\n"; echo "$CMD"
echo -e "\nSent no request on $PIPESDIR/$REQUEST_PIPE"
return 1
fi
if ! cmp "$TMP1" "$CURDIR/request" --silent; then
print_failed
echo -e "Command:\n"; echo "$CMD"
echo -e "\nSent an incorrect request:"
hexdump -C "$TMP1"
echo -e "\nThe following request was expected:"
hexdump -C "$CURDIR/request"
return 1
fi
EXPECTED_RES=$(cat "$CURDIR/exitcode")
if [ "$RES" -ne "$EXPECTED_RES" ]; then
print_failed
echo -e "Command:\n"; echo "$CMD"
echo -e "\nWith reply:"
hexdump -C "$CURDIR/reply"
echo -e "\nExited with code $RES instead of $EXPECTED_RES"
return 1
fi
if [ "$RES" -eq "0" ]; then
if ! cmp <( cat "$TMP2" | normalize_output ) <( cat "$CURDIR/stdout" | normalize_output ) --silent; then
print_failed
echo -e "Command:\n"; echo "$CMD"
echo -e "\nWith reply:"
hexdump -C "$CURDIR/reply"
echo -e "\nWrote an incorrect output on stdout:"
cat "$TMP2"
echo -e "\nThe following output was expected:"
cat "$CURDIR/stdout"
return 1
fi
fi
return 0
}
cd "$TESTSDIR"
TESTS_LIST=()
for f in $(find . -maxdepth 1 -name "${PATTERN}*" | sort -n -t- -k3,3)
do
TESTS_LIST+=("$TESTSDIR/$f")
done
cd - >/dev/null
NB_TESTS=0
NB_TESTS_PASSED=0
for f in "${TESTS_LIST[@]}"
do
(( NB_TESTS++ ))
if [ "$NB_TESTS" -eq 12 ]; then
STRICT="--strict"
else
STRICT=""
fi
if [ "$NB_TESTS" -eq 11 ]; then
PIPESDIR="$PIPESDIR_ALT"
else
PIPESDIR="$PIPESDIR_MAIN"
fi
if run_test "$f" $STRICT; then
(( NB_TESTS_PASSED++ ))
else
printf "\n"
fi
done
rm -f "$TMP1"
rm -f "$TMP2"
if [ "$NB_TESTS_PASSED" -lt "$NB_TESTS" ]; then
printf "==============================================================================\n\n"
fi
printf "Tests passed: %d out of %d\n" "$NB_TESTS_PASSED" "$NB_TESTS"
export LANG="C"
printf "Grade: %.2f / 4\n" $(( $NB_TESTS_PASSED * 400 / $NB_TESTS))e-2