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 | |
| 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
29 files changed, 365 insertions, 104 deletions
diff --git a/.pik/integrations.sh b/.pik/integrations.sh new file mode 100644 index 0000000..4c1af78 --- /dev/null +++ b/.pik/integrations.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# build pik and set $PIK to the built version +go build -o pik . +PIK="$(realpath ./pik)" +export PIK + +cd integration_tests + +FAILED="" + +for dir in * +do + if [ -d "$dir" ] ; then + cd "$dir" + for file in *.test.sh + do + tmpdir=$(mktemp -d) + XDG_CACHE_HOME="$tmpdir" + XDG_CONFIG_HOME="$tmpdir" + export XDG_CACHE_HOME XDG_CONFIG_HOME + + if ! bash "$file" 1>/dev/null 2>&1 ; then + echo "$dir/$file $(tput setaf 1)failed$(tput sgr0)" 2>&1 + bash -x "$file" || true + FAILED=yes + else + echo "$dir/$file $(tput setaf 2)succeeded$(tput sgr0)" 2>&1 + rm -rf "$tmpdir" + fi + done + cd - > /dev/null + fi +done + +if [ -n "$FAILED" ] ; then + exit 1 +fi
\ No newline at end of file diff --git a/.pik/test.sh b/.pik/test.sh index bb91492..ac4945f 100644 --- a/.pik/test.sh +++ b/.pik/test.sh @@ -1,2 +1,4 @@ #!/usr/bin/env bash -go test -tags test -v ./...
\ No newline at end of file +set -euo pipefail +go test -tags test -v ./... +bash .pik/integrations.sh
\ No newline at end of file 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()) +} diff --git a/completion/completion.go b/completion/completion.go index 6aad9d1..f3d76d7 100644 --- a/completion/completion.go +++ b/completion/completion.go @@ -2,15 +2,61 @@ package completion import ( _ "embed" + "errors" + "fmt" + "github.com/ewy1/pik/paths" "github.com/ewy1/pik/spool" + "os" + "path/filepath" + "strings" ) //go:embed completion.sh var completionCode string +var completionFormat = ` +# %s +%s +` + +var completionComment = "\n# pik completion (installed by `pik --install-completion`)\n" + var completionCodeByShell = map[string]string{ - "bash": ". <(pik --completion)", - "zsh": `autoload -Uz compinit && compinit && source <(pik --completion)`, + "bash": ". <(pik --completion)\n\n", + "zsh": `autoload -Uz compinit && compinit && source <(pik --completion)\n\n`, +} + +var completionFileByShell = map[string]string{ + "bash": ".bashrc", + "zsh": ".zshrc", +} + +var AlreadyInstalledError = errors.New("completion already installed") + +func Add(shell string) error { + f := filepath.Join(paths.HomeDir.String(), completionFileByShell[shell]) + content, err := os.ReadFile(f) + if err != nil { + return err + } + if strings.Contains(string(content), strings.TrimSpace(completionCodeByShell[shell])) { + return AlreadyInstalledError + } + fd, err := os.OpenFile(f, os.O_APPEND|os.O_WRONLY, 0600) + defer fd.Close() + if err != nil { + return err + } + _, err = fd.Write([]byte(fmt.Sprintf(completionFormat, completionComment, completionCodeByShell[shell]))) + if err != nil { + return err + } + successMessage(shell, f) + return nil +} + +func successMessage(shell string, file string) { + _, _ = spool.Print("Installed completion for %s in %s\n", shell, file) } func Echo() error { diff --git a/completion/completion.sh b/completion/completion.sh index 36876cf..a48733f 100644 --- a/completion/completion.sh +++ b/completion/completion.sh @@ -1,9 +1,8 @@ -#/usr/bin/env bash _pik_completions() { QUERY="" for word in COMP_WORDS ; do - if [ ! query = "-"* ] ; then + if [[ ! query = "-"* ]] ; then QUERY="$QUERY $WORD" fi done diff --git a/flags/flags.go b/flags/flags.go index f349ce7..d8ac537 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -26,7 +26,8 @@ var ( List = pflag.BoolP("list", "l", false, "list available targets and exit") // Inline means pik does not go to the terminal alt screen // unused because it is accessed by `flags.Get("inline")` - Inline = pflag.BoolP("inline", "i", false, "if true, will force alt screen; if forced false, will disable alt screen") - Edit = pflag.Bool("edit", false, "edit the target in $EDITOR") - Completion = pflag.Bool("completion", false, "echo completion scrip and exit") + Inline = pflag.BoolP("inline", "i", false, "if true, will force alt screen; if forced false, will disable alt screen") + Edit = pflag.Bool("edit", false, "edit the target in $EDITOR") + Completion = pflag.Bool("completion", false, "echo completion scrip and exit") + InstallCompletion = pflag.Bool("install-completion", false, "install completion script to shell rc") ) diff --git a/integration_tests/defaults/.pik/defaults.sh b/integration_tests/defaults/.pik/defaults.sh new file mode 100644 index 0000000..6500c83 --- /dev/null +++ b/integration_tests/defaults/.pik/defaults.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# i have the same name as the source directory +echo "banana"
\ No newline at end of file diff --git a/integration_tests/defaults/.pik/dir/dir.sh b/integration_tests/defaults/.pik/dir/dir.sh new file mode 100644 index 0000000..8d6b69b --- /dev/null +++ b/integration_tests/defaults/.pik/dir/dir.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "apple"
\ No newline at end of file diff --git a/integration_tests/defaults/README.md b/integration_tests/defaults/README.md new file mode 100644 index 0000000..9aaf7eb --- /dev/null +++ b/integration_tests/defaults/README.md @@ -0,0 +1,2 @@ +these tests check whether pik's default targets (sharing a name with either subdirectory or source folder) are selected +by default.
\ No newline at end of file diff --git a/integration_tests/defaults/full.test.sh b/integration_tests/defaults/full.test.sh new file mode 100644 index 0000000..05d3ee4 --- /dev/null +++ b/integration_tests/defaults/full.test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +result="$($PIK defaults dir dir)" +if [[ ! "$result" == *"apple"* ]] ; then + echo "expected apple" >&2 + exit 1 +fi diff --git a/integration_tests/defaults/source.test.sh b/integration_tests/defaults/source.test.sh new file mode 100644 index 0000000..ee966f4 --- /dev/null +++ b/integration_tests/defaults/source.test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +result="$($PIK defaults)" +if [[ ! "$result" == *"banana"* ]] ; then + echo "expected banana" >&2 + exit 1 +fi
\ No newline at end of file diff --git a/integration_tests/defaults/source_full.test.sh b/integration_tests/defaults/source_full.test.sh new file mode 100644 index 0000000..91784c4 --- /dev/null +++ b/integration_tests/defaults/source_full.test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +result="$($PIK defaults defaults)" +if [[ ! "$result" == *"banana"* ]] ; then + echo "expected banana" >&2 + exit 1 +fi
\ No newline at end of file diff --git a/integration_tests/defaults/subdir.test.sh b/integration_tests/defaults/subdir.test.sh new file mode 100644 index 0000000..6edd874 --- /dev/null +++ b/integration_tests/defaults/subdir.test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +result="$($PIK dir)" +if [[ ! "$result" == *"apple"* ]] ; then + echo "expected apple" >&2 + exit 1 +fi diff --git a/integration_tests/defaults/subdir_with_source.test.sh b/integration_tests/defaults/subdir_with_source.test.sh new file mode 100644 index 0000000..3f41277 --- /dev/null +++ b/integration_tests/defaults/subdir_with_source.test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +result="$($PIK defaults dir)" +if [[ ! "$result" == *"apple"* ]] ; then + echo "expected apple" >&2 + exit 1 +fi diff --git a/integration_tests/simple/.pik/echo.sh b/integration_tests/simple/.pik/echo.sh new file mode 100644 index 0000000..c8a6153 --- /dev/null +++ b/integration_tests/simple/.pik/echo.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "$@"
\ No newline at end of file diff --git a/integration_tests/simple/.pik/result.sh b/integration_tests/simple/.pik/result.sh new file mode 100644 index 0000000..7a534a6 --- /dev/null +++ b/integration_tests/simple/.pik/result.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "banana"
\ No newline at end of file diff --git a/integration_tests/simple/README.md b/integration_tests/simple/README.md new file mode 100644 index 0000000..6925e22 --- /dev/null +++ b/integration_tests/simple/README.md @@ -0,0 +1 @@ +these tests try some simple pik usage
\ No newline at end of file diff --git a/integration_tests/simple/echo.test.sh b/integration_tests/simple/echo.test.sh new file mode 100644 index 0000000..917a76d --- /dev/null +++ b/integration_tests/simple/echo.test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +if [[ "$($PIK result)" != *"banana"* ]] ; then + echo "expected banana" 1>&2 + exit 1 +fi
\ No newline at end of file diff --git a/integration_tests/simple/echo_full.test.sh b/integration_tests/simple/echo_full.test.sh new file mode 100644 index 0000000..7290cd2 --- /dev/null +++ b/integration_tests/simple/echo_full.test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +if [[ "$($PIK simple result)" != *"banana"* ]] ; then + echo "expected banana" 1>&2 + exit 1 +fi
\ No newline at end of file diff --git a/integration_tests/simple/nonexistent_target.test.sh b/integration_tests/simple/nonexistent_target.test.sh new file mode 100644 index 0000000..4915e77 --- /dev/null +++ b/integration_tests/simple/nonexistent_target.test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +if [[ "$($PIK 123)" != "" ]] ; then + echo "expected no output" 1>&2 + exit 1 +fi
\ No newline at end of file diff --git a/integration_tests/simple/result.test.sh b/integration_tests/simple/result.test.sh new file mode 100644 index 0000000..3d4a2bc --- /dev/null +++ b/integration_tests/simple/result.test.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +if [[ "$($PIK echo asdf)" != *"asdf"* ]] ; then + echo "expected banana" 1>&2 + exit 1 +fi
\ No newline at end of file @@ -29,7 +29,7 @@ import ( // syncInitializers are ran before the initializers. // useful for initializing stuff like paths, preparing directories, and reading the environment var syncInitializers = ComponentList[model.Initializer]{ - paths.Paths, + paths.Component, cache.Init, } @@ -108,6 +108,10 @@ func mode[T any](list ModeMap[T], fire func(mode T) error) *int { func pik() int { pflag.Parse() + syncInitializers.RunSync(func(initializer model.Initializer) error { + return initializer.Init() + }) + code := mode(statelessModes, func(mode func() error) error { return mode() }) @@ -115,10 +119,6 @@ func pik() int { return *code } - syncInitializers.RunSync(func(initializer model.Initializer) error { - return initializer.Init() - }) - initializers.RunAsync(func(initializer model.Initializer) error { return initializer.Init() }) @@ -128,9 +128,9 @@ func pik() int { _, _ = spool.Warn("%v\n", err) return 1 } - locs := crawl.RichLocations(here) - last := locs[len(locs)-1] - root, err := os.OpenRoot(last) + locs := append(crawl.RichLocations(here), paths.System.String()) + root, err := os.OpenRoot("/") + defer root.Close() if root == nil { _, _ = spool.Warn("%v\n", err) return 1 @@ -150,14 +150,14 @@ func pik() int { if len(stateErrors) > 0 { return } - err := cache.Insert(st) + err := cache.MergeAndSave(st) if err != nil { - spool.Warn("%v\n", err) + _, _ = spool.Warn("%v\n", err) } }() } else { - c, err = cache.LoadFile(fs, cache.Path[1:]) + c, err = cache.LoadFile(fs, paths.ContextsFile.String()[1:]) if err != nil { _, _ = spool.Warn("%v\n", err) return 1 diff --git a/model/new.go b/model/new.go index 94b039e..e83c314 100644 --- a/model/new.go +++ b/model/new.go @@ -10,7 +10,7 @@ import ( "sync" ) -func NewState(f fs.FS, locations []string, indexers []Indexer, runners []Runner) (*State, []error) { +func NewState(rootFs fs.FS, locations []string, indexers []Indexer, runners []Runner) (*State, []error) { var errs []error st := &State{ All: *flags.All, @@ -32,16 +32,16 @@ func NewState(f fs.FS, locations []string, indexers []Indexer, runners []Runner) return } - myWg := sync.WaitGroup{} + locationWg := sync.WaitGroup{} var targets = make([][]Target, len(indexers), len(indexers)) for ti, indexer := range indexers { - myWg.Go(func() { - s, err := fs.Sub(f, loc) + locationWg.Go(func() { + subFs, err := fs.Sub(rootFs, loc) if err != nil && !errors.Is(err, fs.ErrNotExist) { errs = append(errs, err) return } - result, err := indexer.Index("/"+loc, s, runners) + result, err := indexer.Index("/"+loc, subFs, runners) if err != nil && !errors.Is(err, fs.ErrNotExist) { errs = append(errs, err) return @@ -49,7 +49,7 @@ func NewState(f fs.FS, locations []string, indexers []Indexer, runners []Runner) targets[ti] = result }) } - myWg.Wait() + locationWg.Wait() for _, t := range targets { if t == nil { @@ -9,6 +9,7 @@ import ( "github.com/ewy1/pik/run" "github.com/ewy1/pik/spool" "os" + "path/filepath" "runtime" "runtime/pprof" ) @@ -43,6 +44,8 @@ func (m ModeMap[T]) Traverse(then func(in T) error) error { var profileFd *os.File +var UnknownShellError = errors.New("$SHELL not set or empty") + // statelessModes are program modes which do not require state to operate. // like --version and --completion var statelessModes = ModeMap[func() error]{ @@ -50,6 +53,14 @@ var statelessModes = ModeMap[func() error]{ _, err := spool.Print("%s\n", version) return err }, + flags.InstallCompletion: func() error { + sh := os.Getenv("SHELL") + if sh == "" { + return UnknownShellError + } + _, sh = filepath.Split(sh) + return completion.Add(sh) + }, flags.Completion: func() error { return completion.Echo() }, @@ -68,15 +79,24 @@ var statelessModes = ModeMap[func() error]{ }, } +var NoTargetsError = errors.New("no targets or sources to list") + // statefulModes are program modes which require a built state to be executed var statefulModes = ModeMap[func(st *model.State) error]{ flags.List: func(st *model.State) error { + count := 0 for _, s := range st.Sources { + count++ _, _ = spool.Print("%v", s.Label()+paths.Ifs) for _, t := range s.Targets { _, _ = spool.Print("%v", t.ShortestId()+paths.Ifs) + count++ } } + + if count == 0 { + return NoTargetsError + } return nil }, } diff --git a/paths/path.go b/paths/path.go new file mode 100644 index 0000000..5706d29 --- /dev/null +++ b/paths/path.go @@ -0,0 +1,20 @@ +package paths + +type Path struct { + Val *string +} + +func (p *Path) Set(val string) { + p.Val = &val +} + +func (p *Path) String() string { + if p == nil || p.Val == nil { + return "<empty>" + } + return *p.Val +} + +func Empty() *Path { + return &Path{} +} diff --git a/paths/paths.go b/paths/paths.go index cc0c878..b714a23 100644 --- a/paths/paths.go +++ b/paths/paths.go @@ -3,23 +3,39 @@ package paths import ( "github.com/adrg/xdg" "os" + "path" "path/filepath" "strings" ) var ( - Ifs string - Config string - Cache string - This string - Home string + Ifs string + ConfigDir = Empty() + CacheDir = Empty() + ContextsFile = Empty() + HomeDir = Empty() + System = Empty() + This = "pik" ) +var Paths = []*Path{ + ConfigDir, + CacheDir, + ContextsFile, + HomeDir, + System, +} + +var DirectoriesToMake = []*Path{ + ConfigDir, + CacheDir, +} + type paths struct { Initialized bool } -var Paths = &paths{ +var Component = &paths{ Initialized: false, } @@ -31,20 +47,21 @@ func (p *paths) Init() error { xdg.Reload() } - Home = xdg.Home - This = "pik" - Cache = filepath.Join(xdg.CacheHome, This) - Config = filepath.Join(xdg.ConfigHome, This) + HomeDir.Set(xdg.Home) + CacheDir.Set(filepath.Join(xdg.CacheHome, This)) + ConfigDir.Set(filepath.Join(xdg.ConfigHome, This)) + ContextsFile.Set(path.Join(CacheDir.String(), "contexts")) + System.Set(path.Join(ConfigDir.String())) + Ifs = os.Getenv("IFS") - err := os.MkdirAll(Cache, 0700) - if err != nil { - return err - } - err = os.MkdirAll(Config, 0700) - if err != nil { - return err + for _, d := range DirectoriesToMake { + err := os.MkdirAll(d.String(), 0700) + if err != nil { + return err + } } + if Ifs == "" { Ifs = "\n" } @@ -53,5 +70,5 @@ func (p *paths) Init() error { } func ReplaceHome(input string) string { - return strings.Replace(input, Home, "~", 1) + return strings.Replace(input, HomeDir.String(), "~", 1) } diff --git a/paths/paths_test.go b/paths/paths_test.go index 8ab3461..1dd9034 100644 --- a/paths/paths_test.go +++ b/paths/paths_test.go @@ -4,42 +4,17 @@ package paths import ( "github.com/stretchr/testify/assert" + "strconv" "testing" ) -var bHome, bThis, bCache, bConfig string - -// Set temporarily sets the paths for unit test purposes -// remember to defer Reset -func Set(home, this, cache, config string) { - bHome = Home - bThis = This - bCache = Cache - bConfig = Config - - Home = home - This = this - Cache = cache - Config = config -} - -// Reset sets the path variables back to before the unit test -func Reset() { - Home = bHome - This = bThis - Cache = bCache - Config = bConfig -} - func TestSetAndReset(t *testing.T) { - Set("1", "2", "3", "4") - assert.Equal(t, Home, "1") - assert.Equal(t, This, "2") - assert.Equal(t, Cache, "3") - assert.Equal(t, Config, "4") - Reset() - assert.NotEqual(t, Home, "1") - assert.NotEqual(t, This, "2") - assert.NotEqual(t, Cache, "3") - assert.NotEqual(t, Config, "4") + for i, pt := range Paths { + old := pt.String() + val := strconv.Itoa(i) + Set(pt, val) + assert.Equal(t, pt.String(), val) + Reset() + assert.Equal(t, pt.String(), old) + } } diff --git a/paths/paths_testutil.go b/paths/paths_testutil.go new file mode 100644 index 0000000..5b8af48 --- /dev/null +++ b/paths/paths_testutil.go @@ -0,0 +1,26 @@ +//go:build test + +package paths + +var backups = make(map[*Path]string) + +func SetAll(folder string) { + for _, p := range Paths { + Set(p, folder) + } +} + +// Set temporarily sets the paths for unit test purposes +// remember to defer Reset +func Set(target *Path, value string) { + backups[target] = target.String() + target.Set(value) +} + +// Reset sets the path variables back to before the unit test +func Reset() { + for path, oldValue := range backups { + path.Set(oldValue) + } + backups = make(map[*Path]string) +} |
