v0.3.0 ea9abc7

capturefile_test.go RawHistoryFolder

1package capturefile
2
3import (
4	"errors"
5	"io/fs"
6	"os"
7	"path/filepath"
8	"testing"
9
10	"github.com/bnema/nefercap/internal/ports"
11)
12
13func TestCreateIsExclusiveAndPrivate(t *testing.T) {
14	path := filepath.Join(t.TempDir(), "a")
15	f, res, err := Create(path)
16	if err != nil {
17		t.Fatal(err)
18	}
19	defer f.Close()
20	if info, err := os.Stat(path); err != nil || info.Mode().Perm() != 0o600 {
21		t.Fatalf("mode = %v, err = %v; want 0600", info.Mode(), err)
22	}
23	_, _, err = Create(path)
24	if !errors.Is(err, ports.ErrPathExists) || !errors.Is(err, fs.ErrExist) {
25		t.Fatalf("got %v, want both ErrPathExists and fs.ErrExist", err)
26	}
27	var pe *fs.PathError
28	if !errors.As(err, &pe) {
29		t.Fatalf("path error detail lost: %v", err)
30	}
31	if err := res.Remove(); err != nil {
32		t.Fatal(err)
33	}
34	if _, err := os.Lstat(path); !errors.Is(err, fs.ErrNotExist) {
35		t.Fatalf("own file not removed: %v", err)
36	}
37	if err := res.Remove(); err != nil {
38		t.Fatalf("second Remove: %v", err)
39	}
40}
41
42func TestCreateRefusesSymlink(t *testing.T) {
43	dir := t.TempDir()
44	link := filepath.Join(dir, "link")
45	if err := os.Symlink(filepath.Join(dir, "target"), link); err != nil {
46		t.Skip(err)
47	}
48	if _, _, err := Create(link); !errors.Is(err, ports.ErrPathExists) {
49		t.Fatalf("got %v", err)
50	}
51	if _, err := os.Lstat(filepath.Join(dir, "target")); !errors.Is(err, fs.ErrNotExist) {
52		t.Fatalf("symlink target created: %v", err)
53	}
54}
55
56func TestCreateOtherErrorsAreNotPathExists(t *testing.T) {
57	_, _, err := Create(filepath.Join(t.TempDir(), "missing", "a"))
58	if err == nil || errors.Is(err, ports.ErrPathExists) {
59		t.Fatalf("got %v", err)
60	}
61}
62
63func TestRemoveLeavesReplacement(t *testing.T) {
64	dir := t.TempDir()
65	path := filepath.Join(dir, "a")
66	f, res, err := Create(path)
67	if err != nil {
68		t.Fatal(err)
69	}
70	defer f.Close()
71	moved := filepath.Join(dir, "moved")
72	if err := os.Rename(path, moved); err != nil {
73		t.Fatal(err)
74	}
75	for name, replace := range map[string]func() error{
76		"file":    func() error { return os.WriteFile(path, []byte("user"), 0o600) },
77		"symlink": func() error { return os.Symlink(moved, path) },
78	} {
79		if err := replace(); err != nil {
80			t.Fatal(err)
81		}
82		if err := res.Remove(); err != nil {
83			t.Fatalf("%s: %v", name, err)
84		}
85		if _, err := os.Lstat(path); err != nil {
86			t.Fatalf("%s replacement was removed: %v", name, err)
87		}
88		if err := os.Remove(path); err != nil {
89			t.Fatal(err)
90		}
91	}
92	if _, err := os.Lstat(moved); err != nil {
93		t.Fatalf("moved original touched: %v", err)
94	}
95}
96
97func TestOwnsOnlyTheReservedFile(t *testing.T) {
98	dir := t.TempDir()
99	path := filepath.Join(dir, "a")
100	f, res, err := Create(path)
101	if err != nil {
102		t.Fatal(err)
103	}
104	defer f.Close()
105	if !res.Owns() {
106		t.Fatal("reserved file not owned")
107	}
108	if err := os.Rename(path, filepath.Join(dir, "moved")); err != nil {
109		t.Fatal(err)
110	}
111	if res.Owns() {
112		t.Fatal("missing path reported as owned")
113	}
114	if err := os.WriteFile(path, []byte("user"), 0o600); err != nil {
115		t.Fatal(err)
116	}
117	if res.Owns() {
118		t.Fatal("replacement reported as owned")
119	}
120}

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 2

Tags 9

↑↓ moveenter openesc close