summaryrefslogtreecommitdiff
path: root/internal/store
diff options
context:
space:
mode:
Diffstat (limited to 'internal/store')
-rw-r--r--internal/store/store_test.go177
1 files changed, 177 insertions, 0 deletions
diff --git a/internal/store/store_test.go b/internal/store/store_test.go
index 9670a01..47d4692 100644
--- a/internal/store/store_test.go
+++ b/internal/store/store_test.go
@@ -745,3 +745,180 @@ func TestCommitIndexSkipsExisting(t *testing.T) {
t.Errorf("index file was overwritten: got %q; want %q", got, sentinel)
}
}
+
+// --- TestSearchActionPathExport ----------------------------------------------
+
+// TestSearchActionPathExport verifies that ActionPathExport preserves the full
+// description path (not just the basename) when writing to the export dir.
+func TestSearchActionPathExport(t *testing.T) {
+ ctx, store, cfg, _, _ := testSetup(t)
+ initGitRepo(t, cfg.DataDir)
+
+ wantContent := "path export content\n"
+ if err := store.Add(ctx, "docs/subdir/report.txt", wantContent); err != nil {
+ t.Fatalf("Add: %v", err)
+ }
+
+ results, err := store.Search(ctx, "report.txt", ActionPathExport, nil)
+ if err != nil {
+ t.Fatalf("Search ActionPathExport: %v", err)
+ }
+ if len(results) != 1 {
+ t.Fatalf("expected 1 result; got %d", len(results))
+ }
+
+ // ActionPathExport uses the full description as the export path.
+ exportedPath := filepath.Join(cfg.ExportDir, "docs/subdir/report.txt")
+ got, err := os.ReadFile(exportedPath)
+ if err != nil {
+ t.Fatalf("reading exported file at full path: %v", err)
+ }
+ if string(got) != wantContent {
+ t.Errorf("exported content = %q; want %q", got, wantContent)
+ }
+}
+
+// --- TestSearchActionWithCallback --------------------------------------------
+
+// TestSearchActionWithCallback verifies that Search passes the correct Index and
+// Data to the actionFn for actions that delegate to the caller (ActionPaste etc.).
+func TestSearchActionWithCallback(t *testing.T) {
+ ctx, store, cfg, _, _ := testSetup(t)
+ initGitRepo(t, cfg.DataDir)
+
+ wantContent := "callback content\n"
+ if err := store.Add(ctx, "cb/entry.txt", wantContent); err != nil {
+ t.Fatalf("Add: %v", err)
+ }
+
+ var gotDesc string
+ var gotContent string
+ actionFn := func(_ context.Context, idx *Index, d *Data) error {
+ gotDesc = idx.Description
+ gotContent = string(d.Content)
+ return nil
+ }
+
+ // ActionPaste falls through to the default/actionFn branch of applyAction.
+ results, err := store.Search(ctx, "cb/entry.txt", ActionPaste, actionFn)
+ if err != nil {
+ t.Fatalf("Search with callback: %v", err)
+ }
+ if len(results) != 1 {
+ t.Fatalf("expected 1 result; got %d", len(results))
+ }
+ if gotDesc != "cb/entry.txt" {
+ t.Errorf("callback got description %q; want %q", gotDesc, "cb/entry.txt")
+ }
+ if gotContent != wantContent {
+ t.Errorf("callback got content %q; want %q", gotContent, wantContent)
+ }
+}
+
+// --- TestSearchActionNilCallback ---------------------------------------------
+
+// TestSearchActionNilCallback confirms that passing a nil actionFn for a
+// callback-delegated action (ActionPaste) is handled gracefully without panic.
+func TestSearchActionNilCallback(t *testing.T) {
+ ctx, store, cfg, _, _ := testSetup(t)
+ initGitRepo(t, cfg.DataDir)
+
+ if err := store.Add(ctx, "nil/cb.txt", "data"); err != nil {
+ t.Fatalf("Add: %v", err)
+ }
+
+ // nil actionFn: applyAction must return nil without calling anything.
+ _, err := store.Search(ctx, "nil/cb.txt", ActionPaste, nil)
+ if err != nil {
+ t.Fatalf("Search with nil callback: %v", err)
+ }
+}
+
+// --- TestFzfEmpty ------------------------------------------------------------
+
+// TestFzfEmpty calls Fzf on an empty store and confirms it returns ("", nil)
+// without attempting to launch fzf.
+func TestFzfEmpty(t *testing.T) {
+ ctx, store, _, _, _ := testSetup(t)
+ // No entries added — Fzf must return immediately.
+ result, err := store.Fzf(ctx)
+ if err != nil {
+ t.Fatalf("Fzf on empty store: %v", err)
+ }
+ if result != "" {
+ t.Errorf("Fzf on empty store = %q; want empty string", result)
+ }
+}
+
+// --- TestRemoveInteractiveInvalidThenDecline ---------------------------------
+
+// TestRemoveInteractiveInvalidThenDecline exercises the retry loop in
+// confirmAndRemove: an unrecognised answer causes a re-prompt; "n" then exits.
+func TestRemoveInteractiveInvalidThenDecline(t *testing.T) {
+ ctx, store, cfg, _, g := testSetup(t)
+ initGitRepo(t, cfg.DataDir)
+
+ if err := store.Add(ctx, "retry/entry", "data"); err != nil {
+ t.Fatalf("Add: %v", err)
+ }
+ if err := g.Commit(ctx); err != nil {
+ t.Fatalf("Commit: %v", err)
+ }
+
+ // "maybe\n" is not "y" or "n" → retry; "n\n" then declines.
+ input := strings.NewReader("maybe\nn\n")
+ if err := store.Remove(ctx, "retry/entry", input); err != nil {
+ t.Fatalf("Remove: %v", err)
+ }
+
+ // Entry must still be present because deletion was declined.
+ count := 0
+ if err := store.WalkIndexes(ctx, "", func(*Index) error { count++; return nil }); err != nil {
+ t.Fatalf("WalkIndexes: %v", err)
+ }
+ if count != 1 {
+ t.Errorf("expected 1 entry after decline; got %d", count)
+ }
+}
+
+// --- TestImportForceOverwrite ------------------------------------------------
+
+// TestImportForceOverwrite confirms that force=true overwrites an existing entry
+// while force=false (the default) skips it silently.
+func TestImportForceOverwrite(t *testing.T) {
+ ctx, store, cfg, c, _ := testSetup(t)
+ initGitRepo(t, cfg.DataDir)
+
+ srcDir := t.TempDir()
+ src := filepath.Join(srcDir, "f.txt")
+ if err := os.WriteFile(src, []byte("original\n"), 0o600); err != nil {
+ t.Fatalf("write src: %v", err)
+ }
+
+ // First import.
+ if err := store.Import(ctx, src, "force/f.txt", false); err != nil {
+ t.Fatalf("first Import: %v", err)
+ }
+
+ // Overwrite source with new content.
+ if err := os.WriteFile(src, []byte("updated\n"), 0o600); err != nil {
+ t.Fatalf("write updated src: %v", err)
+ }
+
+ // Second import with force=true must overwrite.
+ if err := store.Import(ctx, src, "force/f.txt", true); err != nil {
+ t.Fatalf("second Import (force): %v", err)
+ }
+
+ var idx *Index
+ if err := store.WalkIndexes(ctx, "", func(i *Index) error { idx = i; return nil }); err != nil {
+ t.Fatalf("WalkIndexes: %v", err)
+ }
+ d, err := loadData(ctx, filepath.Join(cfg.DataDir, idx.DataFile), c)
+ if err != nil {
+ t.Fatalf("loadData: %v", err)
+ }
+ if string(d.Content) != "updated\n" {
+ t.Errorf("content after force import = %q; want %q", d.Content, "updated\n")
+ }
+}