package store import ( "os" "path/filepath" "testing" ) // TestBackupSQLiteCreatesValidRestorePoint pins the F4 happy path: a green integrity_check followed by a // VACUUM INTO copy that is itself a valid, integrity-clean, openable SQLite project database. func TestBackupSQLiteCreatesValidRestorePoint(t *testing.T) { dir := t.TempDir() dbPath := filepath.Join(dir, "book.db") s, err := Open(dbPath) // a real, migrated project DB if err != nil { t.Fatalf("open source: %v", err) } s.Close() backupDir := filepath.Join(dir, "backups") const stamp = "20260802T000000Z" path, err := BackupSQLite(dbPath, backupDir, stamp) if err != nil { t.Fatalf("backup: %v", err) } if want := filepath.Join(backupDir, stamp+".db"); path != want { t.Fatalf("backup path = %q, want %q", path, want) } if _, err := os.Stat(path); err != nil { t.Fatalf("backup file missing: %v", err) } // The backup must itself pass integrity and be openable as a store (a real, migrated copy). if err := IntegrityCheck(path); err != nil { t.Errorf("the backup failed its own integrity_check: %v", err) } s2, err := Open(path) if err != nil { t.Fatalf("backup is not openable as a project store: %v", err) } s2.Close() } // TestBackupRefusesCorruptSource pins the SPOF half: a source that is not a valid SQLite file fails loud and // writes NO backup — a corrupt bank must never be laundered into a trusted restore point. func TestBackupRefusesCorruptSource(t *testing.T) { dir := t.TempDir() dbPath := filepath.Join(dir, "corrupt.db") if err := os.WriteFile(dbPath, []byte("this is not a sqlite database, just garbage bytes"), 0o644); err != nil { t.Fatal(err) } backupDir := filepath.Join(dir, "backups") if _, err := BackupSQLite(dbPath, backupDir, "x"); err == nil { t.Fatal("a corrupt source must fail loud, not silently produce a backup") } if _, err := os.Stat(filepath.Join(backupDir, "x.db")); err == nil { t.Error("no backup file may be written when the source fails integrity") } } // TestBackupRefusesMissingSource and refuses to overwrite an existing restore point. func TestBackupRefusesMissingSourceAndOverwrite(t *testing.T) { dir := t.TempDir() if _, err := BackupSQLite(filepath.Join(dir, "nope.db"), filepath.Join(dir, "b"), "x"); err == nil { t.Fatal("a missing source must be a loud error") } dbPath := filepath.Join(dir, "book.db") s, err := Open(dbPath) if err != nil { t.Fatal(err) } s.Close() backupDir := filepath.Join(dir, "backups") if _, err := BackupSQLite(dbPath, backupDir, "same"); err != nil { t.Fatalf("first backup: %v", err) } if _, err := BackupSQLite(dbPath, backupDir, "same"); err == nil { t.Fatal("a second backup at the same stamp must refuse to overwrite the restore point") } }