diff options
| author | ewy <ewy0@protonmail.com> | 2026-05-17 01:37:24 +0200 |
|---|---|---|
| committer | ewy <ewy0@protonmail.com> | 2026-05-17 01:37:24 +0200 |
| commit | f5807d9f3a6c96e70912b61fac17120f412b5782 (patch) | |
| tree | d6928795e06b1af000ffba2ae50bb6f8f7b72685 /cache | |
| parent | 7984fd9beaa7c903288142818cb328c584a139a5 (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.go | 43 | ||||
| -rw-r--r-- | cache/cache_test.go | 64 |
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()) +} |
