cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.43.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/git/changes_test.go

582lines · modecode

1package git_test
2
3import (
4 "fmt"
5 "os"
6 "strings"
7 "testing"
8
9 "github.com/stretchr/testify/require"
10
11 "github.com/cloudflare/pint/internal/git"
12)
13
14func debugGitRun(t *testing.T) git.CommandRunner {
15 return func(args ...string) ([]byte, error) {
16 out, err := git.RunGit(args...)
17 if err == nil {
18 if len(out) == 0 {
19 t.Logf("%s ~> no stdout", strings.Join(args, " "))
20 } else {
21 t.Logf("%s\n---\n%s---", strings.Join(args, " "), string(out))
22 }
23 }
24 return out, err
25 }
26}
27
28func mustRun(t *testing.T, args ...string) {
29 _, err := debugGitRun(t)(args...)
30 require.NoError(t, err, strings.Join(args, " "))
31}
32
33func gitCommit(t *testing.T, message string) {
34 t.Setenv("GIT_AUTHOR_NAME", "pint")
35 t.Setenv("GIT_AUTHOR_EMAIL", "pint@example.com")
36 t.Setenv("GIT_COMMITTER_NAME", "pint")
37 t.Setenv("GIT_COMMITTER_EMAIL", "pint")
38 mustRun(t, "commit", "-am", fmt.Sprintf("commit %s", message))
39}
40
41func TestChanges(t *testing.T) {
42 type testCaseT struct {
43 title string
44 setup func(t *testing.T) (git.CommandRunner, git.CommitRangeResults)
45 changes []*git.FileChange
46 err string
47 }
48
49 testCases := []testCaseT{
50 {
51 title: "git log error",
52 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
53 cmd := func(args ...string) ([]byte, error) {
54 return nil, fmt.Errorf("mock git error: %v", args)
55 }
56 cr := git.CommitRangeResults{From: "a", To: "b"}
57 return cmd, cr
58 },
59 changes: nil,
60 err: "failed to get the list of modified files from git: mock git error: [log --reverse --no-merges --format=%H --name-status a^..b]",
61 },
62 {
63 title: "chmod",
64 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
65 mustRun(t, "init", "--initial-branch=main", ".")
66 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
67 mustRun(t, "add", "index.txt")
68 gitCommit(t, "init")
69
70 mustRun(t, "checkout", "-b", "v2")
71 require.NoError(t, os.Chmod("index.txt", 0o755))
72 mustRun(t, "add", "index.txt")
73 gitCommit(t, "chmod")
74
75 cr, err := git.CommitRange(debugGitRun(t), "main")
76 require.NoError(t, err)
77 return debugGitRun(t), cr
78 },
79 changes: []*git.FileChange{
80 {
81 Path: git.PathDiff{
82 Before: git.Path{
83 Name: "index.txt",
84 Type: git.File,
85 },
86 After: git.Path{
87 Name: "index.txt",
88 Type: git.File,
89 },
90 },
91 Body: git.BodyDiff{
92 Before: []byte("foo"),
93 After: []byte("foo"),
94 ModifiedLines: []int{},
95 },
96 },
97 },
98 err: "",
99 },
100 {
101 title: "dir -> file",
102 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
103 mustRun(t, "init", "--initial-branch=main", ".")
104 require.NoError(t, os.Mkdir("index.txt", 0o755))
105 require.NoError(t, os.WriteFile("index.txt/.keep", []byte("keep"), 0o644))
106 mustRun(t, "add", "index.txt")
107 gitCommit(t, "init")
108
109 mustRun(t, "checkout", "-b", "v2")
110 require.NoError(t, os.RemoveAll("index.txt"))
111 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
112 mustRun(t, "add", "index.txt")
113 gitCommit(t, "chmod")
114
115 cr, err := git.CommitRange(debugGitRun(t), "main")
116 require.NoError(t, err)
117 return debugGitRun(t), cr
118 },
119 changes: []*git.FileChange{
120 {
121 Path: git.PathDiff{
122 Before: git.Path{
123 Name: "index.txt",
124 Type: git.Dir,
125 },
126 After: git.Path{
127 Name: "index.txt",
128 Type: git.File,
129 },
130 },
131 Body: git.BodyDiff{
132 Before: nil,
133 After: []byte("foo"),
134 ModifiedLines: []int{1},
135 },
136 },
137 {
138 Path: git.PathDiff{
139 Before: git.Path{
140 Name: "index.txt/.keep",
141 Type: git.File,
142 },
143 After: git.Path{
144 Name: "index.txt/.keep",
145 Type: git.Missing,
146 },
147 },
148 Body: git.BodyDiff{
149 Before: []byte("keep"),
150 After: nil,
151 ModifiedLines: []int{1},
152 },
153 },
154 },
155 err: "",
156 },
157 {
158 title: "add file, delete and re-add",
159 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
160 mustRun(t, "init", "--initial-branch=main", ".")
161 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
162 mustRun(t, "add", "index.txt")
163 gitCommit(t, "init")
164
165 mustRun(t, "checkout", "-b", "v2")
166 require.NoError(t, os.Remove("index.txt"))
167 mustRun(t, "add", "index.txt")
168 gitCommit(t, "rm")
169 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
170 mustRun(t, "add", "index.txt")
171 gitCommit(t, "add")
172
173 cr, err := git.CommitRange(debugGitRun(t), "main")
174 require.NoError(t, err)
175 return debugGitRun(t), cr
176 },
177 changes: []*git.FileChange{
178 {
179 Path: git.PathDiff{
180 Before: git.Path{
181 Name: "index.txt",
182 Type: git.File,
183 },
184 After: git.Path{
185 Name: "index.txt",
186 Type: git.File,
187 },
188 },
189 Body: git.BodyDiff{
190 Before: []byte("foo"),
191 After: []byte("foo"),
192 ModifiedLines: []int{1},
193 },
194 },
195 },
196 err: "",
197 },
198 {
199 title: "file -> symlink",
200 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
201 mustRun(t, "init", "--initial-branch=main", ".")
202 require.NoError(t, os.WriteFile("index.txt", []byte("foo\n1\n"), 0o644))
203 mustRun(t, "add", "index.txt")
204 require.NoError(t, os.WriteFile("second file.txt", []byte("bar\n1\n"), 0o644))
205 mustRun(t, "add", "second file.txt")
206 gitCommit(t, "init")
207
208 mustRun(t, "checkout", "-b", "v2")
209 require.NoError(t, os.Remove("second file.txt"))
210 require.NoError(t, os.Symlink("index.txt", "second file.txt"))
211 mustRun(t, "add", "second file.txt")
212 gitCommit(t, "symlink")
213
214 cr, err := git.CommitRange(debugGitRun(t), "main")
215 require.NoError(t, err)
216 return debugGitRun(t), cr
217 },
218 changes: []*git.FileChange{
219 {
220 Path: git.PathDiff{
221 Before: git.Path{
222 Name: "second file.txt",
223 Type: git.File,
224 },
225 After: git.Path{
226 Name: "second file.txt",
227 Type: git.Symlink,
228 SymlinkTarget: "index.txt",
229 },
230 },
231 Body: git.BodyDiff{
232 Before: []byte("bar\n1\n"),
233 After: []byte("foo\n1\n"),
234 ModifiedLines: []int{1, 2},
235 },
236 },
237 },
238 err: "",
239 },
240 {
241 title: "rename partial",
242 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
243 mustRun(t, "init", "--initial-branch=main", ".")
244 require.NoError(t, os.WriteFile("index.txt", []byte("1\n2\n3\n4\n5\n6\n7\n8\n9\n"), 0o644))
245 mustRun(t, "add", "index.txt")
246 gitCommit(t, "init")
247
248 mustRun(t, "checkout", "-b", "v2")
249 mustRun(t, "mv", "index.txt", "second.txt")
250 require.NoError(t, os.WriteFile("second.txt", []byte("1\n2\n3\n4\n5\nX\nX\nX\nX\n"), 0o644))
251 mustRun(t, "add", "second.txt")
252 gitCommit(t, "mv")
253
254 cr, err := git.CommitRange(debugGitRun(t), "main")
255 require.NoError(t, err)
256 return debugGitRun(t), cr
257 },
258 changes: []*git.FileChange{
259 {
260 Path: git.PathDiff{
261 Before: git.Path{
262 Name: "index.txt",
263 Type: git.File,
264 },
265 After: git.Path{
266 Name: "second.txt",
267 Type: git.File,
268 },
269 },
270 Body: git.BodyDiff{
271 Before: []byte("1\n2\n3\n4\n5\n6\n7\n8\n9\n"),
272 After: []byte("1\n2\n3\n4\n5\nX\nX\nX\nX\n"),
273 ModifiedLines: []int{6, 7, 8, 9},
274 },
275 },
276 },
277 err: "",
278 },
279 {
280 title: "rename 100% and edit",
281 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
282 mustRun(t, "init", "--initial-branch=main", ".")
283 require.NoError(t, os.WriteFile("index.txt", []byte("1\n2\n3\n4\n5\n6\n7\n8\n9\n"), 0o644))
284 mustRun(t, "add", "index.txt")
285 gitCommit(t, "init")
286
287 mustRun(t, "checkout", "-b", "v2")
288 mustRun(t, "mv", "index.txt", "second.txt")
289 gitCommit(t, "mv")
290 require.NoError(t, os.WriteFile("second.txt", []byte("1\n2\n3\n4\n5\nX\n7\n8\n9\n"), 0o644))
291 mustRun(t, "add", "second.txt")
292 gitCommit(t, "edit")
293
294 cr, err := git.CommitRange(debugGitRun(t), "main")
295 require.NoError(t, err)
296 return debugGitRun(t), cr
297 },
298 changes: []*git.FileChange{
299 {
300 Path: git.PathDiff{
301 Before: git.Path{
302 Name: "index.txt",
303 Type: git.File,
304 },
305 After: git.Path{
306 Name: "second.txt",
307 Type: git.File,
308 },
309 },
310 Body: git.BodyDiff{
311 Before: []byte("1\n2\n3\n4\n5\n6\n7\n8\n9\n"),
312 After: []byte("1\n2\n3\n4\n5\nX\n7\n8\n9\n"),
313 ModifiedLines: []int{6},
314 },
315 },
316 },
317 err: "",
318 },
319 {
320 title: "add file, add another",
321 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
322 mustRun(t, "init", "--initial-branch=main", ".")
323 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
324 mustRun(t, "add", "index.txt")
325 gitCommit(t, "init")
326
327 mustRun(t, "checkout", "-b", "v2")
328 require.NoError(t, os.WriteFile("second.txt", []byte("second"), 0o644))
329 mustRun(t, "add", "second.txt")
330 require.NoError(t, os.WriteFile("third.txt", []byte("third"), 0o644))
331 mustRun(t, "add", "third.txt")
332 gitCommit(t, "add two more")
333
334 cr, err := git.CommitRange(debugGitRun(t), "main")
335 require.NoError(t, err)
336 return debugGitRun(t), cr
337 },
338 changes: []*git.FileChange{
339 {
340 Path: git.PathDiff{
341 Before: git.Path{
342 Name: "second.txt",
343 Type: git.Missing,
344 },
345 After: git.Path{
346 Name: "second.txt",
347 Type: git.File,
348 },
349 },
350 Body: git.BodyDiff{
351 After: []byte("second"),
352 ModifiedLines: []int{1},
353 },
354 },
355 {
356 Path: git.PathDiff{
357 Before: git.Path{
358 Name: "third.txt",
359 Type: git.Missing,
360 },
361 After: git.Path{
362 Name: "third.txt",
363 Type: git.File,
364 },
365 },
366 Body: git.BodyDiff{
367 After: []byte("third"),
368 ModifiedLines: []int{1},
369 },
370 },
371 },
372 err: "",
373 },
374 {
375 title: "delete file",
376 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
377 mustRun(t, "init", "--initial-branch=main", ".")
378 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
379 mustRun(t, "add", "index.txt")
380 require.NoError(t, os.WriteFile("second.txt", []byte("second"), 0o644))
381 mustRun(t, "add", "second.txt")
382 gitCommit(t, "init")
383
384 mustRun(t, "checkout", "-b", "v2")
385 require.NoError(t, os.Remove("second.txt"))
386 mustRun(t, "add", "second.txt")
387 gitCommit(t, "rm second")
388
389 cr, err := git.CommitRange(debugGitRun(t), "main")
390 require.NoError(t, err)
391 return debugGitRun(t), cr
392 },
393 changes: []*git.FileChange{
394 {
395 Path: git.PathDiff{
396 Before: git.Path{
397 Name: "second.txt",
398 Type: git.File,
399 },
400 After: git.Path{
401 Name: "second.txt",
402 Type: git.Missing,
403 },
404 },
405 Body: git.BodyDiff{
406 Before: []byte("second"),
407 ModifiedLines: []int{1},
408 },
409 },
410 },
411 err: "",
412 },
413 {
414 title: "delete symlink",
415 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
416 mustRun(t, "init", "--initial-branch=main", ".")
417 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
418 mustRun(t, "add", "index.txt")
419 require.NoError(t, os.Symlink("index.txt", "second.txt"))
420 mustRun(t, "add", "second.txt")
421 gitCommit(t, "init")
422
423 mustRun(t, "checkout", "-b", "v2")
424 require.NoError(t, os.Remove("second.txt"))
425 mustRun(t, "add", "second.txt")
426 gitCommit(t, "rm second")
427
428 cr, err := git.CommitRange(debugGitRun(t), "main")
429 require.NoError(t, err)
430 return debugGitRun(t), cr
431 },
432 changes: []*git.FileChange{
433 {
434 Path: git.PathDiff{
435 Before: git.Path{
436 Name: "second.txt",
437 Type: git.Symlink,
438 SymlinkTarget: "index.txt",
439 },
440 After: git.Path{
441 Name: "second.txt",
442 Type: git.Missing,
443 },
444 },
445 Body: git.BodyDiff{
446 Before: []byte("foo"),
447 ModifiedLines: []int{1},
448 },
449 },
450 },
451 err: "",
452 },
453 {
454 title: "delete directory with symlinks",
455 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
456 mustRun(t, "init", "--initial-branch=main", ".")
457 require.NoError(t, os.WriteFile("index.txt", []byte("foo"), 0o644))
458 mustRun(t, "add", "index.txt")
459 require.NoError(t, os.Mkdir("dir", 0o755))
460 require.NoError(t, os.Symlink("../index.txt", "dir/first.txt"))
461 require.NoError(t, os.Symlink("../index.txt", "dir/second.txt"))
462 mustRun(t, "add", "dir")
463 gitCommit(t, "init")
464
465 mustRun(t, "checkout", "-b", "v2")
466 require.NoError(t, os.RemoveAll("dir"))
467 mustRun(t, "add", "dir")
468 gitCommit(t, "rm dir")
469
470 cr, err := git.CommitRange(debugGitRun(t), "main")
471 require.NoError(t, err)
472 return debugGitRun(t), cr
473 },
474 changes: []*git.FileChange{
475 {
476 Path: git.PathDiff{
477 Before: git.Path{
478 Name: "dir/first.txt",
479 Type: git.Symlink,
480 SymlinkTarget: "index.txt",
481 },
482 After: git.Path{
483 Name: "dir/first.txt",
484 Type: git.Missing,
485 },
486 },
487 Body: git.BodyDiff{
488 Before: []byte("foo"),
489 ModifiedLines: []int{1},
490 },
491 },
492 {
493 Path: git.PathDiff{
494 Before: git.Path{
495 Name: "dir/second.txt",
496 Type: git.Symlink,
497 SymlinkTarget: "index.txt",
498 },
499 After: git.Path{
500 Name: "dir/second.txt",
501 Type: git.Missing,
502 },
503 },
504 Body: git.BodyDiff{
505 Before: []byte("foo"),
506 ModifiedLines: []int{1},
507 },
508 },
509 },
510 err: "",
511 },
512 {
513 title: "symlink target changed",
514 setup: func(t *testing.T) (git.CommandRunner, git.CommitRangeResults) {
515 mustRun(t, "init", "--initial-branch=main", ".")
516 require.NoError(t, os.WriteFile("index.txt", []byte("foo\n1\n"), 0o644))
517 mustRun(t, "add", "index.txt")
518 require.NoError(t, os.WriteFile("second file.txt", []byte("bar\n1\n"), 0o644))
519 mustRun(t, "add", "second file.txt")
520 require.NoError(t, os.Mkdir("dir", 0o755))
521 require.NoError(t, os.Symlink("../index.txt", "dir/first.txt"))
522 require.NoError(t, os.Symlink("../second file.txt", "dir/second.txt"))
523 mustRun(t, "add", "dir")
524 gitCommit(t, "init")
525
526 mustRun(t, "checkout", "-b", "v2")
527 require.NoError(t, os.Remove("dir/second.txt"))
528 require.NoError(t, os.Symlink("first.txt", "dir/second.txt"))
529 mustRun(t, "add", "dir")
530 gitCommit(t, "symlink change")
531
532 cr, err := git.CommitRange(debugGitRun(t), "main")
533 require.NoError(t, err)
534 return debugGitRun(t), cr
535 },
536 changes: []*git.FileChange{
537 {
538 Path: git.PathDiff{
539 Before: git.Path{
540 Name: "dir/second.txt",
541 Type: git.Symlink,
542 SymlinkTarget: "second file.txt",
543 },
544 After: git.Path{
545 Name: "dir/second.txt",
546 Type: git.Symlink,
547 SymlinkTarget: "index.txt",
548 },
549 },
550 Body: git.BodyDiff{
551 Before: []byte("bar\n1\n"),
552 After: []byte("foo\n1\n"),
553 ModifiedLines: []int{1, 2},
554 },
555 },
556 },
557 err: "",
558 },
559 }
560
561 for _, tc := range testCases {
562 t.Run(tc.title, func(t *testing.T) {
563 dir := t.TempDir()
564 err := os.Chdir(dir)
565 require.NoError(t, err, "chdir")
566
567 cmd, cr := tc.setup(t)
568 changes, err := git.Changes(cmd, cr)
569 if tc.err != "" {
570 require.EqualError(t, err, tc.err)
571 require.Nil(t, changes)
572 } else {
573 require.NoError(t, err)
574 require.Len(t, changes, len(tc.changes))
575 for i := range tc.changes {
576 require.Equal(t, tc.changes[i].Path, changes[i].Path, "changes[%d].Path", i)
577 require.Equal(t, tc.changes[i].Body, changes[i].Body, "changes[%d].Body", i)
578 }
579 }
580 })
581 }
582}
583