@@ -564,3 +564,145 @@ func TestDiscoverRelatedProjectDirs_EmptyStorage(t *testing.T) {
564564 t .Errorf ("expected empty slice, got %v" , related )
565565 }
566566}
567+
568+ func TestMalformedProjectJSON (t * testing.T ) {
569+ tmpDir := t .TempDir ()
570+ projectDir := filepath .Join (tmpDir , "project" )
571+ if err := os .MkdirAll (projectDir , 0755 ); err != nil {
572+ t .Fatalf ("failed to create project dir: %v" , err )
573+ }
574+
575+ validJSON := `{"id":"proj_valid","worktree":"/tmp/valid-project","vcs":"git","time":{"created":1767000000000,"updated":1767100000000}}`
576+ if err := os .WriteFile (filepath .Join (projectDir , "valid.json" ), []byte (validJSON ), 0644 ); err != nil {
577+ t .Fatalf ("failed to write valid project: %v" , err )
578+ }
579+
580+ malformedJSON := `{invalid json`
581+ if err := os .WriteFile (filepath .Join (projectDir , "bad.json" ), []byte (malformedJSON ), 0644 ); err != nil {
582+ t .Fatalf ("failed to write malformed project: %v" , err )
583+ }
584+
585+ a := & Adapter {
586+ storageDir : tmpDir ,
587+ projectIndex : make (map [string ]* Project ),
588+ sessionIndex : make (map [string ]string ),
589+ metaCache : make (map [string ]sessionMetaCacheEntry ),
590+ }
591+
592+ if err := a .loadProjects (); err != nil {
593+ t .Fatalf ("loadProjects should not error on malformed JSON, got: %v" , err )
594+ }
595+
596+ if ! a .projectsLoaded {
597+ t .Error ("projectsLoaded should be true" )
598+ }
599+
600+ if len (a .projectIndex ) != 1 {
601+ t .Errorf ("expected 1 project in index, got %d" , len (a .projectIndex ))
602+ }
603+
604+ if _ , ok := a .projectIndex ["/tmp/valid-project" ]; ! ok {
605+ t .Error ("expected valid project to be in index" )
606+ }
607+ }
608+
609+ func TestMalformedSessionJSON (t * testing.T ) {
610+ tmpDir := t .TempDir ()
611+ projectPath := filepath .Join (tmpDir , "myproject" )
612+ if err := os .MkdirAll (projectPath , 0755 ); err != nil {
613+ t .Fatalf ("failed to create project path: %v" , err )
614+ }
615+
616+ projectDir := filepath .Join (tmpDir , "storage" , "project" )
617+ if err := os .MkdirAll (projectDir , 0755 ); err != nil {
618+ t .Fatalf ("failed to create project dir: %v" , err )
619+ }
620+ projectJSON := fmt .Sprintf (`{"id":"proj1","worktree":"%s","vcs":"git","time":{"created":1767000000000,"updated":1767100000000}}` , projectPath )
621+ if err := os .WriteFile (filepath .Join (projectDir , "proj1.json" ), []byte (projectJSON ), 0644 ); err != nil {
622+ t .Fatalf ("failed to write project file: %v" , err )
623+ }
624+
625+ sessionDir := filepath .Join (tmpDir , "storage" , "session" , "proj1" )
626+ if err := os .MkdirAll (sessionDir , 0755 ); err != nil {
627+ t .Fatalf ("failed to create session dir: %v" , err )
628+ }
629+
630+ now := time .Now ().UnixMilli ()
631+ validSession := fmt .Sprintf (`{"id":"ses_good","title":"Good Session","parentID":"","time":{"created":%d,"updated":%d}}` , now , now )
632+ if err := os .WriteFile (filepath .Join (sessionDir , "ses_good.json" ), []byte (validSession ), 0644 ); err != nil {
633+ t .Fatalf ("failed to write valid session: %v" , err )
634+ }
635+
636+ malformedSession := `{not valid json!!!`
637+ if err := os .WriteFile (filepath .Join (sessionDir , "ses_bad.json" ), []byte (malformedSession ), 0644 ); err != nil {
638+ t .Fatalf ("failed to write malformed session: %v" , err )
639+ }
640+
641+ a := & Adapter {
642+ storageDir : filepath .Join (tmpDir , "storage" ),
643+ projectIndex : make (map [string ]* Project ),
644+ sessionIndex : make (map [string ]string ),
645+ metaCache : make (map [string ]sessionMetaCacheEntry ),
646+ }
647+
648+ sessions , err := a .Sessions (projectPath )
649+ if err != nil {
650+ t .Fatalf ("Sessions should not error on malformed JSON, got: %v" , err )
651+ }
652+
653+ if len (sessions ) != 1 {
654+ t .Fatalf ("expected 1 session (malformed skipped), got %d" , len (sessions ))
655+ }
656+
657+ if sessions [0 ].ID != "ses_good" {
658+ t .Errorf ("expected session ID %q, got %q" , "ses_good" , sessions [0 ].ID )
659+ }
660+
661+ if sessions [0 ].Name != "Good Session" {
662+ t .Errorf ("expected session name %q, got %q" , "Good Session" , sessions [0 ].Name )
663+ }
664+ }
665+
666+ func TestMalformedMessageJSON (t * testing.T ) {
667+ tmpDir := t .TempDir ()
668+ messageDir := filepath .Join (tmpDir , "message" , "ses_test" )
669+ if err := os .MkdirAll (messageDir , 0755 ); err != nil {
670+ t .Fatalf ("failed to create message dir: %v" , err )
671+ }
672+
673+ now := time .Now ().UnixMilli ()
674+ validMsg := fmt .Sprintf (`{"id":"msg_good","sessionID":"ses_test","role":"user","time":{"created":%d}}` , now )
675+ if err := os .WriteFile (filepath .Join (messageDir , "msg_good.json" ), []byte (validMsg ), 0644 ); err != nil {
676+ t .Fatalf ("failed to write valid message: %v" , err )
677+ }
678+
679+ malformedMsg := `{totally broken json`
680+ if err := os .WriteFile (filepath .Join (messageDir , "msg_bad.json" ), []byte (malformedMsg ), 0644 ); err != nil {
681+ t .Fatalf ("failed to write malformed message: %v" , err )
682+ }
683+
684+ a := & Adapter {
685+ storageDir : tmpDir ,
686+ projectIndex : make (map [string ]* Project ),
687+ sessionIndex : make (map [string ]string ),
688+ metaCache : make (map [string ]sessionMetaCacheEntry ),
689+ }
690+
691+ msgMap , err := a .batchReadMessages (messageDir )
692+ if err != nil {
693+ t .Fatalf ("batchReadMessages should not error on malformed JSON, got: %v" , err )
694+ }
695+
696+ if len (msgMap ) != 1 {
697+ t .Fatalf ("expected 1 message (malformed skipped), got %d" , len (msgMap ))
698+ }
699+
700+ msg , ok := msgMap ["msg_good" ]
701+ if ! ok {
702+ t .Fatal ("expected msg_good in result map" )
703+ }
704+
705+ if msg .Role != "user" {
706+ t .Errorf ("expected role %q, got %q" , "user" , msg .Role )
707+ }
708+ }
0 commit comments