1 package golden
2
3 import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "gotest.tools/v3/assert"
9 "gotest.tools/v3/assert/cmp"
10 "gotest.tools/v3/fs"
11 "gotest.tools/v3/internal/source"
12 )
13
14 type fakeT struct {
15 Failed bool
16 }
17
18 func (t *fakeT) Log(...interface{}) {
19 }
20
21 func (t *fakeT) FailNow() {
22 t.Failed = true
23 }
24
25 func (t *fakeT) Fail() {
26 t.Failed = true
27 }
28
29 func (t *fakeT) Helper() {}
30
31 func TestGoldenOpenInvalidFile(t *testing.T) {
32 fakeT := new(fakeT)
33
34 Open(fakeT, "/invalid/path")
35 assert.Assert(t, fakeT.Failed)
36 }
37
38 func TestGoldenOpenAbsolutePath(t *testing.T) {
39 file := fs.NewFile(t, "abs-test", fs.WithContent("content\n"))
40 defer file.Remove()
41 fakeT := new(fakeT)
42
43 f := Open(fakeT, file.Path())
44 assert.Assert(t, !fakeT.Failed)
45 f.Close()
46 }
47
48 func TestGoldenOpen(t *testing.T) {
49 filename, clean := setupGoldenFile(t, "")
50 defer clean()
51
52 fakeT := new(fakeT)
53
54 f := Open(fakeT, filename)
55 assert.Assert(t, !fakeT.Failed)
56 f.Close()
57 }
58
59 func TestGoldenGetInvalidFile(t *testing.T) {
60 fakeT := new(fakeT)
61
62 Get(fakeT, "/invalid/path")
63 assert.Assert(t, fakeT.Failed)
64 }
65
66 func TestGoldenGetAbsolutePath(t *testing.T) {
67 file := fs.NewFile(t, "abs-test", fs.WithContent("content\n"))
68 defer file.Remove()
69 fakeT := new(fakeT)
70
71 Get(fakeT, file.Path())
72 assert.Assert(t, !fakeT.Failed)
73 }
74
75 func TestGoldenGet(t *testing.T) {
76 expected := "content\nline1\nline2"
77
78 filename, clean := setupGoldenFile(t, expected)
79 defer clean()
80
81 fakeT := new(fakeT)
82
83 actual := Get(fakeT, filename)
84 assert.Assert(t, !fakeT.Failed)
85 assert.Assert(t, cmp.DeepEqual(actual, []byte(expected)))
86 }
87
88 func TestGoldenAssertInvalidContent(t *testing.T) {
89 filename, clean := setupGoldenFile(t, "content")
90 defer clean()
91
92 fakeT := new(fakeT)
93
94 Assert(fakeT, "foo", filename)
95 assert.Assert(t, fakeT.Failed)
96 }
97
98 func TestGoldenAssertInvalidContentUpdate(t *testing.T) {
99 setUpdateFlag(t)
100 filename, clean := setupGoldenFile(t, "content")
101 defer clean()
102
103 fakeT := new(fakeT)
104
105 Assert(fakeT, "foo", filename)
106 assert.Assert(t, !fakeT.Failed)
107 }
108
109 func TestGoldenAssertAbsolutePath(t *testing.T) {
110 file := fs.NewFile(t, "abs-test", fs.WithContent("foo"))
111 defer file.Remove()
112 fakeT := new(fakeT)
113
114 Assert(fakeT, "foo", file.Path())
115 assert.Assert(t, !fakeT.Failed)
116 }
117
118 func TestGoldenAssertInDir(t *testing.T) {
119 filename, clean := setupGoldenFileWithDir(t, "testdatasubdir", "foo")
120 defer clean()
121
122 fakeT := new(fakeT)
123
124 Assert(fakeT, "foo", filepath.Join("testdatasubdir", filename))
125 assert.Assert(t, !fakeT.Failed)
126
127 _, err := os.Stat("testdatasubdir")
128 assert.Assert(t, os.IsNotExist(err), "testdatasubdir should not exist outside of testdata")
129 }
130
131 func TestGoldenAssertInDir_UpdateGolden(t *testing.T) {
132 filename, clean := setupGoldenFileWithDir(t, "testdatasubdir", "foo")
133 defer clean()
134 setUpdateFlag(t)
135
136 fakeT := new(fakeT)
137
138 Assert(fakeT, "foo", filepath.Join("testdatasubdir", filename))
139 assert.Assert(t, !fakeT.Failed)
140
141 _, err := os.Stat("testdatasubdir")
142 assert.Assert(t, os.IsNotExist(err), "testdatasubdir should not exist outside of testdata")
143 }
144
145 func TestGoldenAssert(t *testing.T) {
146 filename, clean := setupGoldenFile(t, "foo")
147 defer clean()
148
149 fakeT := new(fakeT)
150
151 Assert(fakeT, "foo", filename)
152 assert.Assert(t, !fakeT.Failed)
153 }
154
155 func TestAssert_WithCarriageReturnInActual(t *testing.T) {
156 filename, clean := setupGoldenFile(t, "a\rfoo\nbar\n")
157 defer clean()
158
159 fakeT := new(fakeT)
160
161 Assert(fakeT, "a\rfoo\r\nbar\r\n", filename)
162 assert.Assert(t, !fakeT.Failed)
163 }
164
165 func TestAssert_WithCarriageReturnInActual_UpdateGolden(t *testing.T) {
166 filename, clean := setupGoldenFile(t, "")
167 defer clean()
168 unsetUpdateFlag := setUpdateFlag(t)
169
170 fakeT := new(fakeT)
171 Assert(fakeT, "a\rfoo\r\nbar\r\n", filename)
172 assert.Assert(t, !fakeT.Failed)
173
174 unsetUpdateFlag()
175 actual := Get(fakeT, filename)
176 assert.Equal(t, string(actual), "a\rfoo\nbar\n")
177
178 Assert(t, "a\rfoo\r\nbar\r\n", filename, "matches with carriage returns")
179 Assert(t, "a\rfoo\nbar\n", filename, "matches without carriage returns")
180 }
181
182 func TestGoldenAssertBytes(t *testing.T) {
183 filename, clean := setupGoldenFile(t, "foo")
184 defer clean()
185
186 fakeT := new(fakeT)
187
188 AssertBytes(fakeT, []byte("foo"), filename)
189 assert.Assert(t, !fakeT.Failed)
190 }
191
192 func setUpdateFlag(t *testing.T) func() {
193 orig := source.Update
194 source.Update = true
195 undo := func() {
196 source.Update = orig
197 }
198 t.Cleanup(undo)
199 return undo
200 }
201
202 func setupGoldenFileWithDir(t *testing.T, dirname, content string) (string, func()) {
203 dirpath := filepath.Join("testdata", dirname)
204 _ = os.MkdirAll(filepath.Join("testdata", dirname), 0755)
205 f, err := os.CreateTemp(dirpath, t.Name()+"-")
206 assert.NilError(t, err, "fail to create test golden file")
207 defer f.Close()
208
209 _, err = f.Write([]byte(content))
210 assert.NilError(t, err)
211
212 return filepath.Base(f.Name()), func() {
213 assert.NilError(t, os.Remove(f.Name()))
214 assert.NilError(t, os.Remove(dirpath))
215 }
216 }
217
218 func setupGoldenFile(t *testing.T, content string) (string, func()) {
219 _ = os.Mkdir("testdata", 0755)
220 f, err := os.CreateTemp("testdata", t.Name()+"-")
221 assert.NilError(t, err, "fail to create test golden file")
222 defer f.Close()
223
224 _, err = f.Write([]byte(content))
225 assert.NilError(t, err)
226
227 return filepath.Base(f.Name()), func() {
228 assert.NilError(t, os.Remove(f.Name()))
229 }
230 }
231
232 func TestStringFailure(t *testing.T) {
233 filename, clean := setupGoldenFile(t, "this is\nthe text")
234 defer clean()
235
236 result := String("this is\nnot the text", filename)()
237 assert.Assert(t, !result.Success())
238 assert.Equal(t, result.(failure).FailureMessage(), `
239 --- expected
240 +++ actual
241 @@ -1,2 +1,2 @@
242 this is
243 -the text
244 +not the text
245 `+failurePostamble(filename))
246 }
247
248 type failure interface {
249 FailureMessage() string
250 }
251
252 func TestBytesFailure(t *testing.T) {
253 filename, clean := setupGoldenFile(t, "5556")
254 defer clean()
255
256 result := Bytes([]byte("5555"), filename)()
257 assert.Assert(t, !result.Success())
258 assert.Equal(t, result.(failure).FailureMessage(),
259 `[53 53 53 53] (actual) != [53 53 53 54] (expected)`+failurePostamble(filename))
260 }
261
262 func TestFlagUpdate(t *testing.T) {
263 assert.Assert(t, !FlagUpdate())
264 setUpdateFlag(t)
265 assert.Assert(t, FlagUpdate())
266 }
267
268 func TestUpdate_CreatesPathsAndFile(t *testing.T) {
269 setUpdateFlag(t)
270
271 dir := fs.NewDir(t, t.Name())
272
273 t.Run("creates the file", func(t *testing.T) {
274 filename := dir.Join("filename")
275 err := update(filename, nil)
276 assert.NilError(t, err)
277
278 _, err = os.Stat(filename)
279 assert.NilError(t, err)
280 })
281
282 t.Run("creates directories", func(t *testing.T) {
283 filename := dir.Join("one/two/filename")
284 err := update(filename, nil)
285 assert.NilError(t, err)
286
287 _, err = os.Stat(filename)
288 assert.NilError(t, err)
289
290 t.Run("no error when directory exists", func(t *testing.T) {
291 err = update(filename, nil)
292 assert.NilError(t, err)
293 })
294 })
295 }
296
View as plain text