diff --git a/sensors_diff/.gitmastery-exercise.json b/sensors_diff/.gitmastery-exercise.json new file mode 100644 index 0000000..ad8d4be --- /dev/null +++ b/sensors_diff/.gitmastery-exercise.json @@ -0,0 +1,18 @@ +{ + "exercise_name": "sensors-diff", + "tags": [ + "git-diff" + ], + "requires_git": true, + "requires_github": true, + "base_files": { + "answers.txt": "answers.txt" + }, + "exercise_repo": { + "repo_type": "remote", + "repo_name": "sensors", + "repo_title": "gm-sensors", + "create_fork": false, + "init": null + } +} \ No newline at end of file diff --git a/sensors_diff/README.md b/sensors_diff/README.md new file mode 100644 index 0000000..9198ba4 --- /dev/null +++ b/sensors_diff/README.md @@ -0,0 +1,16 @@ +# sensors-diff + +A system is using Git to record data received daily from for sensors, each monitoring one of directions east, west, north, south. Each sensor provides 20 integer values, which are stored in a csv file (e.g., values from the sensor monitoring the east direction are recorded as `east.csv`). Data for each day is recorded as one commit. + +## Task + +Examine the revision history to answer the questions in `answers.txt`. + +## Hints + +
+How do I see what's staged vs unstaged? + +Use `git status` to see which files are staged and which are modified but unstaged. + +
diff --git a/sensors_diff/__init__.py b/sensors_diff/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sensors_diff/download.py b/sensors_diff/download.py new file mode 100644 index 0000000..a3896c0 --- /dev/null +++ b/sensors_diff/download.py @@ -0,0 +1,11 @@ +from exercise_utils.git import add + +__resources__ = { + "south.csv": "south.csv", + "north.csv": "north.csv", + "west.csv": "west.csv", +} + + +def setup(verbose: bool = False): + add(["north.csv"], verbose) diff --git a/sensors_diff/res/answers.txt b/sensors_diff/res/answers.txt new file mode 100644 index 0000000..6219e37 --- /dev/null +++ b/sensors_diff/res/answers.txt @@ -0,0 +1,11 @@ +Q: Which are the new values in staged files? +A: + +Q: Which are the new values in modified but unstaged files? +A: + +Q: Which files have changed from Jan 09th to Jan 15th? +A: + +Q: Which new values are new in north.csv on Jan 10th, compared to Jan 01st? +A: diff --git a/sensors_diff/res/north.csv b/sensors_diff/res/north.csv new file mode 100644 index 0000000..93a6a92 --- /dev/null +++ b/sensors_diff/res/north.csv @@ -0,0 +1,20 @@ +6841 +2307 +9754 +4169 +5823 +3086 +7590 +8420 +1679 +5034 +2918 +7645 +8301 +4576 +9208 +3461 +5789 +6940 +1235 +8890 \ No newline at end of file diff --git a/sensors_diff/res/south.csv b/sensors_diff/res/south.csv new file mode 100644 index 0000000..60eabd4 --- /dev/null +++ b/sensors_diff/res/south.csv @@ -0,0 +1,20 @@ +7412 +5068 +8921 +3754 +2809 +6197 +4531 +9674 +1185 +7326 +5401 +8937 +2640 +7083 +5914 +3208 +8745 +4069 +1592 +6831 \ No newline at end of file diff --git a/sensors_diff/res/west.csv b/sensors_diff/res/west.csv new file mode 100644 index 0000000..3da0d79 --- /dev/null +++ b/sensors_diff/res/west.csv @@ -0,0 +1,20 @@ +5193 +8042 +6721 +4389 +2075 +9510 +3642 +7281 +5904 +1837 +4416 +9032 +7765 +6208 +3589 +8471 +2940 +1683 +7352 +5129 diff --git a/sensors_diff/tests/__init__.py b/sensors_diff/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sensors_diff/tests/specs/base.yml b/sensors_diff/tests/specs/base.yml new file mode 100644 index 0000000..00c3a53 --- /dev/null +++ b/sensors_diff/tests/specs/base.yml @@ -0,0 +1,6 @@ +initialization: + steps: + - type: commit + empty: true + message: Empty commit + id: start diff --git a/sensors_diff/tests/test_verify.py b/sensors_diff/tests/test_verify.py new file mode 100644 index 0000000..c9fa37d --- /dev/null +++ b/sensors_diff/tests/test_verify.py @@ -0,0 +1,205 @@ +from git_autograder.answers.rules import ( + NotEmptyRule, + HasExactValueRule, + HasExactListRule, +) +from git_autograder.status import GitAutograderStatus +from git_autograder.test_utils import assert_output +from git_autograder import GitAutograderTestLoader + +from ..verify import ( + QUESTION_ONE, + QUESTION_TWO, + QUESTION_THREE, + QUESTION_FOUR, + SUCCESS_MESSAGE, + verify, +) + +REPOSITORY_NAME = "sensors-diff" + +loader = GitAutograderTestLoader(__file__, REPOSITORY_NAME, verify) + +CORRECT_QUESTION_ONE_ANSWER = "7590" +CORRECT_QUESTION_TWO_ANSWER = """ +- 3642 +- 4531 +""" +CORRECT_QUESTION_TWO_ANSWER_DIFFERENT_ORDER = """ +- 4531 +- 3642 +""" +INCORRECT_QUESTION_TWO_MISSING_VALUE = """ +- 4531 +""" +CORRECT_QUESTION_THREE_ANSWER = """ +- south.csv +- north.csv +- west.csv +""" +CORRECT_QUESTION_FOUR_ANSWER = "3471" +INCORRECT_ANSWER = "incorrect answer" + + +def test_valid_answers(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: CORRECT_QUESTION_ONE_ANSWER, + QUESTION_TWO: CORRECT_QUESTION_TWO_ANSWER, + QUESTION_THREE: CORRECT_QUESTION_THREE_ANSWER, + QUESTION_FOUR: CORRECT_QUESTION_FOUR_ANSWER, + }, + ) as output: + assert_output(output, GitAutograderStatus.SUCCESSFUL, [SUCCESS_MESSAGE]) + + +def test_valid_answers_different_order(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: CORRECT_QUESTION_ONE_ANSWER, + QUESTION_TWO: CORRECT_QUESTION_TWO_ANSWER_DIFFERENT_ORDER, + QUESTION_THREE: CORRECT_QUESTION_THREE_ANSWER, + QUESTION_FOUR: CORRECT_QUESTION_FOUR_ANSWER, + }, + ) as output: + assert_output(output, GitAutograderStatus.SUCCESSFUL, [SUCCESS_MESSAGE]) + + +def test_no_answers(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: "", + QUESTION_TWO: "", + QUESTION_THREE: "", + QUESTION_FOUR: "", + }, + ) as output: + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + NotEmptyRule.EMPTY.format(question=QUESTION_ONE), + NotEmptyRule.EMPTY.format(question=QUESTION_TWO), + NotEmptyRule.EMPTY.format(question=QUESTION_THREE), + NotEmptyRule.EMPTY.format(question=QUESTION_FOUR), + ], + ) + + +def test_incomplete_answers(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: CORRECT_QUESTION_ONE_ANSWER, + QUESTION_TWO: "", + QUESTION_THREE: "", + QUESTION_FOUR: "", + }, + ) as output: + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + NotEmptyRule.EMPTY.format(question=QUESTION_TWO), + NotEmptyRule.EMPTY.format(question=QUESTION_THREE), + NotEmptyRule.EMPTY.format(question=QUESTION_FOUR), + ], + ) + + +def test_incorrect_question_one_answer(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: INCORRECT_ANSWER, + QUESTION_TWO: CORRECT_QUESTION_TWO_ANSWER, + QUESTION_THREE: CORRECT_QUESTION_THREE_ANSWER, + QUESTION_FOUR: CORRECT_QUESTION_FOUR_ANSWER, + }, + ) as output: + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + HasExactValueRule.NOT_EXACT.format(question=QUESTION_ONE), + ], + ) + + +def test_incorrect_question_two_answer(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: CORRECT_QUESTION_ONE_ANSWER, + QUESTION_TWO: INCORRECT_ANSWER, + QUESTION_THREE: CORRECT_QUESTION_THREE_ANSWER, + QUESTION_FOUR: CORRECT_QUESTION_FOUR_ANSWER, + }, + ) as output: + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + HasExactListRule.INCORRECT_UNORDERED.format(question=QUESTION_TWO), + ], + ) + + +def test_incorrect_question_two_answer_missing_value(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: CORRECT_QUESTION_ONE_ANSWER, + QUESTION_TWO: INCORRECT_QUESTION_TWO_MISSING_VALUE, + QUESTION_THREE: CORRECT_QUESTION_THREE_ANSWER, + QUESTION_FOUR: CORRECT_QUESTION_FOUR_ANSWER, + }, + ) as output: + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + HasExactListRule.INCORRECT_UNORDERED.format(question=QUESTION_TWO), + ], + ) + + +def test_incorrect_question_three_answer(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: CORRECT_QUESTION_ONE_ANSWER, + QUESTION_TWO: CORRECT_QUESTION_TWO_ANSWER, + QUESTION_THREE: INCORRECT_ANSWER, + QUESTION_FOUR: CORRECT_QUESTION_FOUR_ANSWER, + }, + ) as output: + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + HasExactListRule.INCORRECT_UNORDERED.format(question=QUESTION_THREE), + ], + ) + + +def test_incorrect_question_four_answer(): + with loader.load( + "specs/base.yml", + mock_answers={ + QUESTION_ONE: CORRECT_QUESTION_ONE_ANSWER, + QUESTION_TWO: CORRECT_QUESTION_TWO_ANSWER, + QUESTION_THREE: CORRECT_QUESTION_THREE_ANSWER, + QUESTION_FOUR: INCORRECT_ANSWER, + }, + ) as output: + assert_output( + output, + GitAutograderStatus.UNSUCCESSFUL, + [ + HasExactValueRule.NOT_EXACT.format(question=QUESTION_FOUR), + ], + ) diff --git a/sensors_diff/verify.py b/sensors_diff/verify.py new file mode 100644 index 0000000..63149c1 --- /dev/null +++ b/sensors_diff/verify.py @@ -0,0 +1,48 @@ +from git_autograder import ( + GitAutograderOutput, + GitAutograderExercise, + GitAutograderStatus, +) +from git_autograder.answers.rules import ( + HasExactValueRule, + NotEmptyRule, + HasExactListRule, +) + +QUESTION_ONE = "Which are the new values in staged files?" +QUESTION_TWO = "Which are the new values in modified but unstaged files?" +QUESTION_THREE = "Which files have changed from Jan 09th to Jan 15th?" +QUESTION_FOUR = ( + "Which new values are new in north.csv on Jan 10th, compared to Jan 01st?" +) +SUCCESS_MESSAGE = "Great work comparing commits in git history!" + + +def verify(exercise: GitAutograderExercise) -> GitAutograderOutput: + ( + exercise.answers.add_validation(QUESTION_ONE, NotEmptyRule()) + .add_validation(QUESTION_ONE, HasExactValueRule("7590", is_case_sensitive=True)) + .add_validation( + QUESTION_TWO, + NotEmptyRule(), + HasExactListRule(["4531", "3642"], is_case_sensitive=True), + ) + .add_validation( + QUESTION_THREE, + NotEmptyRule(), + HasExactListRule( + ["north.csv", "south.csv", "west.csv"], is_case_sensitive=True + ), + ) + .add_validation( + QUESTION_FOUR, + NotEmptyRule(), + HasExactValueRule("3471", is_case_sensitive=True), + ) + .validate() + ) + + return exercise.to_output( + [SUCCESS_MESSAGE], + GitAutograderStatus.SUCCESSFUL, + )