summaryrefslogtreecommitdiff
path: root/cache
diff options
context:
space:
mode:
authorewy <ewy0@protonmail.com>2026-05-17 01:37:24 +0200
committerewy <ewy0@protonmail.com>2026-05-17 01:37:24 +0200
commitf5807d9f3a6c96e70912b61fac17120f412b5782 (patch)
treed6928795e06b1af000ffba2ae50bb6f8f7b72685 /cache
parent7984fd9beaa7c903288142818cb328c584a139a5 (diff)
* integration tests with a pik target to run them
* add abstraction for paths to facilitate unit tests * flesh out completion (--install-completion) * do sync init before stateless modes so list knows more
Diffstat (limited to 'cache')
-rw-r--r--cache/cache.go43
-rw-r--r--cache/cache_test.go64
2 files changed, 80 insertions, 27 deletions
diff --git a/cache/cache.go b/cache/cache.go
index 9e6b1bc..2784e23 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -8,7 +8,6 @@ import (
"io"
"io/fs"
"os"
- "path"
"slices"
"strings"
)
@@ -19,30 +18,22 @@ type Cache struct {
type cacheInit struct{}
-// Path is the file path to the "contexts" cache file
-var Path string
-
-// FsPath is the Path with the leading slash removed, to be opened from fs.FS
-var FsPath string
-
var Init model.Initializer = &cacheInit{}
func (i *cacheInit) Init() error {
- Path = path.Join(paths.Cache, "contexts")
- FsPath = Path[1:]
return nil
}
// Merge combines two caches and filters duplicate keys
func (c *Cache) Merge(other *Cache) *Cache {
- if other == nil && c != nil {
+ switch {
+ case other == nil && c != nil:
return c
- }
- if c == nil && other != nil {
+ case c == nil && other != nil:
return other
- }
- if c == nil {
+ case c == nil:
return nil
+
}
mp := make(map[string]string)
for _, e := range append(c.Entries, other.Entries...) {
@@ -60,9 +51,9 @@ type Entry struct {
Label string
}
-var Empty = Cache{}
-
-var UnexpectedEntryError = errors.New("unexpected cache entry")
+func (e Entry) String() string {
+ return e.Path + " # " + e.Label
+}
// LoadFile creates a Cache from a file or an empty one if the file does not exist
// this handles opening a reader for Unmarshal
@@ -97,8 +88,6 @@ func Unmarshal(r io.Reader) (*Cache, error) {
fallthrough
case 1:
entry.Path = strings.TrimSpace(parts[0])
- default:
- return c, UnexpectedEntryError
}
c.Entries = append(c.Entries, *entry)
}
@@ -109,9 +98,7 @@ func Unmarshal(r io.Reader) (*Cache, error) {
func (c *Cache) Marshal() []byte {
b := strings.Builder{}
for _, e := range c.Entries {
- b.WriteString(e.Path)
- b.WriteString(" # ")
- b.WriteString(e.Label)
+ b.WriteString(e.String())
b.WriteString("\n")
}
return []byte(b.String())
@@ -131,21 +118,23 @@ func New(st *model.State) *Cache {
return c
}
-func Insert(in *model.State) error {
- f := os.DirFS("/")
- loaded, err := LoadFile(f, FsPath)
+func MergeAndSave(in *model.State) error {
+ root := "/"
+ f := os.DirFS(root)
+ // remove leading slash from the dirfs
+ loaded, err := LoadFile(f, strings.TrimPrefix(paths.ContextsFile.String(), "/"))
if err != nil {
return err
}
insert := New(in)
result := loaded.Merge(insert)
if loaded == nil {
- return SaveFile(Path, result)
+ return SaveFile(paths.ContextsFile.String(), result)
}
if slices.Equal(loaded.Entries, result.Entries) {
return nil
}
- return SaveFile(Path, result)
+ return SaveFile(paths.ContextsFile.String(), result)
}
// SaveFile helps you use Save with a file path instead of a reader
diff --git a/cache/cache_test.go b/cache/cache_test.go
index 8753ad6..d2792ca 100644
--- a/cache/cache_test.go
+++ b/cache/cache_test.go
@@ -3,6 +3,8 @@
package cache
import (
+ "github.com/ewy1/pik/paths"
+ "os"
"path/filepath"
"strings"
"testing"
@@ -204,3 +206,65 @@ func TestMergeNilNormal(t *testing.T) {
}
_ = e.Merge(c)
}
+
+func TestCacheInit_Init(t *testing.T) {
+ d := t.TempDir()
+ paths.SetAll(d)
+ c := &cacheInit{}
+ err := c.Init()
+ assert.NoError(t, err)
+ assert.Contains(t, paths.ContextsFile, d)
+}
+
+func TestInsert(t *testing.T) {
+ d := t.TempDir()
+ st := TState(TSource("source", "target"))
+ paths.SetAll(d)
+ defer paths.Reset()
+ err := MergeAndSave(st)
+ assert.NoError(t, err)
+}
+
+func TestInsertNonExistent(t *testing.T) {
+ st := TState(TSource("source", "target"))
+ paths.SetAll("/../")
+ err := MergeAndSave(st)
+ assert.Error(t, err)
+}
+
+func TestLoadState(t *testing.T) {
+ paths.SetAll("/pik")
+ defer paths.Reset()
+ c := &Cache{
+ Entries: []Entry{
+ {Path: "/asdf", Label: "hjkl"},
+ },
+ }
+ f := fstest.MapFS{
+ "/pik/contexts": &fstest.MapFile{
+ Data: []byte("asdf # hjkl"),
+ },
+ }
+ st, errs := LoadState(f, c, nil, nil)
+ for _, e := range errs {
+ assert.NoError(t, e)
+ }
+ assert.NotNil(t, st)
+}
+
+func TestSavesFile(t *testing.T) {
+ d := t.TempDir()
+ paths.Set(paths.ContextsFile, filepath.Join(d, "contexts"))
+ defer paths.Reset()
+ f, err := os.OpenRoot("/")
+ defer f.Close()
+ assert.NoError(t, err)
+ st := TState(TSource("source", "target1", "target2"))
+ c := New(st)
+ assert.NotNil(t, c)
+ err = MergeAndSave(st)
+ assert.NoError(t, err)
+ content, err := os.ReadFile(paths.ContextsFile.String())
+ assert.NoError(t, err)
+ assert.Contains(t, string(content), c.Entries[0].String())
+}