Files
Ein Anderssono 2e73d01b40
pipeline / build (push) Has been cancelled
pipeline / test (push) Has been cancelled
v0.5.0: manifests, filters, logging, docs
2026-06-15 00:00:06 +02:00

1050 lines
24 KiB
Go

package manifest_test
import (
"os"
"path/filepath"
"testing"
"gitea.k3s.k0.nu/tools/photocli/internal/manifest"
)
func TestLoadJSONLEmptyDir(t *testing.T) {
m := manifest.LoadJSONL(t.TempDir())
if m == nil {
t.Fatal("expected non-nil manifest")
}
}
func TestLoadJSONLNonexistentDir(t *testing.T) {
m := manifest.LoadJSONL(filepath.Join(t.TempDir(), "no-such-dir"))
if m == nil {
t.Fatal("expected non-nil manifest even for nonexistent dir")
}
}
func TestLoadJSONLExistingFile(t *testing.T) {
dir := t.TempDir()
path := manifest.JSONLPath(dir)
if err := os.WriteFile(path, []byte(`{"id":"abc","filename":"a.jpg","size":100,"cloud":"gcs","exported":1234}`+"\n"), 0644); err != nil {
t.Fatal(err)
}
m := manifest.LoadJSONL(dir)
if !m.Has("abc") {
t.Fatal("expected to find entry with id abc")
}
}
func TestJSONLAddAndHas(t *testing.T) {
m := manifest.LoadJSONL(t.TempDir())
if m.Has("x") {
t.Fatal("expected Has to return false for unknown id")
}
m.Add("x", "photo.jpg", 42, "s3")
if !m.Has("x") {
t.Fatal("expected Has to return true after Add")
}
if m.Has("y") {
t.Fatal("expected Has to return false for y")
}
}
func TestJSONLSaveAndReload(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("id1", "file1.jpg", 10, "aws")
m.Add("id2", "file2.jpg", 20, "gcs")
if err := m.Save(); err != nil {
t.Fatal(err)
}
m.Close()
m2 := manifest.LoadJSONL(dir)
if !m2.Has("id1") {
t.Fatal("expected id1 after reload")
}
if !m2.Has("id2") {
t.Fatal("expected id2 after reload")
}
}
func TestJSONLOpenAppendCreatesDirs(t *testing.T) {
dir := t.TempDir()
subdir := filepath.Join(dir, "a", "b")
m := manifest.LoadJSONL(subdir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Close()
if _, err := os.Stat(filepath.Dir(manifest.JSONLPath(subdir))); err != nil {
t.Fatalf("expected dirs to be created: %v", err)
}
}
func TestJSONLCloseIdempotent(t *testing.T) {
m := manifest.LoadJSONL(t.TempDir())
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Close()
m.Close()
}
func TestJSONLOpenAppendIdempotent(t *testing.T) {
m := manifest.LoadJSONL(t.TempDir())
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatalf("expected second OpenAppend to succeed: %v", err)
}
m.Close()
}
func TestJSONLEntries(t *testing.T) {
m := manifest.LoadJSONL(t.TempDir())
m.Add("e1", "f1.jpg", 1, "c1")
m.Add("e2", "f2.jpg", 2, "c2")
entries := m.Entries()
if len(entries) != 2 {
t.Fatalf("expected 2 entries, got %d", len(entries))
}
if _, ok := entries["e1"]; !ok {
t.Fatal("missing e1")
}
if _, ok := entries["e2"]; !ok {
t.Fatal("missing e2")
}
}
func TestLoadSQLiteEmptyDir(t *testing.T) {
m, err := manifest.LoadSQLite(t.TempDir())
if err != nil {
t.Fatal(err)
}
if m == nil {
t.Fatal("expected non-nil manifest")
}
m.Close()
}
func TestLoadSQLiteNonexistentDir(t *testing.T) {
m, err := manifest.LoadSQLite(filepath.Join(t.TempDir(), "no-such-dir"))
if err != nil {
t.Fatal(err)
}
if m == nil {
t.Fatal("expected non-nil manifest even for nonexistent dir")
}
m.Close()
}
func TestSQLiteAddHasSaveClose(t *testing.T) {
m, err := manifest.LoadSQLite(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("sid1", "sfile.jpg", 99, "azure")
if !m.Has("sid1") {
t.Fatal("expected Has to return true after Add")
}
if m.Has("nope") {
t.Fatal("expected Has to return false for unknown id")
}
if err := m.Save(); err != nil {
t.Fatal(err)
}
m.Close()
}
func TestSQLiteRoundTrip(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("rid1", "rfile1.jpg", 10, "aws")
m.Add("rid2", "rfile2.jpg", 20, "gcs")
if err := m.Save(); err != nil {
t.Fatal(err)
}
m.Close()
m2, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m2.OpenAppend(); err != nil {
t.Fatal(err)
}
defer m2.Close()
if !m2.Has("rid1") {
t.Fatal("expected rid1 after reload")
}
if !m2.Has("rid2") {
t.Fatal("expected rid2 after reload")
}
}
func TestSQLiteEntries(t *testing.T) {
m, err := manifest.LoadSQLite(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
defer m.Close()
m.Add("se1", "sf1.jpg", 1, "sc1")
m.Add("se2", "sf2.jpg", 2, "sc2")
entries := m.Entries()
if len(entries) != 2 {
t.Fatalf("expected 2 entries, got %d", len(entries))
}
if _, ok := entries["se1"]; !ok {
t.Fatal("missing se1")
}
if _, ok := entries["se2"]; !ok {
t.Fatal("missing se2")
}
}
func TestSQLiteCloseIdempotent(t *testing.T) {
m, err := manifest.LoadSQLite(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Close()
m.Close()
}
func TestSQLiteOpenAppendIdempotent(t *testing.T) {
m, err := manifest.LoadSQLite(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatalf("expected second OpenAppend to succeed: %v", err)
}
m.Close()
}
func TestOpenJSONLNoFileExists(t *testing.T) {
m, err := manifest.Open(t.TempDir(), manifest.FormatJSONL)
if err != nil {
t.Fatal(err)
}
m.Close()
}
func TestOpenSQLiteNoFileExists(t *testing.T) {
m, err := manifest.Open(t.TempDir(), manifest.FormatSQLite)
if err != nil {
t.Fatal(err)
}
m.Close()
}
func TestOpenJSONLConvertsFromSQLite(t *testing.T) {
dir := t.TempDir()
sm, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := sm.OpenAppend(); err != nil {
t.Fatal(err)
}
sm.Add("conv1", "conv1.jpg", 5, "aws")
sm.Close()
m, err := manifest.Open(dir, manifest.FormatJSONL)
if err != nil {
t.Fatal(err)
}
defer m.Close()
if !m.Has("conv1") {
t.Fatal("expected converted entry conv1 to exist")
}
if _, err := os.Stat(manifest.SQLitePath(dir)); err == nil {
t.Fatal("expected sqlite file to be removed after conversion")
}
}
func TestOpenSQLiteConvertsFromJSONL(t *testing.T) {
dir := t.TempDir()
jm := manifest.LoadJSONL(dir)
if err := jm.OpenAppend(); err != nil {
t.Fatal(err)
}
jm.Add("jconv1", "jconv1.jpg", 7, "gcs")
jm.Save()
jm.Close()
m, err := manifest.Open(dir, manifest.FormatSQLite)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
defer m.Close()
if !m.Has("jconv1") {
t.Fatal("expected converted entry jconv1 to exist")
}
if _, err := os.Stat(manifest.JSONLPath(dir)); err == nil {
t.Fatal("expected jsonl file to be removed after conversion")
}
}
func TestOpenBothFormatsPrefersRequested(t *testing.T) {
dir := t.TempDir()
jm := manifest.LoadJSONL(dir)
if err := jm.OpenAppend(); err != nil {
t.Fatal(err)
}
jm.Add("both1", "both1.jpg", 1, "aws")
jm.Save()
jm.Close()
sm, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := sm.OpenAppend(); err != nil {
t.Fatal(err)
}
sm.Add("both2", "both2.jpg", 2, "gcs")
sm.Close()
m, err := manifest.Open(dir, manifest.FormatJSONL)
if err != nil {
t.Fatal(err)
}
m.Close()
if _, err := os.Stat(manifest.JSONLPath(dir)); err != nil {
t.Fatal("expected jsonl file to exist after Open with FormatJSONL")
}
jm2 := manifest.LoadJSONL(dir)
if err := jm2.OpenAppend(); err != nil {
t.Fatal(err)
}
jm2.Add("both1", "both1.jpg", 1, "aws")
jm2.Save()
jm2.Close()
sm2, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := sm2.OpenAppend(); err != nil {
t.Fatal(err)
}
sm2.Add("both2", "both2.jpg", 2, "gcs")
sm2.Close()
m2, err := manifest.Open(dir, manifest.FormatSQLite)
if err != nil {
t.Fatal(err)
}
m2.Close()
if _, err := os.Stat(manifest.SQLitePath(dir)); err != nil {
t.Fatal("expected sqlite file to exist after Open with FormatSQLite")
}
}
func TestParseFormatValid(t *testing.T) {
tests := []struct {
input string
want manifest.Format
}{
{"jsonl", manifest.FormatJSONL},
{"JSONL", manifest.FormatJSONL},
{"json", manifest.FormatJSONL},
{"JSON", manifest.FormatJSONL},
{"sqlite", manifest.FormatSQLite},
{"SQLITE", manifest.FormatSQLite},
{"db", manifest.FormatSQLite},
{"DB", manifest.FormatSQLite},
{"sqlite3", manifest.FormatSQLite},
{"SQLite3", manifest.FormatSQLite},
}
for _, tt := range tests {
got, err := manifest.ParseFormat(tt.input)
if err != nil {
t.Errorf("ParseFormat(%q): unexpected error: %v", tt.input, err)
continue
}
if got != tt.want {
t.Errorf("ParseFormat(%q) = %q, want %q", tt.input, got, tt.want)
}
}
}
func TestParseFormatInvalid(t *testing.T) {
_, err := manifest.ParseFormat("csv")
if err == nil {
t.Fatal("expected error for invalid format")
}
}
func TestOpenAppendReadOnlyPath(t *testing.T) {
dir := t.TempDir()
roDir := filepath.Join(dir, "readonly")
if err := os.MkdirAll(roDir, 0755); err != nil {
t.Fatal(err)
}
path := manifest.JSONLPath(roDir)
if err := os.WriteFile(path, []byte("{}\n"), 0444); err != nil {
t.Fatal(err)
}
m := manifest.LoadJSONL(roDir)
err := m.OpenAppend()
if err == nil {
t.Fatal("expected error opening read-only path")
}
m.Close()
}
func TestJSONLEntriesEmpty(t *testing.T) {
m := manifest.LoadJSONL(t.TempDir())
entries := m.Entries()
if len(entries) != 0 {
t.Fatalf("expected 0 entries, got %d", len(entries))
}
}
func TestSQLiteEntriesEmpty(t *testing.T) {
m, err := manifest.LoadSQLite(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
defer m.Close()
entries := m.Entries()
if len(entries) != 0 {
t.Fatalf("expected 0 entries, got %d", len(entries))
}
}
func TestOpenJSONLWithExistingJSONL(t *testing.T) {
dir := t.TempDir()
jm := manifest.LoadJSONL(dir)
if err := jm.OpenAppend(); err != nil {
t.Fatal(err)
}
jm.Add("exist1", "exist1.jpg", 10, "aws")
jm.Save()
jm.Close()
m, err := manifest.Open(dir, manifest.FormatJSONL)
if err != nil {
t.Fatal(err)
}
defer m.Close()
if !m.Has("exist1") {
t.Fatal("expected exist1 from existing jsonl")
}
}
func TestOpenSQLiteWithExistingSQLite(t *testing.T) {
dir := t.TempDir()
sm, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := sm.OpenAppend(); err != nil {
t.Fatal(err)
}
sm.Add("sexist1", "sexist1.jpg", 15, "azure")
sm.Close()
m, err := manifest.Open(dir, manifest.FormatSQLite)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
defer m.Close()
if !m.Has("sexist1") {
t.Fatal("expected sexist1 from existing sqlite")
}
}
func TestLoadJSONLWithEmptyLines(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "downloads.jsonl")
os.WriteFile(path, []byte("\n\n{\"id\":\"x1\",\"filename\":\"a.jpg\",\"size\":1024,\"cloud\":\"local\",\"exported\":100}\n\n"), 0644)
m := manifest.LoadJSONL(dir)
if !m.Has("x1") {
t.Error("should skip empty lines and parse valid JSON")
}
}
func TestLoadJSONLMalformedJSON(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "downloads.jsonl")
os.WriteFile(path, []byte("not-json\n{\"id\":\"x1\",\"filename\":\"a.jpg\",\"size\":1024,\"cloud\":\"local\",\"exported\":100}\n"), 0644)
m := manifest.LoadJSONL(dir)
if !m.Has("x1") {
t.Error("should skip malformed lines and parse valid ones")
}
}
func TestLoadJSONLEmptyID(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "downloads.jsonl")
os.WriteFile(path, []byte("{\"id\":\"\",\"filename\":\"a.jpg\",\"size\":1024,\"cloud\":\"local\",\"exported\":100}\n"), 0644)
m := manifest.LoadJSONL(dir)
if m.Has("") {
t.Error("should skip entries with empty ID")
}
}
func TestJSONLAddBeforeOpenAppend(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
m.Add("x1", "photo.jpg", 1024, "local")
if !m.Has("x1") {
t.Error("Add before OpenAppend should store in memory")
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Close()
data, err := os.ReadFile(filepath.Join(dir, "downloads.jsonl"))
if err != nil {
t.Fatal(err)
}
if len(data) > 0 {
t.Error("entries added before OpenAppend should not be in file")
}
}
func TestSQLiteHasBeforeOpenAppend(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if m.Has("x1") {
t.Error("Has on unopened sqlite should return false")
}
}
func TestSQLiteAddBeforeOpenAppend(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Close()
}
func TestSQLiteEntriesBeforeOpenAppend(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
entries := m.Entries()
if entries != nil {
t.Error("Entries on unopened sqlite should return nil")
}
}
func TestSQLiteOpenAppendReadOnlyPath(t *testing.T) {
m, err := manifest.LoadSQLite("/proc/cannot-create-dir-here")
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err == nil {
t.Error("expected error from OpenAppend on read-only path")
}
}
func TestFileExistsOnDirectory(t *testing.T) {
dir := t.TempDir()
if manifest.FileExists(dir) {
t.Error("manifest.FileExists should return false for directories")
}
}
func TestConvertFromJSONLOpenAppendError(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
os.Chmod(filepath.Join(dir, "downloads.jsonl"), 0444)
defer os.Chmod(filepath.Join(dir, "downloads.jsonl"), 0644)
_, err := manifest.ConvertFromJSONL(dir)
if err == nil {
t.Error("expected error when JSONL cannot be opened for reading during conversion")
}
}
func TestConvertFromSQLiteReadError(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
result, err := manifest.ConvertFromSQLite(dir)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
result.Close()
if _, err := os.Stat(manifest.JSONLPath(dir)); err != nil {
t.Errorf("JSONL file should exist after conversion: %v", err)
}
if os.Remove(manifest.SQLitePath(dir)) != nil {
t.Logf("sqlite file removed as expected")
}
}
func TestJSONLSaveWithoutFile(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.Save(); err != nil {
t.Errorf("Save without file should return nil, got %v", err)
}
}
func TestJSONLOpenAppendTwice(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Error("second OpenAppend should return nil, got", err)
}
m.Close()
}
func TestSQLiteHasWithoutOpen(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if m.Has("anything") {
t.Error("Has on unopened SQLite should return false")
}
}
func TestSQLiteAddWithoutOpen(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
if m.Has("x1") {
t.Error("Add without OpenAppend should not persist")
}
}
func TestSQLiteEntriesWithoutOpen(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
entries := m.Entries()
if entries != nil {
t.Errorf("Entries without open should return nil, got %v", entries)
}
}
func TestSQLiteCloseWithoutOpen(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
m.Close()
}
func TestSQLiteOpenAppendCreateDir(t *testing.T) {
dir := t.TempDir()
subdir := filepath.Join(dir, "subdir")
m, err := manifest.LoadSQLite(subdir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Errorf("OpenAppend should create dir, got %v", err)
}
m.Close()
}
func TestSQLiteSave(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
if err := m.Save(); err != nil {
t.Errorf("SQLite Save should return nil, got %v", err)
}
m.Close()
}
func TestOpenDefaultSQLite(t *testing.T) {
dir := t.TempDir()
m, err := manifest.Open(dir, manifest.FormatSQLite)
if err != nil {
t.Fatal(err)
}
m.Close()
}
func TestOpenDefaultJSONLNoFile(t *testing.T) {
dir := t.TempDir()
m, err := manifest.Open(dir, manifest.FormatJSONL)
if err != nil {
t.Fatal(err)
}
m.Close()
}
func TestParseFormat(t *testing.T) {
tests := []struct {
input string
want manifest.Format
err bool
}{
{"jsonl", manifest.FormatJSONL, false},
{"json", manifest.FormatJSONL, false},
{"sqlite", manifest.FormatSQLite, false},
{"db", manifest.FormatSQLite, false},
{"sqlite3", manifest.FormatSQLite, false},
{"invalid", "", true},
}
for _, tt := range tests {
got, err := manifest.ParseFormat(tt.input)
if tt.err && err == nil {
t.Errorf("ParseFormat(%q) expected error", tt.input)
}
if !tt.err && got != tt.want {
t.Errorf("ParseFormat(%q) = %v, want %v", tt.input, got, tt.want)
}
}
}
func TestJSONLSaveWithFileSync(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
if err := m.Save(); err != nil {
t.Errorf("Save with open file should succeed, got %v", err)
}
m.Close()
}
func TestConvertFromJSONLSuccess(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("c1", "photo.jpg", 1024, "cloud")
m.Close()
result, err := manifest.ConvertFromJSONL(dir)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if !result.Has("c1") {
t.Error("converted SQLite manifest should have c1")
}
result.Close()
if manifest.FileExists(manifest.JSONLPath(dir)) {
t.Error("JSONL file should be deleted after conversion")
}
}
func TestConvertFromJSONLSQLiteOpenError(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
subdir := filepath.Join(dir, "readonly")
if err := os.MkdirAll(subdir, 0755); err != nil {
t.Fatal(err)
}
srcPath := manifest.JSONLPath(dir)
dstPath := filepath.Join(subdir, "downloads.jsonl")
data, err := os.ReadFile(srcPath)
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(dstPath, data, 0644); err != nil {
t.Fatal(err)
}
}
func TestJSONLOpenAppendMkdirError(t *testing.T) {
dir := t.TempDir()
jsonlFile := filepath.Join(dir, "downloads.jsonl")
if err := os.WriteFile(jsonlFile, []byte("{}\n"), 0644); err != nil {
t.Fatal(err)
}
m := manifest.LoadJSONL(dir)
m.Close()
}
func TestSQLiteOpenAppendMkdirError(t *testing.T) {
m, err := manifest.LoadSQLite("/proc/cannot-write")
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err == nil {
t.Error("expected error creating dir under /proc")
m.Close()
}
}
func TestSQLiteHasAfterClose(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
if m.Has("x1") {
t.Error("Has should return false after Close")
}
}
func TestSQLiteEntriesAfterClose(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
entries := m.Entries()
if entries != nil {
t.Errorf("Entries after Close should return nil, got %d entries", len(entries))
}
}
func TestConvertFromJSONLNoFile(t *testing.T) {
dir := t.TempDir()
result, err := manifest.ConvertFromJSONL(dir)
if err != nil {
t.Fatalf("ConvertFromJSONL with no existing file should work: %v", err)
}
result.Close()
}
func TestConvertFromSQLiteNoFile(t *testing.T) {
dir := t.TempDir()
result, err := manifest.ConvertFromSQLite(dir)
if err != nil {
t.Fatalf("ConvertFromSQLite with no existing file should work: %v", err)
}
result.Close()
if _, err := os.Stat(manifest.JSONLPath(dir)); err != nil {
t.Errorf("JSONL file should exist after conversion: %v", err)
}
}
func TestConvertFromJSONLCloseSrcError(t *testing.T) {
}
func TestConvertFromSQLiteSaveError(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
jsonlPath := manifest.JSONLPath(dir)
os.WriteFile(jsonlPath, []byte(""), 0444)
defer os.Chmod(jsonlPath, 0644)
_, err = manifest.ConvertFromSQLite(dir)
if err == nil {
t.Error("expected error from dst.Save during ConvertFromSQLite")
}
}
func TestOpenExistingJSONL(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Save()
m.Close()
m2, err := manifest.Open(dir, manifest.FormatJSONL)
if err != nil {
t.Fatal(err)
}
if !m2.Has("x1") {
t.Error("should have x1 after reopening")
}
m2.Close()
}
func TestOpenExistingSQLite(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
m2, err := manifest.Open(dir, manifest.FormatSQLite)
if err != nil {
t.Fatal(err)
}
if err := m2.OpenAppend(); err != nil {
t.Fatal(err)
}
if !m2.Has("x1") {
t.Error("should have x1 after reopening")
}
m2.Close()
}
func TestOpenConvertJSONLToSQLite(t *testing.T) {
dir := t.TempDir()
m := manifest.LoadJSONL(dir)
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
m2, err := manifest.Open(dir, manifest.FormatSQLite)
if err != nil {
t.Fatal(err)
}
if !m2.Has("x1") {
t.Error("should have x1 after conversion")
}
m2.Close()
if manifest.FileExists(manifest.JSONLPath(dir)) {
t.Error("JSONL file should be deleted after conversion")
}
}
func TestOpenConvertSQLiteToJSONL(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
m2, err := manifest.Open(dir, manifest.FormatJSONL)
if err != nil {
t.Fatal(err)
}
if !m2.Has("x1") {
t.Error("should have x1 after conversion")
}
m2.Close()
if manifest.FileExists(manifest.SQLitePath(dir)) {
t.Error("SQLite file should be deleted after conversion")
}
}
func TestSQLiteOpenAppendInvalidPath(t *testing.T) {
m, err := manifest.LoadSQLite("/dev/null/impossible/path")
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err == nil {
t.Error("expected error from OpenAppend with invalid path")
m.Close()
}
}
func TestConvertFromSQLiteJSONLOpenAppendError(t *testing.T) {
dir := t.TempDir()
m, err := manifest.LoadSQLite(dir)
if err != nil {
t.Fatal(err)
}
if err := m.OpenAppend(); err != nil {
t.Fatal(err)
}
m.Add("x1", "photo.jpg", 1024, "local")
m.Close()
jsonlPath := manifest.JSONLPath(dir)
os.WriteFile(jsonlPath, []byte("{}\n"), 0444)
defer os.Chmod(jsonlPath, 0644)
_, err = manifest.ConvertFromSQLite(dir)
if err == nil {
t.Error("expected error from dst.OpenAppend during ConvertFromSQLite")
}
}
func TestJSONLOpenAppendMkdirAllError(t *testing.T) {
m := manifest.LoadJSONL("/dev/null/impossible/path/downloads.jsonl")
if err := m.OpenAppend(); err == nil {
t.Error("expected error from OpenAppend with impossible path")
m.Close()
}
}