1// SPDX-License-Identifier: MIT
2
3package git
4
5import (
6 "errors"
7 "testing"
8)
9
10func TestParsePathSpec(t *testing.T) {
11 cases := []struct {
12 in string
13 want string
14 bloom bool
15 bad bool
16 }{
17 {"a/b/c", "a/b/c", true, false},
18 {"a/b/", "a/b", true, false},
19 {"a", "a", true, false},
20 {"a//b", "a/b", false, false},
21 {"a/b//", "a/b", false, false},
22 {"./a", "a", false, false},
23 {"a/./b", "a/b", false, false},
24 {"a/b/../c", "a/c", false, false},
25 {".", "", false, false},
26 {"./", "", false, false},
27 {"", "", false, false},
28 {"a/..", "", false, false},
29 {"../a", "", false, true},
30 {"/a", "", false, true},
31 {"a\x00b", "", false, true},
32 }
33 for _, c := range cases {
34 s, err := parsePathSpec(c.in)
35 if c.bad {
36 if !errors.Is(err, ErrInvalidPath) {
37 t.Errorf("%q: err = %v, want ErrInvalidPath", c.in, err)
38 }
39 continue
40 }
41 if err != nil {
42 t.Errorf("%q: %v", c.in, err)
43 continue
44 }
45 if s.String() != c.want || s.bloom != c.bloom {
46 t.Errorf("%q: got %q bloom=%v, want %q bloom=%v", c.in, s.String(), s.bloom, c.want, c.bloom)
47 }
48 }
49}
50
51func TestEmptyTreeID(t *testing.T) {
52 want := "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
53 if got := emptyTreeID.String(); got != want {
54 t.Fatalf("emptyTreeID = %s", got)
55 }
56}
57
58// TestPathDiffer checks same and exists against git rev-parse on trees that
59// turn files into directories and back.
60func TestPathDiffer(t *testing.T) {
61 f := newFx(t)
62 var trees []ObjectID
63 step := func(setup func()) {
64 setup()
65 f.commit("c")
66 trees = append(trees, mustID(t, f.git("rev-parse", "HEAD^{tree}")))
67 }
68 step(func() { f.write("a", []byte("file"), 0o644); f.write("d/x", []byte("1"), 0o644) })
69 step(func() { f.write("a", []byte("file2"), 0o644) })
70 step(func() { f.git("rm", "-q", "a"); f.write("a/b", []byte("1"), 0o644) })
71 step(func() { f.write("a/b", []byte("2"), 0o644); f.write("d/y", []byte("1"), 0o644) })
72 step(func() { f.write("a/b", []byte("2"), 0o755) })
73 r := f.open()
74 for _, p := range []string{"a", "a/b", "a/b/c", "d", "d/x", "d/y", "zz", ""} {
75 spec, err := parsePathSpec(p)
76 if err != nil {
77 t.Fatal(err)
78 }
79 d := newPathDiffer(r, spec)
80 for i := range trees {
81 for j := range trees {
82 got, err := d.same(trees[i], trees[j])
83 if err != nil {
84 t.Fatal(err)
85 }
86 want := f.git("diff-tree", "-r", "--name-only", trees[i].String(), trees[j].String(), "--", orDot(p)) == ""
87 if got != want {
88 t.Errorf("same(%d,%d,%q) = %v, git says %v", i, j, p, got, want)
89 }
90 }
91 ex, err := d.exists(trees[i])
92 if err != nil {
93 t.Fatal(err)
94 }
95 want := f.git("ls-tree", "-r", "--name-only", trees[i].String(), "--", orDot(p)) != ""
96 if p == "" {
97 want = true
98 }
99 if ex != want {
100 t.Errorf("exists(%d,%q) = %v, git says %v", i, p, ex, want)
101 }
102 }
103 }
104}
105
106func orDot(p string) string {
107 if p == "" {
108 return "."
109 }
110 return p
111}