| 68 | |
| 69 | |
| 70 | class TestBuildAstJson(unittest.TestCase): |
| 71 | def _build(self, source: str, old: dict | None = None) -> tuple: |
| 72 | tree = ast.parse(source) |
| 73 | return _build_ast_json_and_chunks(tree, source, old or {}) |
| 74 | |
| 75 | def test_empty_module(self): |
| 76 | json_str, chunks = self._build("") |
| 77 | parsed = _parse_json(json_str) |
| 78 | self.assertEqual(parsed["node_type"], "Module") |
| 79 | self.assertEqual(parsed["fields"]["body"], []) |
| 80 | self.assertEqual(chunks, {}) |
| 81 | |
| 82 | def test_single_function_structure(self): |
| 83 | src = "def foo(x):\n return x + 1\n" |
| 84 | json_str, chunks = self._build(src) |
| 85 | parsed = _parse_json(json_str) |
| 86 | body = parsed["children"]["body"] |
| 87 | self.assertEqual(len(body), 1) |
| 88 | self.assertEqual(body[0]["node_type"], "FunctionDef") |
| 89 | self.assertIn("FunctionDef:foo", chunks) |
| 90 | |
| 91 | def test_json_matches_direct_encoder(self): |
| 92 | src = "x = 1\ndef foo(): pass\nclass Bar: pass\n" |
| 93 | tree = ast.parse(src) |
| 94 | direct = json.dumps(tree, cls=AstEncoder) |
| 95 | incremental, _ = self._build(src) |
| 96 | self.assertEqual(_parse_json(direct), _parse_json(incremental)) |
| 97 | |
| 98 | def test_chunk_reuse_skips_encoding(self): |
| 99 | src = "def foo(): pass\ndef bar(): pass\n" |
| 100 | _, old_chunks = self._build(src) |
| 101 | |
| 102 | new_src = "def foo(): pass\ndef bar(): return 42\n" |
| 103 | new_tree = ast.parse(new_src) |
| 104 | _, new_chunks = _build_ast_json_and_chunks(new_tree, new_src, old_chunks) |
| 105 | |
| 106 | # Unchanged chunk: identical compressed bytes reused |
| 107 | self.assertEqual(old_chunks["FunctionDef:foo"].ast_json_z, new_chunks["FunctionDef:foo"].ast_json_z) |
| 108 | # Changed chunk: different bytes |
| 109 | self.assertNotEqual( |
| 110 | old_chunks["FunctionDef:bar"].ast_json_z, |
| 111 | new_chunks["FunctionDef:bar"].ast_json_z, |
| 112 | ) |
| 113 | |
| 114 | def test_moved_chunk_not_reused(self): |
| 115 | src = "def foo(): pass\ndef bar(): pass\n" |
| 116 | _, old_chunks = self._build(src) |
| 117 | |
| 118 | # Insert a line at top → foo shifts to line 2 |
| 119 | new_src = "x = 1\ndef foo(): pass\ndef bar(): pass\n" |
| 120 | new_tree = ast.parse(new_src) |
| 121 | _, new_chunks = _build_ast_json_and_chunks(new_tree, new_src, old_chunks) |
| 122 | |
| 123 | # foo moved from line 1 → 2: must NOT reuse |
| 124 | self.assertNotEqual( |
| 125 | old_chunks["FunctionDef:foo"].ast_json_z, |
| 126 | new_chunks["FunctionDef:foo"].ast_json_z, |
| 127 | ) |
nothing calls this directly
no outgoing calls
no test coverage detected