From 0035d2ea0ea693ab328cba0d25997e2dad59f5ec Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 15 Feb 2013 00:10:37 -0500 Subject: [PATCH] quizzes/DiRAC-drivers-license: First pass at automating the exam See: http://software-carpentry.org/blog/2012/08/alpha-test-of-drivers-license-exam.html http://software-carpentry.org/blog/2013/02/dirac-dry-run-two.html I was unable to convert the code review question to the quizzer format, because it's hard to evaluate refactorings automatically. This quiz is probably not under the GPLv3. The licensing for the original quiz is unclear, but most Software Carpentry stuff is under the Creative Commons Attribution 3.0 Unported (CC BY 3.0). --- quizzes/DiRAC-drivers-license.json | 336 +++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 quizzes/DiRAC-drivers-license.json diff --git a/quizzes/DiRAC-drivers-license.json b/quizzes/DiRAC-drivers-license.json new file mode 100644 index 0000000..9f5ca61 --- /dev/null +++ b/quizzes/DiRAC-drivers-license.json @@ -0,0 +1,336 @@ +{ + "version": "0.1", + "introduction": "You have one hour to complete the following tasks involving Git, POSIX, and Python. If at any point you would like clarification, please do not hesitate to ask. If at any point you are unable to complete a task, you may also ask for help so that you can proceed to the next task, but doing so will be considered equivalent to not completing that task. You may search the web, man pages, etc..", + "questions": [ + { + "class": "ScriptQuestion", + "intepreter": "sh", + "id": "find", + "prompt": "Use a single shell command to create a list of all files with names ending in .dat in or below this directory in a file called all-dat-files.txt.", + "answer": "find . -name '*.dat' -print > all-dat-files.txt", + "setup": [ + "mkdir -p inputs/{a,b,c}", + "touch inputs/{,a/,b/,c/}{d,e,f}.dat" + ], + "teardown": [ + "ls all-dat-files.txt", + "sort all-dat-files.txt" + ], + "help": "http://pubs.opengroup.org/onlinepubs/009696699/utilities/find.html", + "tags": [ + "POSIX" + ] + }, + { + "class": "ScriptQuestion", + "intepreter": "sh", + "id": "make", + "prompt": [ + "The analyze.py program takes exactly two arguments: the name of its input file and the name of its output file, in that order. For example, if inputs/a.dat changes, running GNU make will execute the command:", + "", + " ./analyze.py inputs/a.dat outputs/a.out", + "", + "Edit the file Makefile in the current directory so that if any .dat file in the inputs directory changes, the program analyze.py is run to create a file named .out in the outputs directory." + ], + "multiline": true, + "timeout": null, + "answer": [ + "cat >> Makefile <<\\EOF", + "outputs/%.out : inputs/%.dat", + "\t./analyze.py \"$<\" \"$@\"", + "EOF" + ], + "setup": [ + "mkdir -p inputs/{a,b,c}", + "for x in inputs/{,a/,b/,c/}{d,e,f}.dat; do echo \"$x\" > \"$x\"; done", + "cat > analyze.py < Makefile <<\\EOF", + "OUTPUTS = $(sort $(patsubst inputs/%.dat,outputs/%.out,$(wildcard inputs/*.dat) $(wildcard inputs/*/*.dat)))", + "", + "all: $(OUTPUTS)", + "", + "# Add your rule here, using a command like:", + "#", + "# ./analyze.py inputs/a.dat outputs/a.out", + "#", + "# to generate the output files. You should only need one rule.", + "EOF" + ], + "teardown": [ + "make > make.log", + "OUTPUTS=$(find outputs | sort)", + "if [ -n \"$OUTPUTS\" ]; then head $OUTPUTS; fi" + ], + "help": [ + "http://pubs.opengroup.org/onlinepubs/009696699/utilities/make.html", + "http://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html" + ], + "tags": [ + "make" + ] + }, + { + "class": "ScriptQuestion", + "intepreter": "sh", + "id": "git commit", + "prompt": [ + "Commit your changes to Makefile to the version control repository.", + "The commit message should be `Building .out files for .dat files`." + ], + "multiline": true, + "timeout": null, + "answer": [ + "git commit -am 'Building .out files for .dat files'" + ], + "environment": { + "GIT_AUTHOR_NAME": "A U Thor", + "GIT_AUTHOR_EMAIL": "author@example.com", + "GIT_COMMITTER_NAME": "C O Mitter", + "GIT_COMMITTER_EMAIL": "committer@example.com", + "GIT_AUTHOR_DATE": "1970-01-01T00:01:00Z", + "GIT_COMMITTER_DATE": "1970-01-01T00:01:00Z" + }, + "setup": [ + "export GIT_AUTHOR_NAME='A U Thor'", + "export GIT_AUTHOR_EMAIL=author@example.com", + "export GIT_COMMITTER_NAME='C O Mitter'", + "export GIT_COMMITTER_EMAIL=committer@example.com", + "export GIT_AUTHOR_DATE=1970-01-01T00:00:00Z", + "export GIT_COMMITTER_DATE=\"$GIT_AUTHOR_DATE\"", + "git init", + "echo '# Original stuff' > Makefile", + "git add Makefile", + "git commit -m 'Add a Makefile'", + "echo '# New stuff' >> Makefile" + ], + "teardown": [ + "git log -p" + ], + "help": "http://www.kernel.org/pub/software/scm/git/docs/git-commit.html", + "tags": [ + "version-control" + ] + }, + { + "class": "ScriptQuestion", + "interpreter": "sh", + "id": "git merge", + "prompt": [ + "Merge your Makefile changes with some upstream work.", + "Use Git's auto-generated commit message, which should be:", + "", + " Merge branch 'origin/master'", + "", + " Conflicts:", + " \tMakefile", + "", + "You may want to drop into a POSIX shell (e.g. via `!bash`) to do this." + ], + "multiline": true, + "timeout": null, + "allow_interactive": true, + "answer": [ + "git merge origin/master", + "sed -i -e '/<<<.*\\|>>>.*/d' -e 's/===.*//' Makefile", + "git add Makefile", + "git commit --file .git/MERGE_MSG" + ], + "environment": { + "GIT_AUTHOR_NAME": "A U Thor", + "GIT_AUTHOR_EMAIL": "author@example.com", + "GIT_COMMITTER_NAME": "C O Mitter", + "GIT_COMMITTER_EMAIL": "committer@example.com", + "GIT_AUTHOR_DATE": "1970-01-01T00:03:00Z", + "GIT_COMMITTER_DATE": "1970-01-01T00:03:00Z" + }, + "setup": [ + "export GIT_AUTHOR_NAME='A U Thor'", + "export GIT_AUTHOR_EMAIL=author@example.com", + "export GIT_COMMITTER_NAME='C O Mitter'", + "export GIT_COMMITTER_EMAIL=committer@example.com", + "export GIT_AUTHOR_DATE=1970-01-01T00:00:00Z", + "export GIT_COMMITTER_DATE=\"$GIT_AUTHOR_DATE\"", + "git init", + "cat > Makefile <<\\EOF", + "OUTPUTS = $(sort $(patsubst inputs/%.dat,outputs/%.out,$(wildcard inputs/*.dat) $(wildcard inputs/*/*.dat)))", + "", + "all: $(OUTPUTS)", + "", + "# Add your rule here, using a command like:", + "#", + "# ./analyze.py inputs/a.dat outputs/a.out", + "#", + "# to generate the output files. You should only need one rule.", + "EOF", + "git add Makefile", + "git commit -m 'Initial Makefile with OUTPUTS'", + "export GIT_AUTHOR_DATE=1970-01-01T00:01:00Z", + "export GIT_COMMITTER_DATE=\"$GIT_AUTHOR_DATE\"", + "cat >> Makefile <<\\EOF", + "outputs/%.out : inputs/%.dat", + "\t./analyze.py \"$<\" \"$@\"", + "EOF", + "git commit -am 'Building .out files for .dat files'", + "export GIT_AUTHOR_DATE=1970-01-01T00:02:00Z", + "export GIT_COMMITTER_DATE=\"$GIT_AUTHOR_DATE\"", + "git checkout -b origin/master HEAD^", + "cat >> Makefile <<\\EOF", + "clean:", + "\trm -rf outputs/", + "EOF", + "git commit -am \"Makefile: Add a 'clean' target\"", + "git checkout master" + ], + "teardown": [ + "cat Makefile", + "git log --all --oneline --graph --decorate" + ], + "help": "http://www.kernel.org/pub/software/scm/git/docs/git-merge.html", + "tags": [ + "branch", + "merge" + ] + }, + { + "class": "ScriptQuestion", + "intepreter": "sh", + "id": "test running total", + "prompt": [ + "The analyze.py program contains a function called running_total, which is supposed to calculate the total of each strictly increasing sequence of numbers in a list:", + "", + " running_total([1, 2, 1, 8, 9, 2]) == [3, 18, 2]", + " running_total([1, 3, 4, 2, 5, 4, 6, 9]) == [8, 7, 19]", + "", + "In the file test_analyze.py, write the four (4) unit tests that you think are most important to run to test this function. Do not test for cases of invalid input (i.e., inputs that are strings, lists of lists, or anything else that isn't a flat list of numbers).", + "", + "You may want to drop into a POSIX shell (e.g. via `!bash`) to do this.", + "You should be able to run your tests using `nosetests`." + ], + "multiline": true, + "timeout": null, + "allow_interactive": true, + "answer": [ + "cat >> test_analyze.py <> analyze.py < last:", + " totals[-1] += i", + " else:", + " totals.append(i)", + " last = i", + " return totals", + "EOF" + ], + "teardown": [ + "cat > run-nose-without-time.py <&1 | grep -A5 '8<-----'", + "cat >> analyze.py <&1 | grep -A5 '8<-----'" + ], + "help": [ + "https://nose.readthedocs.org/en/latest/writing_tests.html#writing-tests", + "https://nose.readthedocs.org/en/latest/writing_tests.html#test-functions" + ], + "tags": [ + "python", + "testing" + ] + }, + { + "class": "ScriptQuestion", + "intepreter": "sh", + "id": "shell scripting", + "prompt": [ + "Write a shell script called do-many.sh that runs power2.py for many different numbers. For example:", + "", + " ./do-many.sh 27 9 35", + "", + "must produce:", + "", + " 16 8 2 1", + " 8 1", + " 32 2 1", + "", + "as its output. You do not need to do error-checking on the command-line parameters, i.e., you may assume that they are all non-negative integers." + ], + "multiline": true, + "timeout": null, + "answer": [ + "cat >> do-many.sh <<\\EOF", + "#!/bin/sh", + "for number in \"$@\"; do", + " ./power2.py \"$number\"", + "done", + "EOF", + "chmod 755 do-many.sh" + ], + "setup": [ + "cat >> power2.py <