v0.3.0 99dc266

batchwriter_test.go RawHistoryFolder

1package term
2
3import (
4	"errors"
5	"testing"
6)
7
8// recordingWriter records each Write call it receives, copying the bytes
9// so later mutations by the caller (e.g. buffer reuse) don't corrupt the
10// recorded history.
11type recordingWriter struct {
12	writes   [][]byte
13	failNext bool
14}
15
16func (r *recordingWriter) Write(p []byte) (int, error) {
17	if r.failNext {
18		r.failNext = false
19		return 0, errors.New("boom")
20	}
21	cp := make([]byte, len(p))
22	copy(cp, p)
23	r.writes = append(r.writes, cp)
24	return len(p), nil
25}
26
27func (r *recordingWriter) all() []byte {
28	var out []byte
29	for _, w := range r.writes {
30		out = append(out, w...)
31	}
32	return out
33}
34
35func TestBatchWriter_BufferedUntilFlush(t *testing.T) {
36	rw := &recordingWriter{}
37	bw := newBatchWriter(rw, 64)
38
39	n, err := bw.Write([]byte("hello"))
40	if err != nil || n != 5 {
41		t.Fatalf("Write() = %d, %v; want 5, nil", n, err)
42	}
43	if len(rw.writes) != 0 {
44		t.Fatalf("expected no writes reaching sink before Flush, got %d", len(rw.writes))
45	}
46	if got := bw.Buffered(); got != 5 {
47		t.Fatalf("Buffered() = %d, want 5", got)
48	}
49
50	if err := bw.Flush(); err != nil {
51		t.Fatalf("Flush() = %v, want nil", err)
52	}
53	if got := string(rw.all()); got != "hello" {
54		t.Fatalf("sink got %q, want %q", got, "hello")
55	}
56	if got := bw.Buffered(); got != 0 {
57		t.Fatalf("Buffered() after Flush = %d, want 0", got)
58	}
59}
60
61func TestBatchWriter_MultipleWritesCoalesceUntilFlush(t *testing.T) {
62	rw := &recordingWriter{}
63	bw := newBatchWriter(rw, 64)
64
65	for _, s := range []string{"a", "b", "c"} {
66		if _, err := bw.WriteString(s); err != nil {
67			t.Fatalf("WriteString(%q): %v", s, err)
68		}
69	}
70	if len(rw.writes) != 0 {
71		t.Fatalf("expected 0 writes to sink before Flush, got %d", len(rw.writes))
72	}
73
74	if err := bw.Flush(); err != nil {
75		t.Fatalf("Flush(): %v", err)
76	}
77	if got := string(rw.all()); got != "abc" {
78		t.Fatalf("sink got %q, want %q", got, "abc")
79	}
80	// bufio.Writer.Flush issues a single underlying Write.
81	if len(rw.writes) != 1 {
82		t.Fatalf("expected exactly 1 write to sink on Flush, got %d", len(rw.writes))
83	}
84}
85
86func TestBatchWriter_LargeWritePassesThrough(t *testing.T) {
87	rw := &recordingWriter{}
88	bw := newBatchWriter(rw, 8) // small buffer
89
90	big := make([]byte, 64)
91	for i := range big {
92		big[i] = 'x'
93	}
94
95	n, err := bw.Write(big)
96	if err != nil || n != len(big) {
97		t.Fatalf("Write(big) = %d, %v; want %d, nil", n, err, len(big))
98	}
99	// A write larger than the buffer bypasses buffering entirely.
100	if len(rw.writes) == 0 {
101		t.Fatalf("expected large write to pass through immediately, got 0 sink writes")
102	}
103	if got := string(rw.all()); got != string(big) {
104		t.Fatalf("sink content mismatch: got %d bytes, want %d bytes", len(got), len(big))
105	}
106}
107
108func TestBatchWriter_FlushPropagatesError(t *testing.T) {
109	rw := &recordingWriter{failNext: true}
110	bw := newBatchWriter(rw, 64)
111
112	if _, err := bw.WriteString("x"); err != nil {
113		t.Fatalf("WriteString: %v", err)
114	}
115	if err := bw.Flush(); err == nil {
116		t.Fatalf("expected Flush error, got nil")
117	}
118}
119
120func TestBatchWriter_FlushOnEmptyBufferIsNoop(t *testing.T) {
121	rw := &recordingWriter{}
122	bw := newBatchWriter(rw, 64)
123
124	if err := bw.Flush(); err != nil {
125		t.Fatalf("Flush() on empty buffer: %v", err)
126	}
127	if len(rw.writes) != 0 {
128		t.Fatalf("expected no sink writes, got %d", len(rw.writes))
129	}
130}

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 12

Tags 11

↑↓ moveenter openesc close