Template repository for Gradescope autograders used in Clemson CPSC-1011 during the F22 and S23 semesters.
Also includes test files to simulate runtime errors. These can be used to test included runtime error exceptions and methods.
Each autograder has a standard set of files and directories that are used as part of one large script process.
results/
: Folder generated by Gradescope that will contain a generatedresults.json
(holds results of autograder tests after each run).submission/
: Folder generated by Gradescope that will contain any student-uploaded program files. In this repository,submission/
is used to hold sample program files for each full autograder.source/
: Folder that contains source code/scripts for the Gradescope autograder.source/requirements.txt
: Text file that contains the names of anypip3
packages that are required to be installed for autograders to function as expected.source/run_autograder
: Bash script that copies student-uploaded.c
andmakefile
files fromsubmission/
, then runssource/run_tests.py
to start unit tests.source/run_tests.py
: Python script that starts the unit testing process.source/setup.sh
: Bash script that installs Python and anypip3
packages listed insource/requirements.txt
.- (Optional)
makefile
: Makefile that compiles/runs student submissions, if students are not supplying their own Makefile. - (Optional)
source/input/
: Folder which may contain any input files that can be passed asstdin
to a given test. - (Optional)
source/reference/
: Folder which may contain any sample output files that can be compared against in a given test. source/tests/
: Folder which contains Python scripts used in unit testing.source/tests/utils.py
: Python script which contains helper functions/methods that improve the unit testing process.source/tests/timeout.py
: Modified Python script (originally from timeout_decorator.py) that handles timeouts for individual test cases.source/tests/test_subprocess.py
: Main unit testing Python script, where test cases are written.
Each version of source/tests/test_subprocess.py
in this repository contains tests that should be included in all autograder testing.
test_checkFiles
: A test that checks that students have submitted all required files for an assignment, based on an array of file names (found immediately before this test insource/tests/test_subprocess.py
).test_Compile
: A test that compiles student programs by runningmake
or any compilation command. This test can be modified as needed.- If a student-supplied Makefile will be used to compile students' programs, replace the line
stdout, stderr = test.communicate()
in the compile test with the following to catch issues with malformed Makefiles that would cause the autograder to timeout (note, this method is not foolproof):
- If a student-supplied Makefile will be used to compile students' programs, replace the line
try:
stdout, stderr = test.communicate(timeout=10)
except (subprocess.TimeoutExpired):
os.popen(removeLastExecutableCommand)
kill_fail(test, self, compileTimeoutErrorMessage)
The other methods that are used as part of these autograders are likely irrelevant to beginners, as they work behind the scenes and do not require any tinkering to work properly for most purposes not explored in this repository.
However, here's a brief overview of some standout functions:
@timeout.timeout(seconds, exception_message, use_signals=False)
: This decorator allows for individual test timeouts (which allows the script to continue if a certain input causes an infinite loop, as opposed to causing the entire autograder to hang).exception_message
should be populated with a call towrap(string, max_length)
.use_signals=False
must be specified in order to avoid the autograder container running out of memory.wrap(string, max_length)
: This function wraps long error messages to a specified length to allow them to be shown cleanly in the Gradescope interface. The recommended value formax_length
is65
characters.checkRuntimeErrors(proc, utest, stdout, stderr)
: This function determines if thereturncode
of asubprocess.Popen
call matches any of the most common C program runtime errors. If a match is found, the constructor for a custom exception is called which, in turn, callskill_fail(proc, utest, msg)
(except for Makefile return codes, which are handled separately).kill_fail(proc, utest, msg)
: This function kills the child process spawned bysubprocess.Popen
and fails the test with a message supplied by the caller.removeEmptyLines(text)
: This function works with a few helper functions to strip string outputs of empty lines and instances of more than one space.customAssertMultiLineEqual(self, first, second, msg)
: Custom-edited version ofunittest
'sassertMultiLineEqual()
function that uses a few helper functions to re-format diff checks for output comparisons.checkSourceFiles(utest, files)
: Function that leveragescheckFiles()
(used intest_checkFiles
) to ensure all source code (.c
) files are present before compilation. Fails compilation test if files are missing. Used to stop the compilation test prematurely.- This method expects a list of strings to iterate through. If only one source file needs to be checked, it should still be passed as a single-item list.
checkExecutables(utest, executables)
: Function that checks to see if all expected executables (usually just one) are present (indicating compilation has succeeded). Fails test if executables are missing. Used to stop output tests prematurely (so as not to give away answers through diff checks).- This method expects a list of strings to iterate through. If only one executable needs to be checked, it should still be passed as a single-item list.
- See Notes for information about checking variably-named executables produced by Makefiles.
checkForUninitializedChars(str)
: Function that checks output (passed in asstr
) for Unicode NULL character\u0000
, which is printed by uninitialized characters in student program output and not caught byUnicodeDecodeError
.str
should be passed in likestdout.strip().decode('utf-8')
for maximum efficiency.
To test any of these autograders, zip the contents of source/
(recursively) and upload the resulting zip file to a Gradescope Programming Assignment then upload the relevant files from within submission/
to test.
Alternatively, copy the file structure of a given sample autograder (including results/
, source/
, and submission/
) recursively to the root of a server running Linux (Ubuntu 22.04 recommended). Then, run the following:
cd source
chmod +x run_autograder
./run_autograder
- The
checkExecutables(utest, executables)
method can be used to check executables produced by Makefiles when the name of the executable is not known by importing theos
package and passingos.popen(findLastExecutableCommand).read().split()
, which returns the last executable modified (other thanrun_autograder
), as the argument forexecutables
. This method may not function as intended if one Makefile target creates more than one executable. - The script at
source/run_autograder
has been configured to automatically delete any files insubmission/
not ending with the.c
extension or not calledmakefile
orMakefile
. To add an exception, use the exclusion structure:! -name '[FILE_NAME_OR_EXT]'
where[FILE_NAME_OR_EXT]
matches a complete file name or a wildcard like*.txt
. - The script at
source/run_autograder
has been configured to automatically copy any files remaining insubmission/
not previously automatically removed regardless of the directory structure. This means that students uploading a zipped folder (ex:folder.zip
, which unzips tofolder/
with source files inside) will not have their directory structure preserved. If you need to preserve zipped folder structure, replace the linefind /autograder/submission -type f -exec cp {} /autograder/source \;
withcp -r /autograder/submission/* /autograder/source/
.