feat: refactor test helpers

Better organize and allow for re-use across packages.

Signed-off-by: Brian McGee <brian@bmcgee.ie>
This commit is contained in:
Brian McGee 2024-01-02 10:51:39 +00:00
parent 256c6774c6
commit 56cf0cf979
Signed by: brianmcgee
GPG Key ID: D49016E76AD1E8C0
3 changed files with 113 additions and 91 deletions

View File

@ -1,105 +1,21 @@
package cli
import (
"fmt"
"io"
"os"
"path/filepath"
"testing"
"git.numtide.com/numtide/treefmt/internal/test"
"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",
@ -117,12 +33,10 @@ func TestAllowMissingFormatter(t *testing.T) {
func TestSpecifyingFormatters(t *testing.T) {
as := require.New(t)
tempDir := t.TempDir()
tempDir := test.TempExamples(t)
configPath := tempDir + "/treefmt.toml"
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",

View File

@ -0,0 +1,70 @@
package cli
import (
"fmt"
"io"
"os"
"path/filepath"
"testing"
"git.numtide.com/numtide/treefmt/internal/test"
"github.com/alecthomas/kong"
"github.com/stretchr/testify/require"
)
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
}

38
internal/test/temp.go Normal file
View File

@ -0,0 +1,38 @@
package test
import (
"os"
"testing"
"git.numtide.com/numtide/treefmt/internal/format"
"github.com/BurntSushi/toml"
cp "github.com/otiai10/copy"
"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 TempExamples(t *testing.T) string {
tempDir := t.TempDir()
require.NoError(t, cp.Copy("../../test/examples", tempDir), "failed to copy test data to temp dir")
return tempDir
}
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
}