diff --git a/Makefile b/Makefile index a1fecb3821..ae11fcbc2f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ FIRST_GOPATH := $(firstword $(subst :, ,$(GOPATH))) PKGS := $(shell go list ./... | grep -v /tests) GOFILES_NOVENDOR := $(shell find . -type f -name '*.go' -not -path "./vendor/*") +GOFILES_NOTEST := $(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -name "*_test.go") GOPASS_VERSION ?= $(shell cat VERSION) GOPASS_OUTPUT ?= gopass GOPASS_REVISION := $(shell cat COMMIT 2>/dev/null || git rev-parse --short=8 HEAD) @@ -131,7 +132,7 @@ codequality: @which gocyclo > /dev/null; if [ $$? -ne 0 ]; then \ $(GO) get -u github.com/fzipp/gocyclo; \ fi - @$(foreach gofile, $(GOFILES_NOVENDOR),\ + @$(foreach gofile, $(GOFILES_NOTEST),\ gocyclo -over 15 $(gofile) || exit 1;) @$(call ok) diff --git a/config/config_test.go b/config/config_test.go index 405f4a0d16..c11640b6ad 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -1,6 +1,7 @@ package config import ( + "os" "path/filepath" "testing" ) @@ -11,15 +12,49 @@ func TestHomedir(t *testing.T) { } } -func TestPwStoreDir(t *testing.T) { - for in, out := range map[string]string{ - "": filepath.Join(Homedir(), ".password-store"), - "work": filepath.Join(Homedir(), ".password-store-work"), - filepath.Join("foo", "bar"): filepath.Join(Homedir(), ".password-store-foo-bar"), - } { - got := PwStoreDir(in) - if got != out { - t.Errorf("Mismatch for %s: %s != %s", in, got, out) - } +func TestNewConfig(t *testing.T) { + if err := os.Setenv("GOPASS_CONFIG", filepath.Join(os.TempDir(), ".gopass.yml")); err != nil { + t.Fatalf("Failed to set GOPASS_CONFIG: %s", err) + } + + cfg := New() + if cfg.Root.AskForMore { + t.Errorf("AskForMore should be false") + } +} + +func TestSetConfigValue(t *testing.T) { + if err := os.Setenv("GOPASS_CONFIG", filepath.Join(os.TempDir(), ".gopass.yml")); err != nil { + t.Fatalf("Failed to set GOPASS_CONFIG: %s", err) + } + + cfg := New() + if err := cfg.SetConfigValue("", "autosync", "false"); err != nil { + t.Errorf("Error: %s", err) + } + if err := cfg.SetConfigValue("", "askformore", "true"); err != nil { + t.Errorf("Error: %s", err) + } + if err := cfg.SetConfigValue("", "askformore", "yo"); err == nil { + t.Errorf("Should fail") + } + if err := cfg.SetConfigValue("", "cliptimeout", "900"); err != nil { + t.Errorf("Error: %s", err) + } + if err := cfg.SetConfigValue("", "path", "/tmp"); err != nil { + t.Errorf("Error: %s", err) + } + cfg.Mounts["foo"] = &StoreConfig{} + if err := cfg.SetConfigValue("foo", "autosync", "true"); err != nil { + t.Errorf("Error: %s", err) + } + if err := cfg.SetConfigValue("foo", "askformore", "true"); err != nil { + t.Errorf("Error: %s", err) + } + if err := cfg.SetConfigValue("foo", "askformore", "yo"); err == nil { + t.Errorf("Should fail") + } + if err := cfg.SetConfigValue("foo", "cliptimeout", "900"); err != nil { + t.Errorf("Error: %s", err) } } diff --git a/config/io_test.go b/config/io_test.go index afd13a8962..bde18dd4d1 100644 --- a/config/io_test.go +++ b/config/io_test.go @@ -1,6 +1,17 @@ package config -import "testing" +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/fatih/color" +) func TestConfigs(t *testing.T) { for _, cfg := range []string{ @@ -103,3 +114,131 @@ version: "1.0.0"`, } } } + +const testConfig = `root: + askformore: true + autoimport: true + autosync: true + cliptimeout: 5 + noconfirm: true + nopager: true + path: /home/johndoe/.password-store + safecontent: true +mounts: + foo/sub: + askformore: false + autoimport: false + autosync: false + cliptimeout: 45 + noconfirm: false + nopager: false + path: /home/johndoe/.password-store-foo-sub + safecontent: false + work: + askformore: false + autoimport: false + autosync: false + cliptimeout: 45 + noconfirm: false + nopager: false + path: /home/johndoe/.password-store-work + safecontent: false +version: 1.4.0` + +func TestLoad(t *testing.T) { + gcfg := filepath.Join(os.TempDir(), ".gopass.yml") + if err := os.Setenv("GOPASS_CONFIG", gcfg); err != nil { + t.Fatalf("Failed to set GOPASS_CONFIG: %s", err) + } + + if err := ioutil.WriteFile(gcfg, []byte(testConfig), 0600); err != nil { + t.Fatalf("Failed to write config %s: %s", gcfg, err) + } + + cfg := Load() + if !cfg.Root.SafeContent { + t.Errorf("SafeContent should be true") + } +} + +func TestLoadError(t *testing.T) { + gcfg := filepath.Join(os.TempDir(), ".gopass-err.yml") + if err := os.Setenv("GOPASS_CONFIG", gcfg); err != nil { + t.Fatalf("Failed to set GOPASS_CONFIG: %s", err) + } + + _ = os.Remove(gcfg) + if err := ioutil.WriteFile(gcfg, []byte(testConfig), 0000); err != nil { + t.Fatalf("Failed to write config %s: %s", gcfg, err) + } + + capture(t, func() error { + _, err := load(gcfg) + if err == nil { + return fmt.Errorf("Should fail") + } + return nil + }) + + _ = os.Remove(gcfg) + cfg, err := load(gcfg) + if err == nil { + t.Errorf("Should fail") + } + gcfg = filepath.Join(os.TempDir(), "foo", ".gopass.yml") + if err := os.Setenv("GOPASS_CONFIG", gcfg); err != nil { + t.Fatalf("Failed to set GOPASS_CONFIG: %s", err) + } + if err := cfg.Save(); err != nil { + t.Errorf("Error: %s", err) + } +} + +func TestDecodeError(t *testing.T) { + gcfg := filepath.Join(os.TempDir(), ".gopass-err2.yml") + if err := os.Setenv("GOPASS_CONFIG", gcfg); err != nil { + t.Fatalf("Failed to set GOPASS_CONFIG: %s", err) + } + + _ = os.Remove(gcfg) + if err := ioutil.WriteFile(gcfg, []byte(testConfig+"\nfoobar: zab\n"), 0600); err != nil { + t.Fatalf("Failed to write config %s: %s", gcfg, err) + } + + capture(t, func() error { + _, err := load(gcfg) + if err == nil { + return fmt.Errorf("Should fail") + } + return nil + }) +} + +func capture(t *testing.T, fn func() error) string { + t.Helper() + old := os.Stdout + + oldcol := color.NoColor + color.NoColor = true + + r, w, _ := os.Pipe() + os.Stdout = w + + done := make(chan string) + go func() { + buf := &bytes.Buffer{} + _, _ = io.Copy(buf, r) + done <- buf.String() + }() + + err := fn() + // back to normal + _ = w.Close() + os.Stdout = old + color.NoColor = oldcol + if err != nil { + t.Errorf("Error: %s", err) + } + out := <-done + return strings.TrimSpace(out) +} diff --git a/config/location_test.go b/config/location_test.go new file mode 100644 index 0000000000..bc6764d840 --- /dev/null +++ b/config/location_test.go @@ -0,0 +1,95 @@ +package config + +import ( + "os" + "path/filepath" + "testing" +) + +func TestPwStoreDirNoEnv(t *testing.T) { + for in, out := range map[string]string{ + "": filepath.Join(Homedir(), ".password-store"), + "work": filepath.Join(Homedir(), ".password-store-work"), + filepath.Join("foo", "bar"): filepath.Join(Homedir(), ".password-store-foo-bar"), + } { + got := PwStoreDir(in) + if got != out { + t.Errorf("Mismatch for %s: %s != %s", in, got, out) + } + } +} + +func TestPwStoreDir(t *testing.T) { + gph := filepath.Join(os.TempDir(), "home") + _ = os.Setenv("GOPASS_HOMEDIR", gph) + + if d := PwStoreDir(""); d != filepath.Join(gph, ".password-store") { + t.Errorf("Wrong dir: %s", d) + } + if d := PwStoreDir("foo"); d != filepath.Join(gph, ".password-store-foo") { + t.Errorf("Wrong dir: %s", d) + } + + psd := filepath.Join(gph, ".password-store-test") + _ = os.Setenv("PASSWORD_STORE_DIR", psd) + + if d := PwStoreDir(""); d != psd { + t.Errorf("Wrong dir: %s", d) + } + if d := PwStoreDir("foo"); d != filepath.Join(gph, ".password-store-foo") { + t.Errorf("Wrong dir: %s", d) + } +} + +func TestConfigLocation(t *testing.T) { + evs := map[string]struct { + ev string + loc string + }{ + "GOPASS_CONFIG": {ev: filepath.Join(os.TempDir(), "gopass.yml"), loc: filepath.Join(os.TempDir(), "gopass.yml")}, + "XDG_CONFIG_HOME": {ev: filepath.Join(os.TempDir(), "xdg"), loc: filepath.Join(os.TempDir(), "xdg", "gopass", "config.yml")}, + "GOPASS_HOMEDIR": {ev: filepath.Join(os.TempDir(), "home"), loc: filepath.Join(os.TempDir(), "home", ".config", "gopass", "config.yml")}, + } + for k := range evs { + _ = os.Unsetenv(k) + } + for k, v := range evs { + _ = os.Setenv(k, v.ev) + loc := configLocation() + t.Logf("%s = %s -> %s", k, v.ev, loc) + if loc != v.loc { + t.Errorf("'%s' != '%s'", loc, v.loc) + } + _ = os.Unsetenv(k) + } +} + +func TestConfigLocations(t *testing.T) { + gpcfg := filepath.Join(os.TempDir(), "config", ".gopass.yml") + _ = os.Setenv("GOPASS_CONFIG", gpcfg) + xdghome := filepath.Join(os.TempDir(), "xdg") + _ = os.Setenv("XDG_CONFIG_HOME", xdghome) + gphome := filepath.Join(os.TempDir(), "home") + _ = os.Setenv("GOPASS_HOMEDIR", gphome) + + locs := configLocations() + t.Logf("Locations: %+v", locs) + if len(locs) != 4 { + t.Errorf("Expects 4 locations not %d", len(locs)) + } + if locs[0] != gpcfg { + t.Errorf("'%s' != '%s'", locs[0], gpcfg) + } + xdgcfg := filepath.Join(xdghome, "gopass", "config.yml") + if locs[1] != xdgcfg { + t.Errorf("'%s' != '%s'", locs[1], xdgcfg) + } + curcfg := filepath.Join(gphome, ".config", "gopass", "config.yml") + if locs[2] != curcfg { + t.Errorf("'%s' != '%s'", locs[2], curcfg) + } + oldcfg := filepath.Join(gphome, ".gopass.yml") + if locs[3] != oldcfg { + t.Errorf("'%s' != '%s'", locs[3], oldcfg) + } +} diff --git a/config/store_config.go b/config/store_config.go index f95fce89a9..85f5a3c41e 100644 --- a/config/store_config.go +++ b/config/store_config.go @@ -73,7 +73,7 @@ func (c *StoreConfig) SetConfigValue(key, value string) error { } else if value == "false" { f.SetBool(false) } else { - return errors.Errorf("No a bool: %s", value) + return errors.Errorf("not a bool: %s", value) } case reflect.Int: iv, err := strconv.Atoi(value) diff --git a/config/store_config_test.go b/config/store_config_test.go new file mode 100644 index 0000000000..7785c84033 --- /dev/null +++ b/config/store_config_test.go @@ -0,0 +1,12 @@ +package config + +import "testing" + +func TestStoreConfigMap(t *testing.T) { + sc := &StoreConfig{} + scm := sc.ConfigMap() + t.Logf("map: %+v", scm) + if scm["nopager"] != "false" { + t.Errorf("nopager should be false") + } +} diff --git a/utils/ctxutil/ctxutil_test.go b/utils/ctxutil/ctxutil_test.go index 8218d03a2e..106a19969c 100644 --- a/utils/ctxutil/ctxutil_test.go +++ b/utils/ctxutil/ctxutil_test.go @@ -77,44 +77,97 @@ func TestComposite(t *testing.T) { ctx = WithUseSymbols(ctx, false) ctx = WithAlwaysYes(ctx, true) ctx = WithNoColor(ctx, true) + ctx = WithFuzzySearch(ctx, false) + ctx = WithVerbose(ctx, true) if !IsDebug(ctx) { t.Errorf("Debug should be true") } + if !HasDebug(ctx) { + t.Errorf("Should have Debug") + } if IsColor(ctx) { t.Errorf("Color should be false") } + if !HasColor(ctx) { + t.Errorf("Should have Color") + } if IsTerminal(ctx) { - t.Errorf("Termiunal should be false") + t.Errorf("Terminal should be false") + } + if !HasTerminal(ctx) { + t.Errorf("Should have Terminal") } if IsInteractive(ctx) { t.Errorf("IsInteractive should be false") } + if !HasInteractive(ctx) { + t.Errorf("Should have Interactive") + } if !IsStdin(ctx) { t.Errorf("IsStdin should be true") } + if !HasStdin(ctx) { + t.Errorf("Should have Stdin") + } if !IsAskForMore(ctx) { t.Errorf("Ask for more should be true") } + if !HasAskForMore(ctx) { + t.Errorf("Should have AskForMore") + } if GetClipTimeout(ctx) != 10 { t.Errorf("Clip timeout should be 10") } + if !HasClipTimeout(ctx) { + t.Errorf("Should have ClipTimeout") + } if !IsNoConfirm(ctx) { t.Errorf("NoConfirm should be true") } + if !HasNoConfirm(ctx) { + t.Errorf("Should have NoConfirm") + } if !IsNoPager(ctx) { t.Errorf("NoPager should be true") } + if !HasNoPager(ctx) { + t.Errorf("Should have NoPager") + } if !IsShowSafeContent(ctx) { t.Errorf("ShowSafeContexnt should be true") } + if !HasShowSafeContent(ctx) { + t.Errorf("Should have ShowSafeContent") + } if IsGitCommit(ctx) { t.Errorf("Git commit should be false") } + if !HasGitCommit(ctx) { + t.Errorf("Shoud have GitCommit") + } if IsUseSymbols(ctx) { t.Errorf("UseSymbols should be false") } + if !HasUseSymbols(ctx) { + t.Errorf("Should have UseSymbols") + } if !IsAlwaysYes(ctx) { t.Errorf("Always yes should be true") } + if !HasAlwaysYes(ctx) { + t.Errorf("Should have AlwaysYes") + } + if !IsNoColor(ctx) { + t.Errorf("NoColor should be true") + } + if !HasNoColor(ctx) { + t.Errorf("Should have NoColor") + } + if IsFuzzySearch(ctx) { + t.Errorf("FuzzySearch should be false") + } + if !IsVerbose(ctx) { + t.Errorf("Verbose should be true") + } } diff --git a/utils/fsutil/fsutil_test.go b/utils/fsutil/fsutil_test.go index 6b7dd60661..6dc7bc7dcc 100644 --- a/utils/fsutil/fsutil_test.go +++ b/utils/fsutil/fsutil_test.go @@ -9,6 +9,19 @@ import ( "testing" ) +func TestCleanFilename(t *testing.T) { + m := map[string]string{ + `"§$%&aÜÄ*&b%§"'Ä"c%$"'"`: "a____b______c", + } + for k, v := range m { + out := CleanFilename(k) + t.Logf("%s -> %s / %s", k, v, out) + if out != v { + t.Errorf("'%s' != '%s'", out, v) + } + } +} + func TestCleanPath(t *testing.T) { tempdir, err := ioutil.TempDir("", "gopass-") if err != nil {