| 167 | |
| 168 | |
| 169 | class TestSerializeDeserialize(unittest.TestCase): |
| 170 | def _make_entry(self) -> FileCacheEntry: |
| 171 | src = "def foo(): pass\n" |
| 172 | tree = ast.parse(src) |
| 173 | full_json, chunks = _build_ast_json_and_chunks(tree, src, {}) |
| 174 | return FileCacheEntry( |
| 175 | file_path="/tmp/test_file.py", |
| 176 | file_hash=hashlib.sha256(src.encode()).hexdigest(), |
| 177 | mtime=1234567890.0, |
| 178 | full_ast_json_z=zlib.compress(full_json.encode()), |
| 179 | chunks=chunks, |
| 180 | ) |
| 181 | |
| 182 | def test_roundtrip(self): |
| 183 | entry = self._make_entry() |
| 184 | restored = _deserialize_entry(_serialize_entry(entry)) |
| 185 | self.assertEqual(restored.file_path, entry.file_path) |
| 186 | self.assertEqual(restored.file_hash, entry.file_hash) |
| 187 | self.assertEqual(restored.mtime, entry.mtime) |
| 188 | self.assertEqual(restored.full_ast_json_z, entry.full_ast_json_z) |
| 189 | self.assertEqual(restored.version, entry.version) |
| 190 | self.assertEqual(set(restored.chunks.keys()), set(entry.chunks.keys())) |
| 191 | |
| 192 | def test_serialized_is_json_not_pickle(self): |
| 193 | entry = self._make_entry() |
| 194 | raw = _serialize_entry(entry) |
| 195 | # Must be valid JSON |
| 196 | d = json.loads(raw) |
| 197 | self.assertIn("version", d) |
| 198 | self.assertIn("file_hash", d) |
| 199 | # Must NOT be a pickle stream (pickle starts with 0x80 or b'\x80') |
| 200 | self.assertFalse(raw.encode()[0:1] == b'\x80') |
| 201 | # Must start with '{' (JSON object) |
| 202 | self.assertEqual(raw[0], '{') |
| 203 | |
| 204 | def test_deserialize_raises_on_garbage(self): |
| 205 | with self.assertRaises(Exception): |
| 206 | _deserialize_entry("not json at all }{") |
| 207 | |
| 208 | |
| 209 | # ── TestIncrementalAstCache ─────────────────────────────────────────────────── |
nothing calls this directly
no outgoing calls
no test coverage detected