Skip to content

Commit 5022774

Browse files
committed
Improve eq checks and compare_output
1 parent bbf49d7 commit 5022774

10 files changed

+118
-8
lines changed

stanfordkarel/karel_ascii.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -220,14 +220,34 @@ def symmetric_difference(
220220
f"Student: {(first.avenue, first.street)}\n"
221221
f"Expected: {(second.avenue, second.street)}\n\n"
222222
)
223-
if first.world.beepers != second.world.beepers:
223+
224+
if first.direction != second.direction:
225+
result += (
226+
"Karel not facing the correct direction.\n"
227+
f"Student: {first.direction}\n"
228+
f"Expected: {second.direction}\n\n"
229+
)
230+
231+
if first.world.get_beepers() != second.world.get_beepers():
224232
extra_a, extra_b = symmetric_difference(
225-
first.world.beepers, second.world.beepers
233+
first.world.get_beepers(), second.world.get_beepers()
226234
)
227235
result += (
228236
"Beepers do not match: "
229237
"(Only beepers that appear in one world but not the other are listed)\n"
230238
f"Student: {extra_a}\n"
231239
f"Expected: {extra_b}\n\n"
232240
)
241+
242+
if first.world.get_colors() != second.world.get_colors():
243+
extra_a, extra_b = symmetric_difference(
244+
first.world.get_colors(), second.world.get_colors()
245+
)
246+
result += (
247+
"Colors do not match: "
248+
"(Only colors that appear in one world but not the other are listed)\n"
249+
f"Student: {extra_a}\n"
250+
f"Expected: {extra_b}\n\n"
251+
)
252+
233253
return result

stanfordkarel/karel_world.py

+26-4
Original file line numberDiff line numberDiff line change
@@ -116,14 +116,36 @@ def __init__(self, world_file: str) -> None:
116116
# Save initial beeper state to enable world reset
117117
self.init_beepers = copy.deepcopy(self.beepers)
118118

119+
def get_beepers(self) -> dict[tuple[int, int], int]:
120+
"""
121+
Return a beeper dictionary, which is free of any 0 count beepers that
122+
occur as a side effect of calls such as `beepers_present`.
123+
"""
124+
beepers: dict[tuple[int, int], int] = collections.defaultdict(int)
125+
for (x, y), count in sorted(self.beepers.items()):
126+
if count != 0:
127+
beepers[(x, y)] = count
128+
return beepers
129+
130+
def get_colors(self) -> dict[tuple[int, int], str]:
131+
"""
132+
Return a color dictionary, which is free of any blank '' colors that
133+
occur as a side effect of calls such as `corner_color_is`.
134+
"""
135+
colors: dict[tuple[int, int], str] = collections.defaultdict(str)
136+
for (x, y), color in sorted(self.corner_colors.items()):
137+
if color != "":
138+
colors[(x, y)] = color
139+
return colors
140+
119141
def __eq__(self, other: object) -> bool:
120142
if isinstance(other, KarelWorld):
121143
return (
122-
self.beepers == other.beepers
123-
and self.walls == other.walls
124-
and self.num_streets == other.num_streets
144+
self.num_streets == other.num_streets
125145
and self.num_avenues == other.num_avenues
126-
and self.corner_colors == other.corner_colors
146+
and self.walls == other.walls
147+
and self.get_beepers() == other.get_beepers()
148+
and self.get_colors() == other.get_colors()
127149
)
128150
return NotImplemented
129151

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

tests/exceptions_test.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626

2727
@pytest.mark.parametrize(("code_file", "expected_error"), TEST_CASES)
2828
def test_exceptions(tmp_path: Path, code_file: str, expected_error: str) -> None:
29-
txt_file_contents = Path(f"tests/programs/{code_file}").read_text(encoding="utf-8")
29+
txt_file_contents = Path(f"tests/exception_programs/{code_file}").read_text(
30+
encoding="utf-8"
31+
)
3032
py_path = (tmp_path / code_file).with_suffix(".py")
3133
py_path.write_text(txt_file_contents)
3234
execute_karel_code(
@@ -39,7 +41,7 @@ def test_file_coverage() -> None:
3941
tested_files = {filepath for filepath, _ in TEST_CASES}
4042
test_programs = {
4143
filepath.name
42-
for filepath in Path("tests/programs").glob("*.txt")
44+
for filepath in Path("tests/exception_programs").glob("*.txt")
4345
if filepath.name not in IGNORED_FILES
4446
}
4547
untested_files = tested_files ^ test_programs

tests/karel_world_test.py

+46
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from pathlib import Path
22

3+
from stanfordkarel.karel_application import StudentCode
34
from stanfordkarel.karel_program import KarelProgram
45

56
STONE_MASON_ASCII_OUTPUT = (
@@ -87,3 +88,48 @@ def test_save_to_file(tmp_path: Path) -> None:
8788
)
8889

8990
assert output_file.read_text() == "\n".join(expected) + "\n"
91+
92+
@staticmethod
93+
def test_empty_beepers(tmp_path: Path) -> None:
94+
code_file = "empty_beeper.txt"
95+
txt_file_contents = Path(f"tests/programs/{code_file}").read_text(
96+
encoding="utf-8"
97+
)
98+
py_path = (tmp_path / code_file).with_suffix(".py")
99+
py_path.write_text(txt_file_contents)
100+
101+
test_program = KarelProgram("1x1")
102+
103+
test_code = StudentCode(py_path)
104+
test_code.inject_namespace(test_program)
105+
test_code.main()
106+
107+
ref_program = KarelProgram("1x1")
108+
109+
assert ref_program.world.get_beepers() == test_program.world.get_beepers()
110+
111+
@staticmethod
112+
def test_empty_colors(tmp_path: Path) -> None:
113+
code_file = "empty_color.txt"
114+
txt_file_contents = Path(f"tests/programs/{code_file}").read_text(
115+
encoding="utf-8"
116+
)
117+
py_path = (tmp_path / code_file).with_suffix(".py")
118+
py_path.write_text(txt_file_contents)
119+
120+
test_program = KarelProgram("1x1")
121+
122+
test_code = StudentCode(py_path)
123+
test_code.inject_namespace(test_program)
124+
test_code.main()
125+
126+
ref_program = KarelProgram("1x1")
127+
128+
assert ref_program.world.get_beepers() == test_program.world.get_beepers()
129+
130+
@staticmethod
131+
def test_equal_worlds() -> None:
132+
test_program = KarelProgram("1x1")
133+
ref_program = KarelProgram("1x1")
134+
135+
assert ref_program.world == test_program.world

tests/programs/empty_beeper.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from stanfordkarel import *
2+
3+
4+
def main():
5+
if corner_color_is(PINK):
6+
turn_left()
7+
8+
9+
if __name__ == "__main__":
10+
run_karel_program()

tests/programs/empty_color.txt

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from stanfordkarel import *
2+
3+
4+
def main():
5+
if beepers_present():
6+
turn_left()
7+
8+
9+
if __name__ == "__main__":
10+
run_karel_program()

0 commit comments

Comments
 (0)