Repository: rsteube/carapace
Pull request #820 (2023-07-15 13:00:42)

added cache test


Patch:
diff --git a/context.go b/context.go
index f746d6e..601795d 100644
--- a/context.go
+++ b/context.go
@@ -7,7 +7,6 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/internal/env"
 	"github.com/rsteube/carapace/internal/shell/zsh"
 	"github.com/rsteube/carapace/pkg/util"
@@ -47,10 +46,7 @@ func NewContext(args ...string) Context {
 		context.Dir = wd
 	}
 
-	isGoRun := func() bool { return strings.HasPrefix(os.Args[0], os.TempDir()+"/go-build") }
-	if sandbox := env.Sandbox(); sandbox != "" && isGoRun() {
-		var m common.Mock
-		_ = json.Unmarshal([]byte(sandbox), &m)
+	if m, err := env.Sandbox(); err == nil {
 		context.Dir = m.Dir
 		context.mockedReplies = m.Replies
 	}
diff --git a/internal/cache/cache.go b/internal/cache/cache.go
index 388e116..a96b186 100644
--- a/internal/cache/cache.go
+++ b/internal/cache/cache.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/rsteube/carapace/internal/env"
 	"github.com/rsteube/carapace/internal/export"
 	"github.com/rsteube/carapace/internal/uid"
 	"github.com/rsteube/carapace/pkg/cache"
@@ -43,10 +44,17 @@ func Load(file string, timeout time.Duration) (e export.Export, err error) {
 // CacheDir creates a cache folder for current user and returns the path.
 func CacheDir(name string) (dir string, err error) {
 	var userCacheDir string
-	if userCacheDir, err = xdg.UserCacheDir(); err == nil {
-		dir = fmt.Sprintf("%v/carapace/%v/%v", userCacheDir, uid.Executable(), name)
-		err = os.MkdirAll(dir, 0700)
+	userCacheDir, err = xdg.UserCacheDir()
+	if err != nil {
+		return
 	}
+
+	if m, sandboxErr := env.Sandbox(); sandboxErr == nil {
+		userCacheDir = m.CacheDir
+	}
+
+	dir = fmt.Sprintf("%v/carapace/%v/%v", userCacheDir, uid.Executable(), name)
+	err = os.MkdirAll(dir, 0700)
 	return
 }
 
diff --git a/internal/common/mock.go b/internal/common/mock.go
index 8ef8dd9..295a430 100644
--- a/internal/common/mock.go
+++ b/internal/common/mock.go
@@ -1,6 +1,7 @@
 package common
 
 type Mock struct {
-	Dir     string
-	Replies map[string]string
+	Dir      string
+	CacheDir string
+	Replies  map[string]string
 }
diff --git a/internal/env/env.go b/internal/env/env.go
index cc22ff1..8973c73 100644
--- a/internal/env/env.go
+++ b/internal/env/env.go
@@ -1,6 +1,13 @@
 package env
 
-import "os"
+import (
+	"encoding/json"
+	"errors"
+	"os"
+	"strings"
+
+	"github.com/rsteube/carapace/internal/common"
+)
 
 func ColorDisabled() bool {
 	return os.Getenv("NO_COLOR") != "" || os.Getenv("CLICOLOR") == "0"
@@ -14,8 +21,14 @@ func Hashdirs() string {
 	return os.Getenv("CARAPACE_ZSH_HASH_DIRS")
 }
 
-func Sandbox() string {
-	return os.Getenv("CARAPACE_SANDBOX")
+func Sandbox() (m *common.Mock, err error) {
+	sandbox := os.Getenv("CARAPACE_SANDBOX")
+	if sandbox == "" || !isGoRun() {
+		return nil, errors.New("no sandbox")
+	}
+
+	err = json.Unmarshal([]byte(sandbox), &m)
+	return
 }
 
 func Log() bool {
@@ -29,3 +42,5 @@ func Hidden() bool {
 func CoverDir() string {
 	return os.Getenv("CARAPACE_COVERDIR") // custom env for GOCOVERDIR so that it works together with `-coverprofile`
 }
+
+func isGoRun() bool { return strings.HasPrefix(os.Args[0], os.TempDir()+"/go-build") }
diff --git a/pkg/sandbox/sandbox.go b/pkg/sandbox/sandbox.go
index 485af24..7372e3e 100644
--- a/pkg/sandbox/sandbox.go
+++ b/pkg/sandbox/sandbox.go
@@ -39,8 +39,9 @@ func newSandbox(t *testing.T, f func() *cobra.Command) Sandbox {
 		cmdF: f,
 		env:  make(map[string]string),
 		mock: &common.Mock{
-			Dir:     tempDir,
-			Replies: make(map[string]string),
+			Dir:      tempDir,
+			CacheDir: tempDir + "_CACHE",
+			Replies:  make(map[string]string),
 		},
 	}
 }
@@ -55,8 +56,15 @@ func (s *Sandbox) Env(key, value string) {
 }
 
 func (s *Sandbox) remove() {
-	if !s.keep && strings.HasPrefix(s.mock.Dir, os.TempDir()) {
+	if !s.keep && strings.HasPrefix(s.mock.Dir, os.TempDir()) && strings.HasPrefix(s.mock.CacheDir, os.TempDir()) {
 		os.RemoveAll(s.mock.Dir)
+		os.RemoveAll(s.mock.CacheDir)
+	}
+}
+
+func (s *Sandbox) ClearCache() {
+	if strings.HasPrefix(s.mock.CacheDir, os.TempDir()) {
+		os.RemoveAll(s.mock.CacheDir)
 	}
 }
 
@@ -126,20 +134,23 @@ func (s *Sandbox) NewContext(args ...string) carapace.Context {
 // Run executes the sandbox with given arguments.
 func (s *Sandbox) Run(args ...string) run {
 	m, _ := json.Marshal(args)
-	return run{
-		s.t,
-		string(m),
-		s.mock.Dir,
-		s.NewContext(args...),
-		carapace.ActionCallback(func(c carapace.Context) carapace.Action {
-			b, err := json.Marshal(s.mock)
-			if err != nil {
-				return carapace.ActionMessage(err.Error())
-			}
-			c.Setenv("CARAPACE_SANDBOX", string(b))
-			return carapace.ActionExecute(s.cmdF()).Invoke(c).ToA()
-		}),
+	r := run{
+		t:       s.t,
+		id:      string(m),
+		dir:     s.mock.Dir,
+		context: s.NewContext(args...),
 	}
+
+	r.actual = carapace.ActionCallback(func(c carapace.Context) carapace.Action {
+		b, err := json.Marshal(s.mock)
+		if err != nil {
+			return carapace.ActionMessage(err.Error())
+		}
+		c.Setenv("CARAPACE_SANDBOX", string(b))
+		return carapace.ActionExecute(s.cmdF()).Invoke(c).ToA()
+	}).Invoke(r.context).ToA()
+
+	return r
 }
 
 type run struct {
@@ -150,6 +161,7 @@ type run struct {
 	actual  carapace.Action
 }
 
+// TODO rename
 func (r run) invoke(a carapace.Action) string {
 	meta, rawValues := common.FromInvokedAction(a.Invoke(r.context))
 	rawValues = rawValues.FilterPrefix(r.context.Value)
@@ -174,6 +186,19 @@ func (r run) Expect(expected carapace.Action) {
 	})
 }
 
+func (r run) ExpectNot(unexpected carapace.Action) {
+	r.t.Run(r.id, func(t *testing.T) {
+		// t.Parallel() TODO prevent concurrent map write for this (storage.go)
+		if r.invoke(unexpected) == r.invoke(r.actual) {
+			t.Fatal("output should differ") // TODO yuck - print the action?
+		}
+	})
+}
+
+func (r run) Output() carapace.Action {
+	return r.actual
+}
+
 // Command executes the command generated by given function.
 func Command(t *testing.T, cmdF func() *cobra.Command) (f func(func(s *Sandbox))) {
 	return func(f func(s *Sandbox)) {


Test patch:
diff --git a/example/cmd/modifier_test.go b/example/cmd/modifier_test.go
index 1747b59..7dbf0f5 100644
--- a/example/cmd/modifier_test.go
+++ b/example/cmd/modifier_test.go
@@ -2,6 +2,7 @@ package cmd
 
 import (
 	"testing"
+	"time"
 
 	"github.com/rsteube/carapace"
 	"github.com/rsteube/carapace/pkg/sandbox"
@@ -21,6 +22,23 @@ func TestBatch(t *testing.T) {
 	})
 }
 
+func TestCache(t *testing.T) {
+	sandbox.Package(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) {
+		s.Keep()
+		cached := s.Run("modifier", "--cache", "").Output()
+		time.Sleep(1 * time.Second)
+		s.Run("modifier", "--cache", "").
+			Expect(cached.
+				Usage("Cache()"))
+
+		s.ClearCache()
+		s.Run("modifier", "--cache", "").
+			ExpectNot(cached.
+				Usage("Cache()"))
+
+	})
+}
+
 func TestFilter(t *testing.T) {
 	sandbox.Package(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) {
 		s.Run("modifier", "--filter", "").