diff --git a/FINAL/data/image.20 b/FINAL/data/image.20 new file mode 100644 index 0000000000000000000000000000000000000000..378acd775cce311f7f2f28c9fd85568176d0cf79 Binary files /dev/null and b/FINAL/data/image.20 differ diff --git a/FINAL/data/image.200 b/FINAL/data/image.200 new file mode 100644 index 0000000000000000000000000000000000000000..a75ec809db2a2fe0569d43c53c21ece8fc226c0a Binary files /dev/null and b/FINAL/data/image.200 differ diff --git a/FINAL/data/image.5 b/FINAL/data/image.5 new file mode 100644 index 0000000000000000000000000000000000000000..0f35734f0bef1fae285547ad74bd8a34b175efda Binary files /dev/null and b/FINAL/data/image.5 differ diff --git a/FINAL/run.sh b/FINAL/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..572095516626419d068f7221313773783775e361 --- /dev/null +++ b/FINAL/run.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# These functions exist to stop students from using shells within their own +# shell to execute a program. We remove execution ability and use sudo to move +# to another user to then run the program +move_away() +{ + chmod 500 /bin/sh + chmod 500 /bin/bash +} + +move_back() +{ + chmod 555 /bin/sh + chmod 555 /bin/bash +} + +rm -rf /kernel/*.o + +source /helpers.sh + +LOG=$LOGS/test_public.log +ASSIGNMENTDIR=/assignments/FINAL/ + +if [ ! -d /kernel ]; +then + unpack_kernel +fi + +export LC_ALL=C.UTF-8 + +echo "Building assignment..." +cd /kernel +chmod a+rw . + +COMPILE=$LOGS/compile.log +touch $COMPILE +truncate -s 0 $COMPILE +rm sfssh > /dev/null 2> /dev/null || true +rm -rf ./tests +rm -rf ./data +rm -rf ./bin +make +#gcc main.c -o myshell -pthread >> $COMPILE 2>> $COMPILE + +touch $LOG +truncate -s 0 $LOG + +if test -f "sfssh"; +then + echo "Build succeeded." +else + echo "Build failed." + exit +fi + +#copy test scripts +cp -R $ASSIGNMENTDIR/tests ./ + +#copy user binary +mkdir /kernel/tests/bin +cp /kernel/sfssh /kernel/tests/bin/sfssh + +cd /kernel/tests + +# Go through basic tests +# In each of these we are essentially only testing commands with output to stdout + +# This is a way to stop students from trying to use the sh command, we search for this command to be used +# afterwords +echo "Testing..." +for f in $ASSIGNMENTDIR/tests/* +do + if echo "$f" | grep -q ".disabled" || echo "$f" | grep -q ".output" + then + continue + fi + + #refresh test data + cp -R $ASSIGNMENTDIR/data /kernel/tests/ + + bname=$(basename $f) + fn="${bname%.*}" + echo " -> ${fn}..." + echo ">SPLIT<" >> $LOG + echo ">TEST=$fn<" >> $LOG + echo ">Program Output<" >> $LOG + sudo -u root timeout 5s /bin/bash $f >> $LOG 2>> $LOG + echo ">Expected Output<" >> $LOG + cat "${ASSIGNMENTDIR}/tests/${fn}.output" >> $LOG +done + +exit 0 + diff --git a/FINAL/tests/test_cat.output b/FINAL/tests/test_cat.output new file mode 100755 index 0000000000000000000000000000000000000000..ecdeeba37d0467e874877e083ca2f0c34c217eb2 --- /dev/null +++ b/FINAL/tests/test_cat.output @@ -0,0 +1,2 @@ +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_cat.sh b/FINAL/tests/test_cat.sh new file mode 100755 index 0000000000000000000000000000000000000000..e0e2624fd41781a4199304dc8ae40f7d16359735 --- /dev/null +++ b/FINAL/tests/test_cat.sh @@ -0,0 +1,518 @@ +#!/bin/bash + +# Test data/image.5 + +image-5-output() { + cat < /dev/null | sort) <(image-5-output) > test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat test.log +fi +rm -f test.log + +# Test data/image.20 + +image-20-input() { + cat < /dev/null | sort) > image20.out + +echo -n "Testing cat on data/image.20 ... " +if diff -u <(image-20-input | ./bin/sfssh data/image.20 20 2> /dev/null | sort) <(image-20-output) > test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat test.log +fi +rm -f test.log diff --git a/FINAL/tests/test_copyin.output b/FINAL/tests/test_copyin.output new file mode 100755 index 0000000000000000000000000000000000000000..9ad1004b0949bb6da6337f5b8927a61bce98bff8 --- /dev/null +++ b/FINAL/tests/test_copyin.output @@ -0,0 +1,3 @@ +[RESULT]Success +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_copyin.sh b/FINAL/tests/test_copyin.sh new file mode 100755 index 0000000000000000000000000000000000000000..7dbff702ceea243044d88129841bbedea6faa78c --- /dev/null +++ b/FINAL/tests/test_copyin.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +SCRATCH=$(mktemp -d) +trap "rm -fr $SCRATCH" INT QUIT TERM EXIT + +# Test: data/image.5 + +cp data/image.5 $SCRATCH/image.5 +cat < /dev/null 2>&1 +debug +mount +copyout 1 $SCRATCH/1.txt +create +debug +copyin $SCRATCH/1.txt 0 +debug +copyout 0 $SCRATCH/1.copy +EOF +echo -n "Testing copyin in $SCRATCH/image.5 ... " +if [ $(md5sum $SCRATCH/1.copy | awk '{print $1}') = '1edec6bc701059c45053cf79e7e16588' ]; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" +fi + +# Test: data/image.20 + +cp data/image.20 $SCRATCH/image.20 +cat < /dev/null 2>&1 +debug +mount +copyout 2 $SCRATCH/2.txt +copyout 3 $SCRATCH/3.txt +create +copyin $SCRATCH/3.txt 0 +create +copyin $SCRATCH/2.txt 1 +copyout 0 $SCRATCH/3.copy +copyout 1 $SCRATCH/2.copy +debug +EOF +echo -n "Testing copyin in $SCRATCH/image.20 ... " +if [ $(md5sum $SCRATCH/2.copy | awk '{print $1}') = '1adf08d52e0f1a162a3a887a19fcf1f8' ] && + [ $(md5sum $SCRATCH/3.copy | awk '{print $1}') = 'd083a4be9fde347b98a8dbdfcc196819' ]; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" +fi + +# Test: data/image.200 + +cp data/image.200 $SCRATCH/image.200 +cat < /dev/null 2>&1 +debug +mount +copyout 1 $SCRATCH/1.txt +copyout 2 $SCRATCH/2.txt +copyout 9 $SCRATCH/9.txt +create +copyin $SCRATCH/1.txt 0 +create +copyin $SCRATCH/2.txt 3 +create +copyin $SCRATCH/9.txt 4 +debug +copyout 0 $SCRATCH/1.copy +copyout 3 $SCRATCH/2.copy +copyout 4 $SCRATCH/9.copy +EOF +echo -n "Testing copyin in $SCRATCH/image.200 ... " +if [ $(md5sum $SCRATCH/1.copy | awk '{print $1}') = '0af623d6d8cb0a514816e17c7386a298' ] && + [ $(md5sum $SCRATCH/2.copy | awk '{print $1}') = '307fe5cee7ac87c3b06ea5bda80301ee' ] && + [ $(md5sum $SCRATCH/9.copy | awk '{print $1}') = 'fa4280d88da260281e509296fd2f3ea2' ]; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" +fi diff --git a/FINAL/tests/test_copyout.output b/FINAL/tests/test_copyout.output new file mode 100755 index 0000000000000000000000000000000000000000..9ad1004b0949bb6da6337f5b8927a61bce98bff8 --- /dev/null +++ b/FINAL/tests/test_copyout.output @@ -0,0 +1,3 @@ +[RESULT]Success +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_copyout.sh b/FINAL/tests/test_copyout.sh new file mode 100755 index 0000000000000000000000000000000000000000..133a7000102c6042264e82e62f5b265f272ed441 --- /dev/null +++ b/FINAL/tests/test_copyout.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +SCRATCH=$(mktemp -d) +trap "rm -fr $SCRATCH" INT QUIT TERM EXIT + +# Test: data/image.5 + +echo -n "Testing copyout in data/image.5 ... " +cat < /dev/null 2>&1 +mount +copyout 1 $SCRATCH/1.txt +EOF +if [ $(md5sum $SCRATCH/1.txt | awk '{print $1}') = '1edec6bc701059c45053cf79e7e16588' ]; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" +fi + +# Test: data/image.20 + +cat < /dev/null 2>&1 +mount +copyout 2 $SCRATCH/2.txt +copyout 3 $SCRATCH/3.txt +EOF + +echo -n "Testing copyout in data/image.20 ... " +if [ $(md5sum $SCRATCH/2.txt | awk '{print $1}') = 'bfd6a31563edfd2a943edc29c37366b1' ] && + [ $(md5sum $SCRATCH/3.txt | awk '{print $1}') = 'd083a4be9fde347b98a8dbdfcc196819' ]; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" +fi + +# Test: data/image.200 + +cat < /dev/null 2>&1 +mount +copyout 1 $SCRATCH/1.txt +copyout 2 $SCRATCH/2.txt +copyout 9 $SCRATCH/9.txt +EOF + +echo -n "Testing copyout in data/image.200 ... " +if [ $(md5sum $SCRATCH/1.txt | awk '{print $1}') = '0af623d6d8cb0a514816e17c7386a298' ] && + [ $(md5sum $SCRATCH/2.txt | awk '{print $1}') = '307fe5cee7ac87c3b06ea5bda80301ee' ] && + [ $(md5sum $SCRATCH/9.txt | awk '{print $1}') = 'cc4e48a5fe0ba15b13a98b3fd34b340e' ]; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" +fi diff --git a/FINAL/tests/test_create.output b/FINAL/tests/test_create.output new file mode 100755 index 0000000000000000000000000000000000000000..84edb8fa58fabb032c54de1a3ddecff7f29b3376 --- /dev/null +++ b/FINAL/tests/test_create.output @@ -0,0 +1 @@ +[RESULT]Success diff --git a/FINAL/tests/test_create.sh b/FINAL/tests/test_create.sh new file mode 100755 index 0000000000000000000000000000000000000000..7d5a6d2ffe028d2c56a865718ff2b448e3baf135 --- /dev/null +++ b/FINAL/tests/test_create.sh @@ -0,0 +1,552 @@ +#!/bin/bash + +test-input() { + echo debug + echo mount + for i in $(seq 128); do + echo create + done + echo debug +} + +test-output() { + cat < /dev/null | head -n -2) <(test-output); then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" +fi diff --git a/FINAL/tests/test_debug.output b/FINAL/tests/test_debug.output new file mode 100755 index 0000000000000000000000000000000000000000..9ad1004b0949bb6da6337f5b8927a61bce98bff8 --- /dev/null +++ b/FINAL/tests/test_debug.output @@ -0,0 +1,3 @@ +[RESULT]Success +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_debug.sh b/FINAL/tests/test_debug.sh new file mode 100755 index 0000000000000000000000000000000000000000..6fadd58d27048fecbe413559d84e8756591d1b1a --- /dev/null +++ b/FINAL/tests/test_debug.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +image-5-output() { + cat < /dev/null) <($OUTPUT) > test.log; then + echo "[RESULT]Success" + else + echo "[RESULT]Failure" + cat test.log + fi + rm -f test.log +} + +test-debug data/image.5 5 image-5-output +test-debug data/image.20 20 image-20-output +test-debug data/image.200 200 image-200-output diff --git a/FINAL/tests/test_format.output b/FINAL/tests/test_format.output new file mode 100755 index 0000000000000000000000000000000000000000..9ad1004b0949bb6da6337f5b8927a61bce98bff8 --- /dev/null +++ b/FINAL/tests/test_format.output @@ -0,0 +1,3 @@ +[RESULT]Success +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_format.sh b/FINAL/tests/test_format.sh new file mode 100755 index 0000000000000000000000000000000000000000..d253df7fd42b9edee870581b316b65f156d29eb4 --- /dev/null +++ b/FINAL/tests/test_format.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +image-5-output() { + cat < /dev/null) <($OUTPUT) > test.log; then + echo "[RESULT]Success" + else + echo "[RESULT]Failure" + cat test.log + fi + rm -f $DISK.formatted test.log +} + +test-format data/image.5 5 image-5-output +test-format data/image.20 20 image-20-output +test-format data/image.200 200 image-200-output diff --git a/FINAL/tests/test_mount.output b/FINAL/tests/test_mount.output new file mode 100755 index 0000000000000000000000000000000000000000..49526eeb5519cd97a5e15c77aab5b5e6dfaf1126 --- /dev/null +++ b/FINAL/tests/test_mount.output @@ -0,0 +1,8 @@ +[RESULT]Success +[RESULT]Success +[RESULT]Success +[RESULT]Success +[RESULT]Success +[RESULT]Success +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_mount.sh b/FINAL/tests/test_mount.sh new file mode 100755 index 0000000000000000000000000000000000000000..4376aa8db31176fdb3696f6dc5aab15b2b349d48 --- /dev/null +++ b/FINAL/tests/test_mount.sh @@ -0,0 +1,143 @@ +#!/bin/bash + +#!/bin/bash + +mount-input() { + cat < /dev/null) <($TEST-output) > test.log; then + echo "[RESULT]Success" + else + echo "[RESULT]Failure" + cat test.log + fi + rm -f test.log +} + +test-mount mount +test-mount mount-mount +test-mount mount-format + +SCRATCH=$(mktemp -d) +trap "rm -fr $SCRATCH" INT QUIT TERM EXIT + +bad-mount-input() { + cat < $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n "Testing bad-mount on $SCRATCH/image.5 ... " +if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi + +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf1 0xf0) > $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n "Testing bad-mount on $SCRATCH/image.5 ... " +if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi + +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf0 0xf0) > $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x00 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n "Testing bad-mount on $SCRATCH/image.5 ... " +if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi + +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf0 0xf0) > $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x02 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x80 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n "Testing bad-mount on $SCRATCH/image.5 ... " +if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi + +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x10 0x34 0xf0 0xf0) > $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x05 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x01 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n -e $(printf '\\x%x\\x%x\\x%x\\x%x' 0x70 0x00 0x00 0x00) >> $SCRATCH/image.5 +echo -n "Testing bad-mount on $SCRATCH/image.5 ... " +if diff -u <(bad-mount-input| ./bin/sfssh $SCRATCH/image.5 5 2> /dev/null) <(bad-mount-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi diff --git a/FINAL/tests/test_remove.output b/FINAL/tests/test_remove.output new file mode 100755 index 0000000000000000000000000000000000000000..9ad1004b0949bb6da6337f5b8927a61bce98bff8 --- /dev/null +++ b/FINAL/tests/test_remove.output @@ -0,0 +1,3 @@ +[RESULT]Success +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_remove.sh b/FINAL/tests/test_remove.sh new file mode 100755 index 0000000000000000000000000000000000000000..152fef7dcf34c5fc5db33d36f607df51ddd352a8 --- /dev/null +++ b/FINAL/tests/test_remove.sh @@ -0,0 +1,239 @@ +#!/bin/bash + +SCRATCH=$(mktemp -d) + +# Test 0 + +test-0-input() { + echo debug + echo mount + echo create + echo create + echo create + echo remove 0 + echo debug + echo create + echo remove 0 + echo remove 0 + echo remove 1 + echo remove 3 + echo debug +} + +test-0-output() { + cat < /dev/null | head -n -2) <(test-0-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi + +# Test 1 + +test-1-input() { + cat < /dev/null | head -n -2) <(test-1-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi + +# Test 2 + +test-2-input() { + cat < /dev/null | head -n -2) <(test-2-output) > $SCRATCH/test.log; then + echo "[RESULT]Success" +else + echo "[RESULT]Failure" + cat $SCRATCH/test.log +fi diff --git a/FINAL/tests/test_stat.output b/FINAL/tests/test_stat.output new file mode 100755 index 0000000000000000000000000000000000000000..9ad1004b0949bb6da6337f5b8927a61bce98bff8 --- /dev/null +++ b/FINAL/tests/test_stat.output @@ -0,0 +1,3 @@ +[RESULT]Success +[RESULT]Success +[RESULT]Success diff --git a/FINAL/tests/test_stat.sh b/FINAL/tests/test_stat.sh new file mode 100755 index 0000000000000000000000000000000000000000..eb3deac7a4e8688d84b0a7aaa8c524220be683b4 --- /dev/null +++ b/FINAL/tests/test_stat.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +image-5-input() { + cat < /dev/null) <(image-$BLOCKS-output) > test.log; then + echo "[RESULT]Success" + else + echo "[RESULT]Failure" + cat test.log + fi + rm -f test.log +} + +test-stat 5 +test-stat 20 +test-stat 200 diff --git a/FINAL/tests/test_valgrind.output b/FINAL/tests/test_valgrind.output new file mode 100755 index 0000000000000000000000000000000000000000..84edb8fa58fabb032c54de1a3ddecff7f29b3376 --- /dev/null +++ b/FINAL/tests/test_valgrind.output @@ -0,0 +1 @@ +[RESULT]Success diff --git a/FINAL/tests/test_valgrind.sh.disabled b/FINAL/tests/test_valgrind.sh.disabled new file mode 100755 index 0000000000000000000000000000000000000000..e8a1cb553230a7a39bffd66aff2c255450addcb7 --- /dev/null +++ b/FINAL/tests/test_valgrind.sh.disabled @@ -0,0 +1,43 @@ +#!/bin/bash + +SCRATCH=$(mktemp -d) +trap "rm -fr $SCRATCH" INT QUIT TERM EXIT + +# Test: data/image.200 + +test-input() { + cat <Expected Output<", +] + +def mark(tests, helpers, t_type, grade_per, debug=False): + try: + grade = 0 + cmts = set() + tests = [t for t in tests if t_type in t.name] + if len(tests) == 0: + cmts.add(f"Compilation error") + return (f"{t_type} Tests", grade, ",".join(cmts)) + + for t in tests: + # get the lines from the output + r = t.results().strip().split("\n") + + for i, strout in enumerate(r): + for title in title_str: + if title in strout: + r[i] = title + break + + # compose program output + # remove all > and spaces + idx = r.index(">Expected Output<") + prog_output = ''.join(r[1:idx]) + + exp_output = ''.join(r[idx+1:]) + exp_output = exp_output.replace(" ", "") + exp_output = exp_output.replace("\n", "") + + output = [i for i in range(len(prog_output)) if prog_output.startswith('[RESULT]', i)] + prog_output_fmt = "" + for idx in output: + if prog_output[idx+8] == 'S': + prog_output_fmt += "[RESULT]Success" + else: + prog_output_fmt += "[RESULT]Failure" + + if debug: + print("=================") + print(f"[Program output] {prog_output_fmt}") + print(f"[Expected output] {exp_output}") + + if prog_output_fmt != exp_output: + cmts.add(f"Wrong output {t.name}") + continue + + grade += grade_per + except: + if DEBUG: + print(traceback.format_exc()) + cmts.add("Cannot parse assignment log - likely an error in your assignment. Ensure that your shell is correctly formated.") + + return (f"{t_type} Tests", grade, ",".join(cmts)) + +def test(tests, helpers): + return mark(tests, helpers, TYPE_TEST, TEST_GRADE_PER, DEBUG) + + +RUBRIC = { + test: TEST_GRADE_PER * TEST_NUM, +}