turbo-editors/turbo-corepublic Fork 0
28d59854361aeda8541d853093e732126f3d7bff
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

edit_test.go · 232 lines · 5.7 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 20h ago1package buffer
2
3import "testing"
4
5func TestInsertPutsTextAtTheCursor(t *testing.T) {
6 b := NewFromString("ab")
7 b.SetCursor(Position{Line: 0, Col: 1})
8
9 b.Insert("X")
10
11 if got := b.Line(0); got != "aXb" {
12 t.Errorf("Line(0) = %q, want %q", got, "aXb")
13 }
14 if got := b.Cursor(); got != (Position{Line: 0, Col: 2}) {
15 t.Errorf("Cursor() = %+v, want the position just after the inserted text", got)
16 }
17 if !b.Modified() {
18 t.Error("inserting must mark the buffer modified")
19 }
20}
21
22func TestInsertSplitsTheLineOnALineFeed(t *testing.T) {
23 b := NewFromString("ab")
24 b.SetCursor(Position{Line: 0, Col: 1})
25
26 b.Insert("1\n2")
27
28 want := []string{"a1", "2b"}
29 if got := b.LineCount(); got != len(want) {
30 t.Fatalf("LineCount() = %d, want %d", got, len(want))
31 }
32 for i, w := range want {
33 if got := b.Line(i); got != w {
34 t.Errorf("Line(%d) = %q, want %q", i, got, w)
35 }
36 }
37 if got := b.Cursor(); got != (Position{Line: 1, Col: 1}) {
38 t.Errorf("Cursor() = %+v, want {Line:1 Col:1}", got)
39 }
40}
41
42func TestInsertReplacesTheSelection(t *testing.T) {
43 b := NewFromString("hello world")
44 b.SetCursor(Position{Line: 0, Col: 0})
45 b.StartSelection()
46 b.SetCursorKeepingSelection(Position{Line: 0, Col: 5})
47
48 b.Insert("bye")
49
50 if got := b.Line(0); got != "bye world" {
51 t.Errorf("Line(0) = %q, want %q", got, "bye world")
52 }
53 if _, ok := b.Selection(); ok {
54 t.Error("the selection must be gone after typing over it")
55 }
56}
57
58func TestInsertNewlineAndIndentCarriesTheLeadingWhitespace(t *testing.T) {
59 tests := []struct {
60 name string
61 line string
62 col int
63 wantNext string
64 }{
65 {"tab indent", "\tfoo()", 6, "\t"},
66 {"space indent", " foo()", 9, " "},
67 {"no indent", "foo()", 5, ""},
68 {"cursor inside the indent", "\t\tfoo()", 1, "\t"},
69 }
70
71 for _, tc := range tests {
72 t.Run(tc.name, func(t *testing.T) {
73 b := NewFromString(tc.line)
74 b.SetCursor(Position{Line: 0, Col: tc.col})
75
76 b.InsertNewlineAndIndent()
77
78 if got := b.LineCount(); got != 2 {
79 t.Fatalf("LineCount() = %d, want 2", got)
80 }
81 if got := b.Line(1); got[:len(tc.wantNext)] != tc.wantNext {
82 t.Errorf("Line(1) = %q, want it to start with %q", got, tc.wantNext)
83 }
84 if got := b.Cursor().Col; got != len(tc.wantNext) {
85 t.Errorf("Cursor().Col = %d, want %d (just past the indent)", got, len(tc.wantNext))
86 }
87 })
88 }
89}
90
91func TestBackspaceRemovesTheCharacterBefore(t *testing.T) {
92 b := NewFromString("abc")
93 b.SetCursor(Position{Line: 0, Col: 2})
94
95 b.Backspace()
96
97 if got := b.Line(0); got != "ac" {
98 t.Errorf("Line(0) = %q, want %q", got, "ac")
99 }
100 if got := b.Cursor(); got != (Position{Line: 0, Col: 1}) {
101 t.Errorf("Cursor() = %+v, want {Line:0 Col:1}", got)
102 }
103}
104
105func TestBackspaceAtColumnZeroJoinsTheLines(t *testing.T) {
106 b := NewFromString("ab\ncd")
107 b.SetCursor(Position{Line: 1, Col: 0})
108
109 b.Backspace()
110
111 if got := b.LineCount(); got != 1 {
112 t.Fatalf("LineCount() = %d, want 1", got)
113 }
114 if got := b.Line(0); got != "abcd" {
115 t.Errorf("Line(0) = %q, want %q", got, "abcd")
116 }
117 if got := b.Cursor(); got != (Position{Line: 0, Col: 2}) {
118 t.Errorf("Cursor() = %+v, want the join point", got)
119 }
120}
121
122func TestBackspaceAtTheStartOfTheBufferDoesNothing(t *testing.T) {
123 b := NewFromString("abc")
124 b.SetCursor(Position{})
125
126 b.Backspace()
127
128 if got := b.Text(); got != "abc" {
129 t.Errorf("Text() = %q, want it unchanged", got)
130 }
131 if b.Modified() {
132 t.Error("a backspace that changed nothing must not mark the buffer modified")
133 }
134}
135
136func TestDeleteRemovesTheCharacterUnderTheCursor(t *testing.T) {
137 b := NewFromString("abc")
138 b.SetCursor(Position{Line: 0, Col: 1})
139
140 b.Delete()
141
142 if got := b.Line(0); got != "ac" {
143 t.Errorf("Line(0) = %q, want %q", got, "ac")
144 }
145 if got := b.Cursor(); got != (Position{Line: 0, Col: 1}) {
146 t.Errorf("Cursor() = %+v, want it to stay put", got)
147 }
148}
149
150func TestDeleteAtTheEndOfALineJoinsTheNextOne(t *testing.T) {
151 b := NewFromString("ab\ncd")
152 b.SetCursor(Position{Line: 0, Col: 2})
153
154 b.Delete()
155
156 if got := b.Text(); got != "abcd" {
157 t.Errorf("Text() = %q, want %q", got, "abcd")
158 }
159}
160
161func TestDeleteAtTheEndOfTheBufferDoesNothing(t *testing.T) {
162 b := NewFromString("ab")
163 b.MoveBufferEnd()
164
165 b.Delete()
166
167 if got := b.Text(); got != "ab" {
168 t.Errorf("Text() = %q, want it unchanged", got)
169 }
170 if b.Modified() {
171 t.Error("a delete that changed nothing must not mark the buffer modified")
172 }
173}
174
175func TestDeleteRangeAcrossSeveralLines(t *testing.T) {
176 b := NewFromString("one\ntwo\nthree")
177
178 b.DeleteRange(Range{
179 Start: Position{Line: 0, Col: 1},
180 End: Position{Line: 2, Col: 2},
181 })
182
183 if got := b.LineCount(); got != 1 {
184 t.Fatalf("LineCount() = %d, want 1", got)
185 }
186 if got := b.Line(0); got != "oree" {
187 t.Errorf("Line(0) = %q, want %q", got, "oree")
188 }
189}
190
191func TestReplaceRangeClampsOutOfBoundsPositions(t *testing.T) {
192 b := NewFromString("abc")
193
194 end := b.ReplaceRange(Range{
195 Start: Position{Line: -5, Col: -5},
196 End: Position{Line: 99, Col: 99},
197 }, "z")
198
199 if got := b.Text(); got != "z" {
200 t.Errorf("Text() = %q, want %q", got, "z")
201 }
202 if end != (Position{Line: 0, Col: 1}) {
203 t.Errorf("ReplaceRange returned %+v, want {Line:0 Col:1}", end)
204 }
205}
206
207func TestReplaceRangeAcceptsReversedBounds(t *testing.T) {
208 b := NewFromString("abcd")
209
210 b.ReplaceRange(Range{
211 Start: Position{Line: 0, Col: 3},
212 End: Position{Line: 0, Col: 1},
213 }, "-")
214
215 if got := b.Line(0); got != "a-d" {
216 t.Errorf("Line(0) = %q, want %q", got, "a-d")
217 }
218}
219
220func TestReplaceRangeDoesNotAliasTheInsertedText(t *testing.T) {
221 b := NewFromString("x")
222
223 // Two successive edits must not share memory through the internal line
224 // slices, or the second would corrupt the first.
225 b.ReplaceRange(Range{}, "one\ntwo\nthree")
226 b.ReplaceRange(Range{Start: Position{Line: 1}, End: Position{Line: 1, Col: 3}}, "TWO")
227
228 want := "one\nTWO\nthreex"
229 if got := b.Text(); got != want {
230 t.Errorf("Text() = %q, want %q", got, want)
231 }
232}