2424from models import Bubble , SchemaError
2525from utils .cli_chat_reader import (
2626 classify_blob_data ,
27+ extract_blob_refs ,
2728 messages_to_bubbles ,
2829 traverse_blobs ,
29- _extract_blob_refs , # internal helper; covered directly alongside classify_blob_data
3030)
3131from utils .text_extract import extract_text_from_bubble
3232
@@ -132,17 +132,39 @@ def _make_meta_value(meta: dict) -> str:
132132
133133
134134def _build_store_db_raw (path : str , meta : dict , blobs : dict [str , bytes ]) -> None :
135- """Minimal store.db with arbitrary blob payloads (for traverse_blobs fuzz)."""
135+ """Minimal store.db with well-formed meta dict and arbitrary blob payloads."""
136+ _build_store_db_meta_row (path , _make_meta_value (meta ), blobs )
137+
138+
139+ def _build_store_db_meta_row (
140+ path : str , meta_row : str | None , blobs : dict [str , bytes ]
141+ ) -> None :
142+ """Minimal store.db; *meta_row* is the raw ``meta.value`` (hex JSON or adversarial)."""
136143 conn = sqlite3 .connect (path )
137144 conn .execute ("CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT)" )
138145 conn .execute ("CREATE TABLE blobs (id TEXT PRIMARY KEY, data BLOB)" )
139- conn .execute ("INSERT INTO meta VALUES ('0', ?)" , (_make_meta_value (meta ),))
146+ if meta_row is not None :
147+ conn .execute ("INSERT INTO meta VALUES ('0', ?)" , (meta_row ,))
140148 for blob_id , data in blobs .items ():
141149 conn .execute ("INSERT INTO blobs VALUES (?, ?)" , (blob_id , data ))
142150 conn .commit ()
143151 conn .close ()
144152
145153
154+ _FUZZ_META_ROW = st .one_of (
155+ st .none (),
156+ st .just ("" ),
157+ st .text (min_size = 0 , max_size = 200 ),
158+ st .dictionaries (st .text (max_size = 20 ), _JSON_VALUES , max_size = 6 ).map (
159+ lambda d : json .dumps (d ).encode ("utf-8" ).hex ()
160+ ),
161+ st .builds (
162+ lambda root : _make_meta_value ({"latestRootBlobId" : root , "createdAt" : 1 }),
163+ _BLOB_ID_HEX ,
164+ ),
165+ )
166+
167+
146168def _assemble_workspace_bubble (bubble_id : object , value : object ) -> dict | None :
147169 """Mirror workspace_tabs KV bubble load (json.loads → Bubble.from_dict).
148170
@@ -219,7 +241,7 @@ class TestBlobChainParsingFuzz(unittest.TestCase):
219241 @settings (max_examples = 120 , deadline = None )
220242 def test_extract_blob_refs_never_raises (self , data : bytes ) -> None :
221243 try :
222- refs = _extract_blob_refs (data )
244+ refs = extract_blob_refs (data )
223245 except Exception as exc :
224246 self .fail (f"unexpected { type (exc ).__name__ } : { exc } " )
225247 self .assertIsInstance (refs , list )
@@ -230,7 +252,7 @@ def test_extract_blob_refs_never_raises(self, data: bytes) -> None:
230252 @given (data = st .binary (max_size = 4096 ))
231253 @settings (max_examples = 80 , deadline = None )
232254 def test_extract_blob_refs_is_idempotent (self , data : bytes ) -> None :
233- self .assertEqual (_extract_blob_refs (data ), _extract_blob_refs (data ))
255+ self .assertEqual (extract_blob_refs (data ), extract_blob_refs (data ))
234256
235257 @given (data = st .binary (max_size = 4096 ))
236258 @settings (max_examples = 80 , deadline = None )
@@ -273,6 +295,23 @@ def test_traverse_blobs_never_raises(
273295 self .fail (f"traverse_blobs raised { type (exc ).__name__ } : { exc } " )
274296 self .assertIsInstance (messages , list )
275297
298+ @given (meta_row = _FUZZ_META_ROW )
299+ @settings (
300+ max_examples = 30 ,
301+ deadline = None ,
302+ suppress_health_check = [HealthCheck .too_slow ],
303+ )
304+ def test_traverse_blobs_meta_parse_never_raises (self , meta_row : str | None ) -> None :
305+ """Covers meta decode / CliSessionMeta.from_dict failure → return [] (no crash)."""
306+ with tempfile .TemporaryDirectory () as td :
307+ db_path = os .path .join (td , "store.db" )
308+ _build_store_db_meta_row (db_path , meta_row , {})
309+ try :
310+ messages = traverse_blobs (db_path )
311+ except Exception as exc :
312+ self .fail (f"traverse_blobs raised { type (exc ).__name__ } : { exc } " )
313+ self .assertIsInstance (messages , list )
314+
276315
277316class TestTextExtractionFuzz (unittest .TestCase ):
278317 @given (bubble = _BUBBLE_LIKE )
0 commit comments