Files
go-golden/gold.go

174 lines
3.5 KiB
Go

package golden
import (
"os"
"path/filepath"
"strings"
"github.com/jimeh/go-golden/sanitize"
)
// gold is the underlying struct that implements the Golden interface.
type gold struct {
// dirMode determines the file system permissions of any folders created to
// hold golden files.
dirMode os.FileMode
// fileMode determines the file system permissions of any created or updated
// golden files written to disk.
fileMode os.FileMode
// suffix determines the filename suffix for all golden files. Typically
// this should be ".golden", but can be changed here if needed.
suffix string
// dirname is the name of the top-level directory at the root of the package
// which holds all golden files. Typically this should be "testdata", but
// can be changed here if needed.
dirname string
// updateFunc is used to determine if golden files should be updated or
// not. Its boolean return value is returned by Update().
updateFunc UpdateFunc
// fs is used for all file system operations. This enables providing custom
// afero.fs instances which can be useful for testing purposes.
fs FS
// logOnWrite determines if a message is logged with t.Logf when a golden
// file is written to with either of the set methods.
logOnWrite bool
}
// Ensure golden satisfies Golden interface.
var _ Golden = &gold{}
func (g *gold) Do(t TestingT, data []byte) []byte {
t.Helper()
if g.Update() {
g.Set(t, data)
}
return g.Get(t)
}
func (g *gold) DoP(t TestingT, name string, data []byte) []byte {
t.Helper()
if g.Update() {
g.SetP(t, name, data)
}
return g.GetP(t, name)
}
func (g *gold) File(t TestingT) string {
t.Helper()
return g.file(t, "")
}
func (g *gold) FileP(t TestingT, name string) string {
t.Helper()
if name == "" {
t.Fatalf("golden: name cannot be empty")
}
return g.file(t, name)
}
func (g *gold) file(t TestingT, name string) string {
t.Helper()
if t.Name() == "" {
t.Fatalf("golden: could not determine filename for TestingT instance")
}
base := []string{g.dirname, filepath.FromSlash(t.Name())}
if name != "" {
base = append(base, name)
}
f := filepath.Clean(filepath.Join(base...) + g.suffix)
dirty := strings.Split(f, string(os.PathSeparator))
clean := make([]string, 0, len(dirty))
for _, s := range dirty {
clean = append(clean, sanitize.Filename(s))
}
return strings.Join(clean, string(os.PathSeparator))
}
func (g *gold) Get(t TestingT) []byte {
t.Helper()
return g.get(t, "")
}
func (g *gold) GetP(t TestingT, name string) []byte {
t.Helper()
if name == "" {
t.Fatalf("golden: name cannot be empty")
}
return g.get(t, name)
}
func (g *gold) get(t TestingT, name string) []byte {
t.Helper()
f := g.file(t, name)
b, err := g.fs.ReadFile(f)
if err != nil {
t.Fatalf("golden: %s", err.Error())
}
return b
}
func (g *gold) Set(t TestingT, data []byte) {
t.Helper()
g.set(t, "", data)
}
func (g *gold) SetP(t TestingT, name string, data []byte) {
t.Helper()
if name == "" {
t.Fatalf("golden: name cannot be empty")
}
g.set(t, name, data)
}
func (g *gold) set(t TestingT, name string, data []byte) {
t.Helper()
f := g.file(t, name)
dir := filepath.Dir(f)
if g.logOnWrite {
t.Logf("golden: writing golden file: %s", f)
}
err := g.fs.MkdirAll(dir, g.dirMode)
if err != nil {
t.Fatalf("golden: failed to create directory: %s", err.Error())
}
err = g.fs.WriteFile(f, data, g.fileMode)
if err != nil {
t.Fatalf("golden: filed to write file: %s", err.Error())
}
}
func (g *gold) Update() bool {
return g.updateFunc()
}