Verify that the PyDict_Next fast path (unsorted exact dict) and the iterator slow path (sorted, dict subclass, or non-dict mapping) produce identical output for a variety of edge cases.
| 285 | |
| 286 | |
| 287 | class TestDictEncodingPaths(TestCase): |
| 288 | """Verify that the PyDict_Next fast path (unsorted exact dict) and the |
| 289 | iterator slow path (sorted, dict subclass, or non-dict mapping) produce |
| 290 | identical output for a variety of edge cases.""" |
| 291 | |
| 292 | def _assert_same_output(self, data, **kwargs): |
| 293 | """Encode data and verify the result round-trips correctly.""" |
| 294 | encoded = json.dumps(data, **kwargs) |
| 295 | decoded = json.loads(encoded) |
| 296 | # Keys are always strings after round-trip |
| 297 | expected = json.loads(json.dumps(data, **kwargs)) |
| 298 | self.assertEqual(decoded, expected) |
| 299 | return encoded |
| 300 | |
| 301 | def test_exact_dict_unsorted(self): |
| 302 | """Fast path: exact dict, sort_keys=False.""" |
| 303 | d = {"b": 2, "a": 1, "c": 3} |
| 304 | result = json.loads(json.dumps(d)) |
| 305 | self.assertEqual(result, d) |
| 306 | |
| 307 | def test_exact_dict_sorted(self): |
| 308 | """Slow path: exact dict, sort_keys=True.""" |
| 309 | d = {"b": 2, "a": 1, "c": 3} |
| 310 | self.assertEqual( |
| 311 | json.dumps(d, sort_keys=True), |
| 312 | '{"a": 1, "b": 2, "c": 3}') |
| 313 | |
| 314 | def test_dict_subclass_unsorted(self): |
| 315 | """Slow path: dict subclass falls back to iterator path.""" |
| 316 | class MyDict(dict): |
| 317 | pass |
| 318 | d = MyDict(b=2, a=1, c=3) |
| 319 | result = json.loads(json.dumps(d)) |
| 320 | self.assertEqual(result, {"a": 1, "b": 2, "c": 3}) |
| 321 | |
| 322 | def test_dict_subclass_sorted(self): |
| 323 | """Slow path: dict subclass with sort_keys=True.""" |
| 324 | class MyDict(dict): |
| 325 | pass |
| 326 | d = MyDict([("z", 26), ("a", 1), ("m", 13)]) |
| 327 | self.assertEqual( |
| 328 | json.dumps(d, sort_keys=True), |
| 329 | '{"a": 1, "m": 13, "z": 26}') |
| 330 | |
| 331 | def test_non_string_keys_fast_path(self): |
| 332 | """Fast path with non-string keys that get stringified.""" |
| 333 | d = {1: "int", 2.5: "float", True: "bool", None: "none"} |
| 334 | result = json.loads(json.dumps(d)) |
| 335 | # All keys become strings |
| 336 | for v in result.values(): |
| 337 | self.assertIn(v, ["int", "float", "bool", "none"]) |
| 338 | |
| 339 | def test_non_string_keys_sorted(self): |
| 340 | """Slow path with non-string keys + sort_keys.""" |
| 341 | d = {1: "a", 2: "b", 3: "c"} |
| 342 | self.assertEqual( |
| 343 | json.dumps(d, sort_keys=True), |
| 344 | '{"1": "a", "2": "b", "3": "c"}') |
nothing calls this directly
no outgoing calls
no test coverage detected
searching dependent graphs…