From 1659fed99fdfeea53fa0d1da9da4fc3f7591116b Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Fri, 27 May 2022 11:15:35 -0400 Subject: [PATCH 01/19] test(778): capture stderr and stdout during tests --- commands/env.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/commands/env.go b/commands/env.go index ac7b789a4be0e1008e0d40a05db7e18e81eff627..98a7e1a57e043d21679abca371e5b37350b80471 100644 --- a/commands/env.go +++ b/commands/env.go @@ -141,6 +141,9 @@ func loadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error { // This wrapper style is necessary because a Cobra PostE function does not run if RunE return an error. func closeBackend(env *Env, runE func(cmd *cobra.Command, args []string) error) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { + env.err = out{Writer: cmd.ErrOrStderr()} + env.out = out{Writer: cmd.OutOrStdout()} + errRun := runE(cmd, args) if env.backend == nil { From 523a1481857e4e4e13c03a1d4d7630db73568694 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Fri, 27 May 2022 13:33:44 -0400 Subject: [PATCH 02/19] test(778): allow alternate CWD via context --- commands/env.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/commands/env.go b/commands/env.go index 98a7e1a57e043d21679abca371e5b37350b80471..4d90348f1ea02e96c936ebf7170961a59fe0f5ff 100644 --- a/commands/env.go +++ b/commands/env.go @@ -46,12 +46,26 @@ func (o out) Println(a ...interface{}) { _, _ = fmt.Fprintln(o, a...) } +func getCWD(cmd *cobra.Command, args []string) (string, error) { + cwd, ok := cmd.Context().Value("cwd").(string) + if cwd != "" && ok { + return cwd, nil + } + + cwd, err := os.Getwd() + if err != nil { + return "", fmt.Errorf("unable to get the current working directory: %q", err) + } + + return cwd, nil +} + // loadRepo is a pre-run function that load the repository for use in a command func loadRepo(env *Env) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { - cwd, err := os.Getwd() + cwd, err := getCWD(cmd, args) if err != nil { - return fmt.Errorf("unable to get the current working directory: %q", err) + return err } env.repo, err = repository.OpenGoGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader}) From 5962ed8453c07ff824a6935883b648cd642c4d2a Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Fri, 27 May 2022 13:34:59 -0400 Subject: [PATCH 03/19] test(778): verify root command returns main help text --- commands/root_test.go | 82 +++++++++++++++++++++++++++ commands/testdata/root_out_golden.txt | 38 +++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 commands/root_test.go create mode 100644 commands/testdata/root_out_golden.txt diff --git a/commands/root_test.go b/commands/root_test.go new file mode 100644 index 0000000000000000000000000000000000000000..5e780ec7329b1adea4addefef82157f9cf678405 --- /dev/null +++ b/commands/root_test.go @@ -0,0 +1,82 @@ +package commands_test + +import ( + "bytes" + "context" + "flag" + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/MichaelMure/git-bug/commands" + "github.com/MichaelMure/git-bug/repository" + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" +) + +var update = flag.Bool("update", false, "pass -update to the test runner to update golden files") + +type testEnv struct { + cwd string + repo *repository.GoGitRepo + cmd *cobra.Command + out *bytes.Buffer +} + +func newTestEnv(t *testing.T) *testEnv { + t.Helper() + + cwd, err := ioutil.TempDir("", "") + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, os.RemoveAll(cwd)) + }) + + repo, err := repository.InitGoGitRepo(cwd) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, repo.Close()) + }) + + out := new(bytes.Buffer) + cmd := commands.NewRootCommand() + cmd.SetArgs([]string{}) + cmd.SetErr(out) + cmd.SetOut(out) + + return &testEnv{ + cwd: cwd, + repo: repo, + cmd: cmd, + out: out, + } +} + +func (e *testEnv) Execute(t *testing.T) { + t.Helper() + + ctx := context.WithValue(context.Background(), "cwd", e.cwd) + require.NoError(t, e.cmd.ExecuteContext(ctx)) +} + +func requireGoldenFileEqual(t *testing.T, path string, act []byte) { + t.Helper() + + path = filepath.Join("testdata", path) + + if *update { + require.NoError(t, ioutil.WriteFile(path, act, 0644)) + } + + exp, err := ioutil.ReadFile(path) + require.NoError(t, err) + require.Equal(t, exp, act) +} + +func TestNewRootCommand(t *testing.T) { + testEnv := newTestEnv(t) + testEnv.Execute(t) + + requireGoldenFileEqual(t, "root_out_golden.txt", testEnv.out.Bytes()) +} diff --git a/commands/testdata/root_out_golden.txt b/commands/testdata/root_out_golden.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff371afd833f682a3dfdecbfba928bece4668454 --- /dev/null +++ b/commands/testdata/root_out_golden.txt @@ -0,0 +1,38 @@ +git-bug is a bug tracker embedded in git. + +git-bug use git objects to store the bug tracking separated from the files +history. As bugs are regular git objects, they can be pushed and pulled from/to +the same git remote you are already using to collaborate with other people. + +Usage: + git-bug [flags] + git-bug [command] + +Available Commands: + add Create a new bug. + bridge Configure and use bridges to other bug trackers. + commands Display available commands. + comment Display or add comments to a bug. + completion Generate the autocompletion script for the specified shell + deselect Clear the implicitly selected bug. + help Help about any command + label Display, add or remove labels to/from a bug. + ls List bugs. + ls-id List bug identifiers. + ls-label List valid labels. + pull Pull bugs update from a git remote. + push Push bugs update to a git remote. + rm Remove an existing bug. + select Select a bug for implicit use in future commands. + show Display the details of a bug. + status Display or change a bug status. + termui Launch the terminal UI. + title Display or change a title of a bug. + user Display or change the user identity. + version Show git-bug version information. + webui Launch the web UI. + +Flags: + -h, --help help for git-bug + +Use "git-bug [command] --help" for more information about a command. From 50324b8a7c23d5f68246af05e59024278e199148 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Fri, 27 May 2022 13:39:16 -0400 Subject: [PATCH 04/19] test(778): verify user create results in an identity and cache --- commands/user_create.go | 3 +++ commands/user_create_test.go | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 commands/user_create_test.go diff --git a/commands/user_create.go b/commands/user_create.go index b5cb0528b47116f44ae09bd1b74b9866a3329b2e..14a13eac54ef2244f4c79f652b0b6cbaeefeea69 100644 --- a/commands/user_create.go +++ b/commands/user_create.go @@ -22,6 +22,9 @@ func newUserCreateCommand() *cobra.Command { Short: "Create a new identity.", PreRunE: loadBackend(env), RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error { + env.err = out{Writer: cmd.ErrOrStderr()} + env.out = out{Writer: cmd.OutOrStdout()} + return runUserCreate(env, options) }), } diff --git a/commands/user_create_test.go b/commands/user_create_test.go new file mode 100644 index 0000000000000000000000000000000000000000..c2e2398f83faa8d84d4588c663aa0ef97470ea33 --- /dev/null +++ b/commands/user_create_test.go @@ -0,0 +1,37 @@ +package commands_test + +import ( + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func newTestEnvAndUser(t *testing.T) (*testEnv, string) { + t.Helper() + + testEnv := newTestEnv(t) + + testEnv.cmd.SetArgs( + []string{ + "user", + "create", + "--non-interactive", + "-n John Doe", + "-e jdoe@example.com", + }) + + testEnv.Execute(t) + + return testEnv, strings.TrimSpace(testEnv.out.String()) +} + +func TestUserCreateCommand(t *testing.T) { + testEnv, userID := newTestEnvAndUser(t) + + t.Log("CWD:", testEnv.cwd) + + require.FileExists(t, filepath.Join(testEnv.cwd, ".git", "refs", "identities", userID)) + require.FileExists(t, filepath.Join(testEnv.cwd, ".git", "git-bug", "identity-cache")) +} From 508d0eb82a8a29cc814e87d11f7ee0959cb137ab Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Sat, 28 May 2022 10:29:30 -0400 Subject: [PATCH 05/19] test(778): clear output after user creation --- commands/user_create_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commands/user_create_test.go b/commands/user_create_test.go index c2e2398f83faa8d84d4588c663aa0ef97470ea33..07ed657bf04a54e5822ad3b07aa2c88150a8bb89 100644 --- a/commands/user_create_test.go +++ b/commands/user_create_test.go @@ -23,8 +23,10 @@ func newTestEnvAndUser(t *testing.T) (*testEnv, string) { }) testEnv.Execute(t) + userID := strings.TrimSpace(testEnv.out.String()) + testEnv.out.Reset() - return testEnv, strings.TrimSpace(testEnv.out.String()) + return testEnv, userID } func TestUserCreateCommand(t *testing.T) { From ecfffe3902731224288add3b44119dccae46fd6f Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Sat, 28 May 2022 10:30:44 -0400 Subject: [PATCH 06/19] test(778): execute add user in testEnv and return userID --- commands/add_test.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 commands/add_test.go diff --git a/commands/add_test.go b/commands/add_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b85c7fa25c2090f024b1f6f762a63496ad66435d --- /dev/null +++ b/commands/add_test.go @@ -0,0 +1,33 @@ +package commands_test + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func newTestEnvUserAndBug(t *testing.T) (*testEnv, string, string) { + t.Helper() + + testEnv, userID := newTestEnvAndUser(t) + + testEnv.cmd.SetArgs([]string{ + "add", + "--non-interactive", + "-t 'this is a bug title'", + "-m 'this is a bug message'", + }) + + testEnv.Execute(t) + require.Regexp(t, "^[0-9A-Fa-f]{7} created\n$", testEnv.out) + bugID := strings.Split(testEnv.out.String(), " ")[0] + testEnv.out.Reset() + + return testEnv, userID, bugID +} + +func TestAdd(t *testing.T) { + _, _, user := newTestEnvUserAndBug(t) + require.Regexp(t, "^[0-9A-Fa-f]{7}$", user) +} From 90208b5f6dc13cafc088862fcf5e7f961e119f27 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Sat, 28 May 2022 10:38:04 -0400 Subject: [PATCH 07/19] test(778): execute rm bug in testEnv (hangs) --- commands/rm_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 commands/rm_test.go diff --git a/commands/rm_test.go b/commands/rm_test.go new file mode 100644 index 0000000000000000000000000000000000000000..e8b53057c924d1a00ce689d00fe275db0fdf8f04 --- /dev/null +++ b/commands/rm_test.go @@ -0,0 +1,15 @@ +package commands_test + +import "testing" + +func TestRm(t *testing.T) { + testEnv, _, bugID := newTestEnvUserAndBug(t) + + testEnv.cmd.SetArgs([]string{ + "rm", + bugID, + }) + + testEnv.Execute(t) + // TODO: add assertions after #778 is diagnosed and fixed +} From eda312f9b1998f5c6d6881312091fd9451c2ffe3 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Tue, 31 May 2022 21:25:23 -0400 Subject: [PATCH 08/19] fix(778): remove extra mutex lock when resolving bug prefix --- cache/repo_cache_bug.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cache/repo_cache_bug.go b/cache/repo_cache_bug.go index bce019265b6dfecc2310fc7a155441331e2f8cf7..f8bf5a2fd73a4818e34014c74b2e5b91849f0e44 100644 --- a/cache/repo_cache_bug.go +++ b/cache/repo_cache_bug.go @@ -499,14 +499,10 @@ func (c *RepoCache) NewBugRaw(author *IdentityCache, unixTime int64, title strin // RemoveBug removes a bug from the cache and repo given a bug id prefix func (c *RepoCache) RemoveBug(prefix string) error { - c.muBug.RLock() - b, err := c.ResolveBugPrefix(prefix) if err != nil { - c.muBug.RUnlock() return err } - c.muBug.RUnlock() c.muBug.Lock() err = bug.RemoveBug(c.repo, b.Id()) From cd1099aac8cd2de0c3c47587a76da53df2c2f448 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Mon, 6 Jun 2022 08:25:36 -0400 Subject: [PATCH 09/19] fix(808): replace Windows line terminators --- commands/root_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/commands/root_test.go b/commands/root_test.go index 5e780ec7329b1adea4addefef82157f9cf678405..5f5a88760e21b15d96c3fcc361507f7105e21e26 100644 --- a/commands/root_test.go +++ b/commands/root_test.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "testing" "github.com/MichaelMure/git-bug/commands" @@ -63,6 +64,9 @@ func (e *testEnv) Execute(t *testing.T) { func requireGoldenFileEqual(t *testing.T, path string, act []byte) { t.Helper() + // Replace Windows line terminators + act = []byte(strings.ReplaceAll(string(act), "\r\n", "\n")) + path = filepath.Join("testdata", path) if *update { @@ -71,7 +75,7 @@ func requireGoldenFileEqual(t *testing.T, path string, act []byte) { exp, err := ioutil.ReadFile(path) require.NoError(t, err) - require.Equal(t, exp, act) + require.Equal(t, string(exp), string(act)) } func TestNewRootCommand(t *testing.T) { From 5982e8fb3c7d07ff47d2b6143bc74d32669970f7 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Mon, 6 Jun 2022 08:39:40 -0400 Subject: [PATCH 10/19] chore(808): merge in LocalStorage namespace configuration --- commands/env.go | 4 ++-- commands/root_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commands/env.go b/commands/env.go index 0bf32a1a2221b340b694ef1c9a851b32ff07312a..c2128780d1f998809fdd4eff33582f6b6d9e2c8c 100644 --- a/commands/env.go +++ b/commands/env.go @@ -14,7 +14,7 @@ import ( "github.com/MichaelMure/git-bug/util/interrupt" ) -const gitBugNamespace = "git-bug" +const GitBugNamespace = "git-bug" // Env is the environment of a command type Env struct { @@ -70,7 +70,7 @@ func loadRepo(env *Env) func(*cobra.Command, []string) error { return err } - env.repo, err = repository.OpenGoGitRepo(cwd, gitBugNamespace, []repository.ClockLoader{bug.ClockLoader}) + env.repo, err = repository.OpenGoGitRepo(cwd, GitBugNamespace, []repository.ClockLoader{bug.ClockLoader}) if err == repository.ErrNotARepo { return fmt.Errorf("%s must be run from within a git repo", rootCommandName) } diff --git a/commands/root_test.go b/commands/root_test.go index 5f5a88760e21b15d96c3fcc361507f7105e21e26..840bedda7870194c932668a3a23e87dbc13c9b21 100644 --- a/commands/root_test.go +++ b/commands/root_test.go @@ -34,7 +34,7 @@ func newTestEnv(t *testing.T) *testEnv { require.NoError(t, os.RemoveAll(cwd)) }) - repo, err := repository.InitGoGitRepo(cwd) + repo, err := repository.InitGoGitRepo(cwd, commands.GitBugNamespace) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, repo.Close()) From 1a504e05225bb86492bec5a6f8b1b0172d1860c7 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Mon, 6 Jun 2022 09:01:02 -0400 Subject: [PATCH 11/19] fix(808): simplify handling of Windows line terminations --- commands/root_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/commands/root_test.go b/commands/root_test.go index 840bedda7870194c932668a3a23e87dbc13c9b21..c26964d772177ae7a31bbf4b05ffc7d9b3ef5d60 100644 --- a/commands/root_test.go +++ b/commands/root_test.go @@ -7,7 +7,6 @@ import ( "io/ioutil" "os" "path/filepath" - "strings" "testing" "github.com/MichaelMure/git-bug/commands" @@ -65,7 +64,7 @@ func requireGoldenFileEqual(t *testing.T, path string, act []byte) { t.Helper() // Replace Windows line terminators - act = []byte(strings.ReplaceAll(string(act), "\r\n", "\n")) + // act = []byte(strings.ReplaceAll(string(act), "\r\n", "\n")) path = filepath.Join("testdata", path) From 99669d77b11851dd35e4c9998594d3cb517543f3 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Mon, 6 Jun 2022 09:38:15 -0400 Subject: [PATCH 12/19] test(808): do not run golden file tests on Windows --- commands/env_test.go | 60 +++++++++++++++++++++++++++++++++++++++++++ commands/root_test.go | 55 +++------------------------------------ 2 files changed, 63 insertions(+), 52 deletions(-) create mode 100644 commands/env_test.go diff --git a/commands/env_test.go b/commands/env_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1a5922a912dad78a28dff3550998b34397aae88b --- /dev/null +++ b/commands/env_test.go @@ -0,0 +1,60 @@ +package commands_test + +import ( + "bytes" + "context" + "flag" + "io/ioutil" + "os" + "testing" + + "github.com/MichaelMure/git-bug/commands" + "github.com/MichaelMure/git-bug/repository" + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" +) + +var update = flag.Bool("update", false, "pass -update to the test runner to update golden files") + +type testEnv struct { + cwd string + repo *repository.GoGitRepo + cmd *cobra.Command + out *bytes.Buffer +} + +func newTestEnv(t *testing.T) *testEnv { + t.Helper() + + cwd, err := ioutil.TempDir("", "") + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, os.RemoveAll(cwd)) + }) + + repo, err := repository.InitGoGitRepo(cwd, commands.GitBugNamespace) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, repo.Close()) + }) + + out := new(bytes.Buffer) + cmd := commands.NewRootCommand() + cmd.SetArgs([]string{}) + cmd.SetErr(out) + cmd.SetOut(out) + + return &testEnv{ + cwd: cwd, + repo: repo, + cmd: cmd, + out: out, + } +} + +func (e *testEnv) Execute(t *testing.T) { + t.Helper() + + ctx := context.WithValue(context.Background(), "cwd", e.cwd) + require.NoError(t, e.cmd.ExecuteContext(ctx)) +} diff --git a/commands/root_test.go b/commands/root_test.go index c26964d772177ae7a31bbf4b05ffc7d9b3ef5d60..8983037c111b21df768068cd2ee9d4b904cf67d1 100644 --- a/commands/root_test.go +++ b/commands/root_test.go @@ -1,70 +1,21 @@ +//go:build !windows + package commands_test import ( "bytes" - "context" - "flag" "io/ioutil" - "os" "path/filepath" "testing" - "github.com/MichaelMure/git-bug/commands" - "github.com/MichaelMure/git-bug/repository" - "github.com/spf13/cobra" "github.com/stretchr/testify/require" ) -var update = flag.Bool("update", false, "pass -update to the test runner to update golden files") - -type testEnv struct { - cwd string - repo *repository.GoGitRepo - cmd *cobra.Command - out *bytes.Buffer -} - -func newTestEnv(t *testing.T) *testEnv { - t.Helper() - - cwd, err := ioutil.TempDir("", "") - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, os.RemoveAll(cwd)) - }) - - repo, err := repository.InitGoGitRepo(cwd, commands.GitBugNamespace) - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, repo.Close()) - }) - - out := new(bytes.Buffer) - cmd := commands.NewRootCommand() - cmd.SetArgs([]string{}) - cmd.SetErr(out) - cmd.SetOut(out) - - return &testEnv{ - cwd: cwd, - repo: repo, - cmd: cmd, - out: out, - } -} - -func (e *testEnv) Execute(t *testing.T) { - t.Helper() - - ctx := context.WithValue(context.Background(), "cwd", e.cwd) - require.NoError(t, e.cmd.ExecuteContext(ctx)) -} - func requireGoldenFileEqual(t *testing.T, path string, act []byte) { t.Helper() // Replace Windows line terminators - // act = []byte(strings.ReplaceAll(string(act), "\r\n", "\n")) + act = bytes.ReplaceAll(act, []byte{'\r'}, []byte{}) path = filepath.Join("testdata", path) From 54306a8f0a6f3223042e40423f0b9378a420d200 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Mon, 6 Jun 2022 09:49:13 -0400 Subject: [PATCH 13/19] test(808): make build tag compatible with Go 1.16 --- commands/root_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/commands/root_test.go b/commands/root_test.go index 8983037c111b21df768068cd2ee9d4b904cf67d1..63331605e135f0e3175942847ee70ca01d6a0571 100644 --- a/commands/root_test.go +++ b/commands/root_test.go @@ -1,4 +1,5 @@ //go:build !windows +// +build !windows package commands_test From 848f72537d45b750dd78947c7f193402669fcaf1 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Mon, 6 Jun 2022 10:13:42 -0400 Subject: [PATCH 14/19] fix(808): remove duplication stderr/stdout set-up --- commands/user_create.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/commands/user_create.go b/commands/user_create.go index 14a13eac54ef2244f4c79f652b0b6cbaeefeea69..b5cb0528b47116f44ae09bd1b74b9866a3329b2e 100644 --- a/commands/user_create.go +++ b/commands/user_create.go @@ -22,9 +22,6 @@ func newUserCreateCommand() *cobra.Command { Short: "Create a new identity.", PreRunE: loadBackend(env), RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error { - env.err = out{Writer: cmd.ErrOrStderr()} - env.out = out{Writer: cmd.OutOrStdout()} - return runUserCreate(env, options) }), } From f0f52472dc570baede240572dba8392cf75cad5d Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Tue, 7 Jun 2022 07:34:04 -0400 Subject: [PATCH 15/19] test(808): skip root help test that uses a golden file --- commands/root_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/commands/root_test.go b/commands/root_test.go index 63331605e135f0e3175942847ee70ca01d6a0571..aaf708c8df44e58f7cfb9e530ab16ad746186e2a 100644 --- a/commands/root_test.go +++ b/commands/root_test.go @@ -4,7 +4,6 @@ package commands_test import ( - "bytes" "io/ioutil" "path/filepath" "testing" @@ -15,9 +14,6 @@ import ( func requireGoldenFileEqual(t *testing.T, path string, act []byte) { t.Helper() - // Replace Windows line terminators - act = bytes.ReplaceAll(act, []byte{'\r'}, []byte{}) - path = filepath.Join("testdata", path) if *update { @@ -30,6 +26,8 @@ func requireGoldenFileEqual(t *testing.T, path string, act []byte) { } func TestNewRootCommand(t *testing.T) { + t.Skip() + testEnv := newTestEnv(t) testEnv.Execute(t) From 6ec7d67ea14d236c65b3d93bb4c4501432696659 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Tue, 7 Jun 2022 07:45:30 -0400 Subject: [PATCH 16/19] test(808): document getCWD() and clean-up arguments --- commands/env.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/commands/env.go b/commands/env.go index c2128780d1f998809fdd4eff33582f6b6d9e2c8c..9be20c1486536520d57e643b1529e0e0e3681504 100644 --- a/commands/env.go +++ b/commands/env.go @@ -48,7 +48,13 @@ func (o out) Println(a ...interface{}) { _, _ = fmt.Fprintln(o, a...) } -func getCWD(cmd *cobra.Command, args []string) (string, error) { +// getCWD returns the current working directory. Normal operation simply +// returns the working directory reported by the OS (as an OS-compatible +// filepath.) During tests, temporary repositories are created outside +// the test execution's CWD. In this case, it's possible to provide an +// alternate CWD filepath by adding a value to the command's context +// with the key "cwd". +func getCWD(cmd *cobra.Command) (string, error) { cwd, ok := cmd.Context().Value("cwd").(string) if cwd != "" && ok { return cwd, nil @@ -65,7 +71,7 @@ func getCWD(cmd *cobra.Command, args []string) (string, error) { // loadRepo is a pre-run function that load the repository for use in a command func loadRepo(env *Env) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { - cwd, err := getCWD(cmd, args) + cwd, err := getCWD(cmd) if err != nil { return err } From 941f5b3fc362be388dd3bd979799dd296daec243 Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Tue, 7 Jun 2022 08:01:19 -0400 Subject: [PATCH 17/19] chore(808): rearrange imports to git-bug convention --- commands/env_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/commands/env_test.go b/commands/env_test.go index 1a5922a912dad78a28dff3550998b34397aae88b..346024ab7b2271bae9e40c35e126ebab881d1207 100644 --- a/commands/env_test.go +++ b/commands/env_test.go @@ -8,10 +8,11 @@ import ( "os" "testing" - "github.com/MichaelMure/git-bug/commands" - "github.com/MichaelMure/git-bug/repository" "github.com/spf13/cobra" "github.com/stretchr/testify/require" + + "github.com/MichaelMure/git-bug/commands" + "github.com/MichaelMure/git-bug/repository" ) var update = flag.Bool("update", false, "pass -update to the test runner to update golden files") From 0a9aaa94429172d14297f709ec2137cd3749cfea Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Wed, 15 Jun 2022 09:07:00 -0400 Subject: [PATCH 18/19] refactor(778): test only command implementations --- commands/add_test.go | 19 ++++---- commands/env.go | 31 ++------------ commands/env_test.go | 61 -------------------------- commands/env_testing.go | 62 +++++++++++++++++++++++++++ commands/rm_test.go | 18 ++++---- commands/root_test.go | 35 --------------- commands/testdata/root_out_golden.txt | 38 ---------------- commands/user_create_test.go | 21 ++++----- 8 files changed, 94 insertions(+), 191 deletions(-) delete mode 100644 commands/env_test.go create mode 100644 commands/env_testing.go delete mode 100644 commands/root_test.go delete mode 100644 commands/testdata/root_out_golden.txt diff --git a/commands/add_test.go b/commands/add_test.go index b85c7fa25c2090f024b1f6f762a63496ad66435d..63eda06e3043f45be04dd4d8f33986419ee86d97 100644 --- a/commands/add_test.go +++ b/commands/add_test.go @@ -1,4 +1,4 @@ -package commands_test +package commands import ( "strings" @@ -11,15 +11,14 @@ func newTestEnvUserAndBug(t *testing.T) (*testEnv, string, string) { t.Helper() testEnv, userID := newTestEnvAndUser(t) - - testEnv.cmd.SetArgs([]string{ - "add", - "--non-interactive", - "-t 'this is a bug title'", - "-m 'this is a bug message'", - }) - - testEnv.Execute(t) + opts := addOptions{ + title: "this is a bug title", + message: "this is a bug message", + messageFile: "", + nonInteractive: true, + } + + require.NoError(t, runAdd(testEnv.env, opts)) require.Regexp(t, "^[0-9A-Fa-f]{7} created\n$", testEnv.out) bugID := strings.Split(testEnv.out.String(), " ")[0] testEnv.out.Reset() diff --git a/commands/env.go b/commands/env.go index 9be20c1486536520d57e643b1529e0e0e3681504..a6bca7e4ccc8fdef6b58b122e866e8b45248410c 100644 --- a/commands/env.go +++ b/commands/env.go @@ -14,7 +14,7 @@ import ( "github.com/MichaelMure/git-bug/util/interrupt" ) -const GitBugNamespace = "git-bug" +const gitBugNamespace = "git-bug" // Env is the environment of a command type Env struct { @@ -48,35 +48,15 @@ func (o out) Println(a ...interface{}) { _, _ = fmt.Fprintln(o, a...) } -// getCWD returns the current working directory. Normal operation simply -// returns the working directory reported by the OS (as an OS-compatible -// filepath.) During tests, temporary repositories are created outside -// the test execution's CWD. In this case, it's possible to provide an -// alternate CWD filepath by adding a value to the command's context -// with the key "cwd". -func getCWD(cmd *cobra.Command) (string, error) { - cwd, ok := cmd.Context().Value("cwd").(string) - if cwd != "" && ok { - return cwd, nil - } - - cwd, err := os.Getwd() - if err != nil { - return "", fmt.Errorf("unable to get the current working directory: %q", err) - } - - return cwd, nil -} - // loadRepo is a pre-run function that load the repository for use in a command func loadRepo(env *Env) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { - cwd, err := getCWD(cmd) + cwd, err := os.Getwd() if err != nil { - return err + return fmt.Errorf("unable to get the current working directory: %q", err) } - env.repo, err = repository.OpenGoGitRepo(cwd, GitBugNamespace, []repository.ClockLoader{bug.ClockLoader}) + env.repo, err = repository.OpenGoGitRepo(cwd, gitBugNamespace, []repository.ClockLoader{bug.ClockLoader}) if err == repository.ErrNotARepo { return fmt.Errorf("%s must be run from within a git repo", rootCommandName) } @@ -163,9 +143,6 @@ func loadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error { // This wrapper style is necessary because a Cobra PostE function does not run if RunE return an error. func closeBackend(env *Env, runE func(cmd *cobra.Command, args []string) error) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { - env.err = out{Writer: cmd.ErrOrStderr()} - env.out = out{Writer: cmd.OutOrStdout()} - errRun := runE(cmd, args) if env.backend == nil { diff --git a/commands/env_test.go b/commands/env_test.go deleted file mode 100644 index 346024ab7b2271bae9e40c35e126ebab881d1207..0000000000000000000000000000000000000000 --- a/commands/env_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package commands_test - -import ( - "bytes" - "context" - "flag" - "io/ioutil" - "os" - "testing" - - "github.com/spf13/cobra" - "github.com/stretchr/testify/require" - - "github.com/MichaelMure/git-bug/commands" - "github.com/MichaelMure/git-bug/repository" -) - -var update = flag.Bool("update", false, "pass -update to the test runner to update golden files") - -type testEnv struct { - cwd string - repo *repository.GoGitRepo - cmd *cobra.Command - out *bytes.Buffer -} - -func newTestEnv(t *testing.T) *testEnv { - t.Helper() - - cwd, err := ioutil.TempDir("", "") - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, os.RemoveAll(cwd)) - }) - - repo, err := repository.InitGoGitRepo(cwd, commands.GitBugNamespace) - require.NoError(t, err) - t.Cleanup(func() { - require.NoError(t, repo.Close()) - }) - - out := new(bytes.Buffer) - cmd := commands.NewRootCommand() - cmd.SetArgs([]string{}) - cmd.SetErr(out) - cmd.SetOut(out) - - return &testEnv{ - cwd: cwd, - repo: repo, - cmd: cmd, - out: out, - } -} - -func (e *testEnv) Execute(t *testing.T) { - t.Helper() - - ctx := context.WithValue(context.Background(), "cwd", e.cwd) - require.NoError(t, e.cmd.ExecuteContext(ctx)) -} diff --git a/commands/env_testing.go b/commands/env_testing.go new file mode 100644 index 0000000000000000000000000000000000000000..092ff23317e27094bcce7c039b711e09b04ac2f6 --- /dev/null +++ b/commands/env_testing.go @@ -0,0 +1,62 @@ +package commands + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/MichaelMure/git-bug/cache" + "github.com/MichaelMure/git-bug/repository" + "github.com/MichaelMure/git-bug/util/interrupt" +) + +type testEnv struct { + env *Env + cwd string + out *bytes.Buffer +} + +func newTestEnv(t *testing.T) *testEnv { + t.Helper() + + cwd := t.TempDir() + + repo, err := repository.InitGoGitRepo(cwd, gitBugNamespace) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, repo.Close()) + }) + + buf := new(bytes.Buffer) + + backend, err := cache.NewRepoCache(repo) + require.NoError(t, err) + + testEnv := &testEnv{ + env: &Env{ + repo: repo, + backend: backend, + out: out{Writer: buf}, + err: out{Writer: buf}, + }, + cwd: cwd, + out: buf, + } + + cleaner := func(env *Env) interrupt.CleanerFunc { + return func() error { + if env.backend != nil { + err := env.backend.Close() + env.backend = nil + return err + } + return nil + } + } + + // Cleanup properly on interrupt + interrupt.RegisterCleaner(cleaner(testEnv.env)) + + return testEnv +} diff --git a/commands/rm_test.go b/commands/rm_test.go index e8b53057c924d1a00ce689d00fe275db0fdf8f04..5d4e7cca1007d336e891b96c0550c2da501d3182 100644 --- a/commands/rm_test.go +++ b/commands/rm_test.go @@ -1,15 +1,17 @@ -package commands_test +package commands -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/require" +) func TestRm(t *testing.T) { testEnv, _, bugID := newTestEnvUserAndBug(t) - testEnv.cmd.SetArgs([]string{ - "rm", - bugID, - }) + exp := "bug " + bugID + " removed\n" - testEnv.Execute(t) - // TODO: add assertions after #778 is diagnosed and fixed + require.NoError(t, runRm(testEnv.env, []string{bugID})) + require.Equal(t, exp, testEnv.out.String()) + testEnv.out.Reset() } diff --git a/commands/root_test.go b/commands/root_test.go deleted file mode 100644 index aaf708c8df44e58f7cfb9e530ab16ad746186e2a..0000000000000000000000000000000000000000 --- a/commands/root_test.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build !windows -// +build !windows - -package commands_test - -import ( - "io/ioutil" - "path/filepath" - "testing" - - "github.com/stretchr/testify/require" -) - -func requireGoldenFileEqual(t *testing.T, path string, act []byte) { - t.Helper() - - path = filepath.Join("testdata", path) - - if *update { - require.NoError(t, ioutil.WriteFile(path, act, 0644)) - } - - exp, err := ioutil.ReadFile(path) - require.NoError(t, err) - require.Equal(t, string(exp), string(act)) -} - -func TestNewRootCommand(t *testing.T) { - t.Skip() - - testEnv := newTestEnv(t) - testEnv.Execute(t) - - requireGoldenFileEqual(t, "root_out_golden.txt", testEnv.out.Bytes()) -} diff --git a/commands/testdata/root_out_golden.txt b/commands/testdata/root_out_golden.txt deleted file mode 100644 index ff371afd833f682a3dfdecbfba928bece4668454..0000000000000000000000000000000000000000 --- a/commands/testdata/root_out_golden.txt +++ /dev/null @@ -1,38 +0,0 @@ -git-bug is a bug tracker embedded in git. - -git-bug use git objects to store the bug tracking separated from the files -history. As bugs are regular git objects, they can be pushed and pulled from/to -the same git remote you are already using to collaborate with other people. - -Usage: - git-bug [flags] - git-bug [command] - -Available Commands: - add Create a new bug. - bridge Configure and use bridges to other bug trackers. - commands Display available commands. - comment Display or add comments to a bug. - completion Generate the autocompletion script for the specified shell - deselect Clear the implicitly selected bug. - help Help about any command - label Display, add or remove labels to/from a bug. - ls List bugs. - ls-id List bug identifiers. - ls-label List valid labels. - pull Pull bugs update from a git remote. - push Push bugs update to a git remote. - rm Remove an existing bug. - select Select a bug for implicit use in future commands. - show Display the details of a bug. - status Display or change a bug status. - termui Launch the terminal UI. - title Display or change a title of a bug. - user Display or change the user identity. - version Show git-bug version information. - webui Launch the web UI. - -Flags: - -h, --help help for git-bug - -Use "git-bug [command] --help" for more information about a command. diff --git a/commands/user_create_test.go b/commands/user_create_test.go index 07ed657bf04a54e5822ad3b07aa2c88150a8bb89..223e7ec3fc1e9e38e07bba614f9f8c10396728cf 100644 --- a/commands/user_create_test.go +++ b/commands/user_create_test.go @@ -1,4 +1,4 @@ -package commands_test +package commands import ( "path/filepath" @@ -13,16 +13,15 @@ func newTestEnvAndUser(t *testing.T) (*testEnv, string) { testEnv := newTestEnv(t) - testEnv.cmd.SetArgs( - []string{ - "user", - "create", - "--non-interactive", - "-n John Doe", - "-e jdoe@example.com", - }) + opts := createUserOptions{ + name: "John Doe", + email: "jdoe@example.com", + avatarURL: "", + nonInteractive: true, + } + + require.NoError(t, runUserCreate(testEnv.env, opts)) - testEnv.Execute(t) userID := strings.TrimSpace(testEnv.out.String()) testEnv.out.Reset() @@ -32,8 +31,6 @@ func newTestEnvAndUser(t *testing.T) (*testEnv, string) { func TestUserCreateCommand(t *testing.T) { testEnv, userID := newTestEnvAndUser(t) - t.Log("CWD:", testEnv.cwd) - require.FileExists(t, filepath.Join(testEnv.cwd, ".git", "refs", "identities", userID)) require.FileExists(t, filepath.Join(testEnv.cwd, ".git", "git-bug", "identity-cache")) } From d853a6fbc996762ab264452150558bb92bdbd6fc Mon Sep 17 00:00:00 2001 From: Steve Moyer Date: Wed, 15 Jun 2022 10:23:33 -0400 Subject: [PATCH 19/19] test(778): simplify and guarantee backend cleanup --- commands/env_testing.go | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/commands/env_testing.go b/commands/env_testing.go index 092ff23317e27094bcce7c039b711e09b04ac2f6..4de66a9db3757d72d541b87d3ff40c493dc5c662 100644 --- a/commands/env_testing.go +++ b/commands/env_testing.go @@ -8,7 +8,6 @@ import ( "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/repository" - "github.com/MichaelMure/git-bug/util/interrupt" ) type testEnv struct { @@ -32,8 +31,11 @@ func newTestEnv(t *testing.T) *testEnv { backend, err := cache.NewRepoCache(repo) require.NoError(t, err) + t.Cleanup(func() { + backend.Close() + }) - testEnv := &testEnv{ + return &testEnv{ env: &Env{ repo: repo, backend: backend, @@ -43,20 +45,4 @@ func newTestEnv(t *testing.T) *testEnv { cwd: cwd, out: buf, } - - cleaner := func(env *Env) interrupt.CleanerFunc { - return func() error { - if env.backend != nil { - err := env.backend.Close() - env.backend = nil - return err - } - return nil - } - } - - // Cleanup properly on interrupt - interrupt.RegisterCleaner(cleaner(testEnv.env)) - - return testEnv }