From 6beff3cebcaae538bba80223de5cfbefd2baf035 Mon Sep 17 00:00:00 2001 From: Bradley Kemp Date: Sat, 19 May 2018 14:27:00 +0100 Subject: [PATCH] Allow one-shot configuration options (#34) * s/coverage.txt/coverage.out/ * Remove Snapshotter interface, make Config exported, support one-shot configuration * Add WithOptions test --- .travis.yml | 2 +- Makefile | 2 +- config.go | 28 +++++++++++------- cupaloy.go | 56 +++++++++++++++++------------------- examples/advanced_test.go | 2 ++ examples/testdata/TestConfig | 1 + util.go | 6 ++-- 7 files changed, 53 insertions(+), 44 deletions(-) create mode 100644 examples/testdata/TestConfig diff --git a/.travis.yml b/.travis.yml index 4e76b2a..28ca8bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ script: - make test-ci after_success: - - $GOPATH/bin/goveralls -service=travis-ci -coverprofile=coverage.txt + - $GOPATH/bin/goveralls -service=travis-ci -coverprofile=coverage.out notifications: email: diff --git a/Makefile b/Makefile index af9dac7..f4c2b32 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ test-ci: coverage lint .PHONY: coverage coverage: - go test -v -coverpkg ./... -coverprofile coverage.txt ./... + go test -v -coverpkg ./... -coverprofile coverage.out ./... .PHONY: clean clean: diff --git a/config.go b/config.go index 4c94698..7785f74 100644 --- a/config.go +++ b/config.go @@ -1,7 +1,7 @@ package cupaloy // Configurator is a functional option that can be passed to cupaloy.New() to change snapshotting behaviour. -type Configurator func(*config) +type Configurator func(*Config) // EnvVariableName can be used to customize the environment variable that determines whether snapshots should be updated // e.g. @@ -9,7 +9,7 @@ type Configurator func(*config) // Will create an instance where snapshots will be updated if the UPDATE environment variable is set, // instead of the default of UPDATE_SNAPSHOTS. func EnvVariableName(name string) Configurator { - return func(c *config) { + return func(c *Config) { c.shouldUpdate = func() bool { return envVariableSet(name) } @@ -22,7 +22,7 @@ func EnvVariableName(name string) Configurator { // cupaloy.New(ShouldUpdate(func () bool { return *update }) // Will create an instance where snapshots are updated if the --update flag is passed to go test. func ShouldUpdate(f func() bool) Configurator { - return func(c *config) { + return func(c *Config) { c.shouldUpdate = f } } @@ -32,19 +32,27 @@ func ShouldUpdate(f func() bool) Configurator { // cupaloy.New(SnapshotSubdirectory("testdata")) // Will create an instance where snapshots are stored in testdata/ rather than the default .snapshots/ func SnapshotSubdirectory(name string) Configurator { - return func(c *config) { + return func(c *Config) { c.subDirName = name } } -type config struct { +// Config provides the same snapshotting functions with additional configuration capabilities. +type Config struct { shouldUpdate func() bool subDirName string } -func defaultConfig() *config { - c := &config{} - SnapshotSubdirectory(".snapshots")(c) - EnvVariableName("UPDATE_SNAPSHOTS")(c) - return c +func defaultConfig() *Config { + return (&Config{}).WithOptions( + SnapshotSubdirectory(".snapshots"), + EnvVariableName("UPDATE_SNAPSHOTS"), + ) +} + +func (c *Config) clone() *Config { + return &Config{ + shouldUpdate: c.shouldUpdate, + subDirName: c.subDirName, + } } diff --git a/cupaloy.go b/cupaloy.go index 640cf8b..95dfceb 100644 --- a/cupaloy.go +++ b/cupaloy.go @@ -7,31 +7,9 @@ import ( "testing" ) -// Snapshotter is the API for taking snapshots of values in your tests. -type Snapshotter interface { - // Snapshot compares the given value to the it's previous value stored on the filesystem. - // An error containing a diff is returned if the snapshots do not match. - // Snapshot determines the snapshot file automatically from the name of the calling function. - Snapshot(i ...interface{}) error - - // SnapshotMulti is identical to Snapshot but can be called multiple times from the same function. - // This is done by providing a unique snapshotId for each invocation. - SnapshotMulti(snapshotID string, i ...interface{}) error - - // SnapshotT is identical to Snapshot but gets the snapshot name using - // t.Name() and calls t.Fail() directly if the snapshots do not match. - SnapshotT(t *testing.T, i ...interface{}) -} - // New constructs a new, configured instance of cupaloy using the given Configurators. -func New(configurators ...Configurator) Snapshotter { - config := defaultConfig() - - for _, configurator := range configurators { - configurator(config) - } - - return config +func New(configurators ...Configurator) *Config { + return defaultConfig().WithOptions(configurators...) } // Snapshot calls Snapshotter.Snapshot with the default config. @@ -51,21 +29,28 @@ func SnapshotT(t *testing.T, i ...interface{}) { defaultConfig().SnapshotT(t, i...) } -func (c *config) Snapshot(i ...interface{}) error { +// Snapshot compares the given value to the it's previous value stored on the filesystem. +// An error containing a diff is returned if the snapshots do not match. +// Snapshot determines the snapshot file automatically from the name of the calling function. +func (c *Config) Snapshot(i ...interface{}) error { return c.snapshot(getNameOfCaller(), i...) } -func (c *config) SnapshotMulti(snapshotID string, i ...interface{}) error { +// SnapshotMulti is identical to Snapshot but can be called multiple times from the same function. +// This is done by providing a unique snapshotId for each invocation. +func (c *Config) SnapshotMulti(snapshotID string, i ...interface{}) error { snapshotName := fmt.Sprintf("%s-%s", getNameOfCaller(), snapshotID) return c.snapshot(snapshotName, i...) } -func (c *config) SnapshotT(t *testing.T, i ...interface{}) { +// SnapshotT is identical to Snapshot but gets the snapshot name using +// t.Name() and calls t.Fail() directly if the snapshots do not match. +func (c *Config) SnapshotT(t *testing.T, i ...interface{}) { t.Helper() if t.Failed() { return } - + snapshotName := strings.Replace(t.Name(), "/", "-", -1) err := c.snapshot(snapshotName, i...) if err != nil { @@ -73,7 +58,20 @@ func (c *config) SnapshotT(t *testing.T, i ...interface{}) { } } -func (c *config) snapshot(snapshotName string, i ...interface{}) error { +// WithOptions allows the modification of an existing Config. This can usefully be +// used to use a different option for a single call e.g. +// snapshotter.WithOptions(cupaloy.SnapshotSubdirectory("testdata")).SnapshotT(t, result) +func (c *Config) WithOptions(configurators ...Configurator) *Config { + clonedConfig := c.clone() + + for _, configurator := range configurators { + configurator(clonedConfig) + } + + return clonedConfig +} + +func (c *Config) snapshot(snapshotName string, i ...interface{}) error { snapshot := takeSnapshot(i...) prevSnapshot, err := c.readSnapshot(snapshotName) diff --git a/examples/advanced_test.go b/examples/advanced_test.go index ee8c9e1..9e92c80 100644 --- a/examples/advanced_test.go +++ b/examples/advanced_test.go @@ -40,6 +40,8 @@ func TestConfig(t *testing.T) { if err != nil { t.Fatalf("The config struct has all the same methods as the default %s", err) } + + snapshotter.WithOptions(cupaloy.SnapshotSubdirectory("testdata")).SnapshotT(t, "Hello world!") } // If a snapshot is updated then this returns an error diff --git a/examples/testdata/TestConfig b/examples/testdata/TestConfig new file mode 100644 index 0000000..cd08755 --- /dev/null +++ b/examples/testdata/TestConfig @@ -0,0 +1 @@ +Hello world! diff --git a/util.go b/util.go index 8deb72c..0bfa972 100644 --- a/util.go +++ b/util.go @@ -35,7 +35,7 @@ func envVariableSet(envVariable string) bool { return varSet } -func (c *config) snapshotFilePath(testName string) string { +func (c *Config) snapshotFilePath(testName string) string { return filepath.Join(c.subDirName, testName) } @@ -63,7 +63,7 @@ func takeSnapshot(i ...interface{}) string { return snapshot.String() } -func (c *config) readSnapshot(snapshotName string) (string, error) { +func (c *Config) readSnapshot(snapshotName string) (string, error) { snapshotFile := c.snapshotFilePath(snapshotName) buf, err := ioutil.ReadFile(snapshotFile) @@ -78,7 +78,7 @@ func (c *config) readSnapshot(snapshotName string) (string, error) { return string(buf), nil } -func (c *config) updateSnapshot(snapshotName string, snapshot string) error { +func (c *Config) updateSnapshot(snapshotName string, snapshot string) error { // check that subdirectory exists before writing snapshot err := os.MkdirAll(c.subDirName, os.ModePerm) if err != nil {