main de06cbd

treediff_test.go RawHistoryFolder

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}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 2

↑↓ moveenter openesc close