From d51ccf918ba760696bd239f75f56d96950959290 Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Tue, 2 Jan 2024 10:51:39 +0000 Subject: [PATCH] feat: refactor test helpers Better organize and allow for re-use across packages. Signed-off-by: Brian McGee --- internal/cli/format_test.go | 90 ++---------------------------------- internal/cli/helpers_test.go | 69 +++++++++++++++++++++++++++ internal/test/temp.go | 29 ++++++++++++ 3 files changed, 101 insertions(+), 87 deletions(-) create mode 100644 internal/cli/helpers_test.go create mode 100644 internal/test/temp.go diff --git a/internal/cli/format_test.go b/internal/cli/format_test.go index 088ece6..135a790 100644 --- a/internal/cli/format_test.go +++ b/internal/cli/format_test.go @@ -1,105 +1,21 @@ package cli import ( - "fmt" - "io" - "os" - "path/filepath" + "git.numtide.com/numtide/treefmt/internal/test" "testing" "git.numtide.com/numtide/treefmt/internal/format" - "github.com/BurntSushi/toml" - "github.com/alecthomas/kong" cp "github.com/otiai10/copy" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func writeConfig(t *testing.T, path string, cfg format.Config) { - t.Helper() - f, err := os.Create(path) - if err != nil { - t.Fatalf("failed to create a new config file: %v", err) - } - encoder := toml.NewEncoder(f) - if err = encoder.Encode(cfg); err != nil { - t.Fatalf("failed to write to config file: %v", err) - } -} - -func newKong(t *testing.T, cli interface{}, options ...kong.Option) *kong.Kong { - t.Helper() - options = append([]kong.Option{ - kong.Name("test"), - kong.Exit(func(int) { - t.Helper() - t.Fatalf("unexpected exit()") - }), - }, options...) - parser, err := kong.New(cli, options...) - assert.NoError(t, err) - return parser -} - -func tempFile(t *testing.T, path string) *os.File { - t.Helper() - file, err := os.Create(path) - if err != nil { - t.Fatalf("failed to create temporary file: %v", err) - } - return file -} - -func cmd(t *testing.T, args ...string) ([]byte, error) { - t.Helper() - - // create a new kong context - p := newKong(t, &Cli) - ctx, err := p.Parse(args) - if err != nil { - return nil, err - } - - tempDir := t.TempDir() - tempOut := tempFile(t, filepath.Join(tempDir, "combined_output")) - - // capture standard outputs before swapping them - stdout := os.Stdout - stderr := os.Stderr - - // swap them temporarily - os.Stdout = tempOut - os.Stderr = tempOut - - // run the command - if err = ctx.Run(); err != nil { - return nil, err - } - - // reset and read the temporary output - if _, err = tempOut.Seek(0, 0); err != nil { - return nil, fmt.Errorf("%w: failed to reset temp output for reading", err) - } - - out, err := io.ReadAll(tempOut) - if err != nil { - return nil, fmt.Errorf("%w: failed to read temp output", err) - } - - // swap outputs back - os.Stdout = stdout - os.Stderr = stderr - - return out, nil -} - func TestAllowMissingFormatter(t *testing.T) { as := require.New(t) tempDir := t.TempDir() configPath := tempDir + "/treefmt.toml" - writeConfig(t, configPath, format.Config{ + test.WriteConfig(t, configPath, format.Config{ Formatters: map[string]*format.Formatter{ "foo-fmt": { Command: "foo-fmt", @@ -122,7 +38,7 @@ func TestSpecifyingFormatters(t *testing.T) { as.NoError(cp.Copy("../../test/examples", tempDir), "failed to copy test data to temp dir") - writeConfig(t, configPath, format.Config{ + test.WriteConfig(t, configPath, format.Config{ Formatters: map[string]*format.Formatter{ "elm": { Command: "echo", diff --git a/internal/cli/helpers_test.go b/internal/cli/helpers_test.go new file mode 100644 index 0000000..4c93135 --- /dev/null +++ b/internal/cli/helpers_test.go @@ -0,0 +1,69 @@ +package cli + +import ( + "fmt" + "git.numtide.com/numtide/treefmt/internal/test" + "github.com/alecthomas/kong" + "github.com/stretchr/testify/require" + "io" + "os" + "path/filepath" + "testing" +) + +func newKong(t *testing.T, cli interface{}, options ...kong.Option) *kong.Kong { + t.Helper() + options = append([]kong.Option{ + kong.Name("test"), + kong.Exit(func(int) { + t.Helper() + t.Fatalf("unexpected exit()") + }), + }, options...) + parser, err := kong.New(cli, options...) + require.NoError(t, err) + return parser +} + +func cmd(t *testing.T, args ...string) ([]byte, error) { + t.Helper() + + // create a new kong context + p := newKong(t, &Cli) + ctx, err := p.Parse(args) + if err != nil { + return nil, err + } + + tempDir := t.TempDir() + tempOut := test.TempFile(t, filepath.Join(tempDir, "combined_output")) + + // capture standard outputs before swapping them + stdout := os.Stdout + stderr := os.Stderr + + // swap them temporarily + os.Stdout = tempOut + os.Stderr = tempOut + + // run the command + if err = ctx.Run(); err != nil { + return nil, err + } + + // reset and read the temporary output + if _, err = tempOut.Seek(0, 0); err != nil { + return nil, fmt.Errorf("%w: failed to reset temp output for reading", err) + } + + out, err := io.ReadAll(tempOut) + if err != nil { + return nil, fmt.Errorf("%w: failed to read temp output", err) + } + + // swap outputs back + os.Stdout = stdout + os.Stderr = stderr + + return out, nil +} diff --git a/internal/test/temp.go b/internal/test/temp.go new file mode 100644 index 0000000..04ca260 --- /dev/null +++ b/internal/test/temp.go @@ -0,0 +1,29 @@ +package test + +import ( + "git.numtide.com/numtide/treefmt/internal/format" + "github.com/BurntSushi/toml" + "os" + "testing" +) + +func WriteConfig(t *testing.T, path string, cfg format.Config) { + t.Helper() + f, err := os.Create(path) + if err != nil { + t.Fatalf("failed to create a new config file: %v", err) + } + encoder := toml.NewEncoder(f) + if err = encoder.Encode(cfg); err != nil { + t.Fatalf("failed to write to config file: %v", err) + } +} + +func TempFile(t *testing.T, path string) *os.File { + t.Helper() + file, err := os.Create(path) + if err != nil { + t.Fatalf("failed to create temporary file: %v", err) + } + return file +}