summaryrefslogtreecommitdiff
path: root/internal/store/index_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-22 16:52:37 +0200
committerPaul Buetow <paul@buetow.org>2026-02-22 16:52:37 +0200
commitbcb07f5587c310063b74d280f7e82aa47a132c39 (patch)
tree15ec499cf9acdde3b3876f3fd1cf9316a602cf6d /internal/store/index_test.go
parentbb5ce162f82417191b80c04f69193d1a8af6b3d8 (diff)
Address store package review findings (task 352/store)
Fix CommitIndex to respect force=false by checking os.Stat before writing, mirroring the Data.Commit behaviour and keeping index/data pairs consistent. Skip .git directory in WalkIndexes via filepath.SkipDir to avoid spurious errors or false matches inside the git metadata tree. Make ShredAllExported continue past individual shred errors and return the last error, matching Ruby's best-effort shredding behaviour. Accept io.Reader in Store.Remove instead of hardwiring os.Stdin, enabling deterministic testing via strings.NewReader injection. Fix runFzf comment to state that any non-zero fzf exit is treated as no selection (not only exit 130). Document ImportRecursive divergence from Ruby basename-flattening behaviour. Add 14 new tests: Search, SearchActionCat, SearchActionCatBinarySkip, ShredAllExported, SearchActionExport, ImportRecursive, ReimportAfterExport, RemoveInteractive, RemoveInteractiveDecline, CommitIndexSkipsExisting, LoadIndexMissingFile, LoadIndexCorrupted, LoadDataMissingFile, LoadDataCorrupted, DataExportUnwritable, HashPathEdgeCases, ImportMissingSourceFile, WalkIndexesInvalidRegex. Improve TestIndexSort to call sort.Sort and assert final order. Remove orphaned section-header comment from store_test.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/store/index_test.go')
-rw-r--r--internal/store/index_test.go80
1 files changed, 71 insertions, 9 deletions
diff --git a/internal/store/index_test.go b/internal/store/index_test.go
index 6bf2cef..a16d757 100644
--- a/internal/store/index_test.go
+++ b/internal/store/index_test.go
@@ -2,10 +2,30 @@
package store
import (
+ "context"
+ "os"
+ "path/filepath"
+ "sort"
"strings"
"testing"
+
+ "codeberg.org/snonux/geheim/internal/crypto"
)
+// newTestIndexCipher is a local helper to avoid import cycle via store_test.go.
+func newTestIndexCipher(t *testing.T) *crypto.Cipher {
+ t.Helper()
+ keyFile := filepath.Join(t.TempDir(), "key")
+ if err := os.WriteFile(keyFile, []byte("testkey1234567890"), 0o600); err != nil {
+ t.Fatalf("writing key file: %v", err)
+ }
+ c, err := crypto.NewCipher(keyFile, 32, "testpin", "Hello world")
+ if err != nil {
+ t.Fatalf("NewCipher: %v", err)
+ }
+ return c
+}
+
// --- TestIsBinary ------------------------------------------------------------
// TestIsBinary verifies that IsBinary returns the correct value for every case
@@ -82,9 +102,44 @@ func TestIndexString(t *testing.T) {
})
}
+// --- TestLoadIndexMissingFile ------------------------------------------------
+
+// TestLoadIndexMissingFile confirms that loadIndex returns an error when the
+// .index file does not exist on disk.
+func TestLoadIndexMissingFile(t *testing.T) {
+ ctx := context.Background()
+ c := newTestIndexCipher(t)
+
+ _, err := loadIndex(ctx, "/nonexistent/path/to.index", t.TempDir(), c)
+ if err == nil {
+ t.Error("loadIndex with missing file: expected error, got nil")
+ }
+}
+
+// --- TestLoadIndexCorrupted --------------------------------------------------
+
+// TestLoadIndexCorrupted confirms that loadIndex returns an error when the file
+// contains data that cannot be decrypted (not valid ciphertext).
+func TestLoadIndexCorrupted(t *testing.T) {
+ ctx := context.Background()
+ c := newTestIndexCipher(t)
+
+ dir := t.TempDir()
+ badPath := filepath.Join(dir, "bad.index")
+ if err := os.WriteFile(badPath, []byte("not valid ciphertext"), 0o600); err != nil {
+ t.Fatalf("writing bad file: %v", err)
+ }
+
+ _, err := loadIndex(ctx, badPath, dir, c)
+ if err == nil {
+ t.Error("loadIndex with corrupted file: expected error, got nil")
+ }
+}
+
// --- TestIndexSort -----------------------------------------------------------
-// TestIndexSort verifies that IndexSlice sorts by Description alphabetically.
+// TestIndexSort verifies that IndexSlice sorts by Description alphabetically
+// using sort.Sort, and validates the sort.Interface helper methods directly.
func TestIndexSort(t *testing.T) {
hash := strings.Repeat("0", 64)
indexes := IndexSlice{
@@ -93,21 +148,28 @@ func TestIndexSort(t *testing.T) {
{Description: "mango", Hash: hash},
}
- // Use sort package via the interface methods directly.
- n := indexes.Len()
- if n != 3 {
+ if n := indexes.Len(); n != 3 {
t.Fatalf("Len() = %d; want 3", n)
}
- // apple < mango should hold.
- appleIdx, mangoIdx := 1, 2 // after original order: zebra=0, apple=1, mango=2
- if !indexes.Less(appleIdx, mangoIdx) {
+ // Before sorting: zebra=0, apple=1, mango=2 — Less(1,2) = apple < mango = true.
+ if !indexes.Less(1, 2) {
t.Errorf("Less(apple, mango) = false; want true")
}
-
- // Swap zebra and apple.
+ // Swap and verify.
indexes.Swap(0, 1)
if indexes[0].Description != "apple" || indexes[1].Description != "zebra" {
t.Errorf("Swap(0,1) did not exchange elements")
}
+ // Restore original order before sort.Sort.
+ indexes.Swap(0, 1)
+
+ // Verify sort.Sort produces ascending alphabetical order.
+ sort.Sort(indexes)
+ want := []string{"apple", "mango", "zebra"}
+ for i, w := range want {
+ if indexes[i].Description != w {
+ t.Errorf("indexes[%d].Description = %q; want %q", i, indexes[i].Description, w)
+ }
+ }
}