|
17 | 17 |
|
18 | 18 | from in2lambda.api.part import Part |
19 | 19 | from in2lambda.api.question import Question |
20 | | -from in2lambda.api.response_area import Case, ResponseArea, Test |
| 20 | +from in2lambda.api.response_area import Case, InputSymbol, ResponseArea, Test |
21 | 21 | from in2lambda.api.set import Set |
22 | 22 |
|
23 | 23 | each_export = pytest.mark.parametrize("export_dir", EXPORTS, ids=lambda path: path.name) |
@@ -132,22 +132,76 @@ def test_written_keys_exist_in_export(export_dir: Path, tmp_path: Path) -> None: |
132 | 132 | assert not missing, missing |
133 | 133 |
|
134 | 134 |
|
135 | | -def test_response_area_built_in_python_writes_distinct_ids(tmp_path: Path) -> None: |
136 | | - """Tests and cases given no id are written with a distinct uuid each, as import needs.""" |
137 | | - area = ResponseArea( |
138 | | - tests=[Test("x", True), Test("y", False)], |
139 | | - cases=[Case("x", "", True), Case("y", "", False)], |
| 135 | +def _area_shape(area: dict) -> frozenset[str]: |
| 136 | + # Without indices, an area's shape is the keys it has, not how many tests, cases |
| 137 | + # or symbols it lists. |
| 138 | + return frozenset(re.sub(r"\[\d+\]", "[]", path) for path in _key_paths(area)) |
| 139 | + |
| 140 | + |
| 141 | +def test_response_areas_built_in_python_write_as_exported(tmp_path: Path) -> None: |
| 142 | + """Boxes of each exported type built in Python reload unchanged, shaped as exported.""" |
| 143 | + part = Part( |
| 144 | + text="Find the drag, then say whether it scales.", |
| 145 | + response_areas=[ |
| 146 | + ResponseArea( |
| 147 | + response_type="MATH_SINGLE_LINE", |
| 148 | + answer="(pi/6)*rho*U**2*R**2", |
| 149 | + config={ |
| 150 | + "allowPhoto": True, |
| 151 | + "allowHandwrite": True, |
| 152 | + "enableRefinement": True, |
| 153 | + }, |
| 154 | + evaluation_function="symbolicEqual", |
| 155 | + grade_params={"strict_syntax": False}, |
| 156 | + pre_text="$D=$", |
| 157 | + content_after="Now put in the numbers.", |
| 158 | + input_symbols=[InputSymbol("\\(R\\)", "R", ["r"])], |
| 159 | + tests=[Test("(pi/6)*rho*U**2*R**2", True)], |
| 160 | + cases=[Case("pi*rho*U**2*R**2", "A factor is missing.", False)], |
| 161 | + ), |
| 162 | + ResponseArea( |
| 163 | + response_type="NUMERIC_UNITS", |
| 164 | + answer="30 N", |
| 165 | + evaluation_function="comparePhysicalQuantities", |
| 166 | + grade_params={"rtol": 0.05, "strict_syntax": False}, |
| 167 | + tests=[Test("30 N", True), Test("30", False)], |
| 168 | + cases=[ |
| 169 | + Case("30 kg m s-2", "Put negative exponents in brackets.", False) |
| 170 | + ], |
| 171 | + ), |
| 172 | + ResponseArea( |
| 173 | + response_type="MULTIPLE_CHOICE", |
| 174 | + answer=[True, False], |
| 175 | + config={"single": True, "options": ["Yes", "No"], "randomise": False}, |
| 176 | + evaluation_function="arrayEqual", |
| 177 | + ), |
| 178 | + ], |
140 | 179 | ) |
141 | | - question_set = Set(questions=[Question(parts=[Part(response_areas=[area])])]) |
| 180 | + written = _write_back(Set(questions=[Question(parts=[part])]), tmp_path) |
| 181 | + |
| 182 | + # Equality includes the ids, so reloading must keep the ones that were written. |
| 183 | + assert Set.from_json(str(written)).questions[0].parts == [part] |
142 | 184 |
|
143 | | - written = _write_back(question_set, tmp_path) |
144 | 185 | (question_file,) = written.glob("question_*.json") |
145 | | - (written_area,) = json.loads(question_file.read_text())["parts"][0]["responseAreas"] |
| 186 | + written_areas = json.loads(question_file.read_text())["parts"][0]["responseAreas"] |
146 | 187 |
|
147 | | - ids = [item["id"] for item in written_area["tests"] + written_area["cases"]] |
148 | | - assert len(set(ids)) == 4 |
| 188 | + # Import needs every test and case given no id to be written with its own uuid. |
| 189 | + ids = [ |
| 190 | + item["id"] for area in written_areas for item in area["tests"] + area["cases"] |
| 191 | + ] |
| 192 | + assert len(set(ids)) == 5 |
149 | 193 | assert all(uuid.UUID(id_) for id_ in ids) |
150 | 194 |
|
| 195 | + exported_shapes = { |
| 196 | + _area_shape(area) |
| 197 | + for export_dir in EXPORTS |
| 198 | + for file in export_dir.glob("question_*.json") |
| 199 | + for exported_part in json.loads(file.read_text())["parts"] |
| 200 | + for area in exported_part["responseAreas"] |
| 201 | + } |
| 202 | + for area in written_areas: |
| 203 | + assert _area_shape(area) in exported_shapes, area["response"] |
| 204 | + |
151 | 205 |
|
152 | 206 | def test_from_json_rejects_folder_without_set(tmp_path: Path) -> None: |
153 | 207 | """A folder with no set file is refused with an error that says where it looked.""" |
|
0 commit comments