-
Notifications
You must be signed in to change notification settings - Fork 4
/
golden.go
140 lines (110 loc) · 3.61 KB
/
golden.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package testutils
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"
)
var update bool
const (
// UpdateGoldenFilesEnv is the environment variable used to indicate go test that
// the golden files should be overwritten with the current test results.
UpdateGoldenFilesEnv = `TESTS_UPDATE_GOLDEN`
)
func init() {
if os.Getenv(UpdateGoldenFilesEnv) != "" {
update = true
}
}
type goldenOptions struct {
goldenPath string
}
// Option is a supported option reference to change the golden files comparison.
type Option func(*goldenOptions)
// WithGoldenPath overrides the default path for golden files used.
func WithGoldenPath(path string) Option {
return func(o *goldenOptions) {
if path != "" {
o.goldenPath = path
}
}
}
// LoadWithUpdateFromGolden loads the element from a plaintext golden file.
// It will update the file if the update flag is used prior to loading it.
func LoadWithUpdateFromGolden(t *testing.T, data string, opts ...Option) string {
t.Helper()
o := goldenOptions{
goldenPath: Path(t),
}
for _, opt := range opts {
opt(&o)
}
if update {
t.Logf("updating golden file %s", o.goldenPath)
err := os.MkdirAll(filepath.Dir(o.goldenPath), 0750)
require.NoError(t, err, "Cannot create directory for updating golden files")
err = os.WriteFile(o.goldenPath, []byte(data), 0600)
require.NoError(t, err, "Cannot write golden file")
}
want, err := os.ReadFile(o.goldenPath)
t.Log(o.goldenPath)
require.NoError(t, err, "Cannot load golden file")
r := string(want)
if runtime.GOOS == "windows" {
r = strings.ReplaceAll(r, "\r\n", "\n")
}
return r
}
// LoadWithUpdateFromGoldenYAML load the generic element from a YAML serialized golden file.
// It will update the file if the update flag is used prior to deserializing it.
func LoadWithUpdateFromGoldenYAML[E any](t *testing.T, got E, opts ...Option) E {
t.Helper()
t.Logf("Serializing object for golden file")
data, err := yaml.Marshal(got)
require.NoError(t, err, "Cannot serialize provided object")
want := LoadWithUpdateFromGolden(t, string(data), opts...)
var wantDeserialized E
err = yaml.Unmarshal([]byte(want), &wantDeserialized)
require.NoError(t, err, "Cannot create expanded policy objects from golden file")
return wantDeserialized
}
// TestFamilyPath returns the path of the dir for storing fixtures and other files related to the test.
func TestFamilyPath(t *testing.T) string {
t.Helper()
// Ensures that only the name of the parent test is used.
familyName, _, _ := strings.Cut(t.Name(), "/")
return filepath.Join("testdata", familyName)
}
// TestFixturePath returns the path of the dir or file for storing fixture specific to the subtest name.
func TestFixturePath(t *testing.T) string {
t.Helper()
// Ensures that only the name of the parent test is used.
familyName, subtestName, _ := strings.Cut(t.Name(), "/")
return filepath.Join("testdata", familyName, normalizeName(t, subtestName))
}
// Path returns the golden path for the provided test.
func Path(t *testing.T) string {
t.Helper()
path := filepath.Join(TestFamilyPath(t), "golden")
_, sub, found := strings.Cut(t.Name(), "/")
if found {
path = filepath.Join(path, normalizeName(t, sub))
}
return path
}
// normalizeName returns a path from name with illegal Windows
// characters replaced or removed.
func normalizeName(t *testing.T, name string) string {
t.Helper()
name = strings.ReplaceAll(name, `\`, "_")
name = strings.ReplaceAll(name, ":", "")
name = strings.ToLower(name)
return name
}
// UpdateEnabled is a getter for the update flag.
func UpdateEnabled() bool {
return update
}