turbo-editors/turbo-corepublic Fork 0
v1.0.2
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.

file_test.go · 341 lines · 8.7 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 16h ago1package buffer
2
3import (
4 "errors"
5 "os"
6 "path/filepath"
7 "testing"
8)
9
10func TestOpenReadsTheFile(t *testing.T) {
11 path := filepath.Join(t.TempDir(), "main.go")
12 writeTestFile(t, path, "package main\n\nfunc main() {}\n")
13
14 b, err := Open(path)
15 if err != nil {
16 t.Fatalf("Open() error = %v", err)
17 }
18
19 if got := b.LineCount(); got != 3 {
20 t.Errorf("LineCount() = %d, want 3", got)
21 }
22 if got := b.Path(); got != path {
23 t.Errorf("Path() = %q, want %q", got, path)
24 }
25 if b.Modified() {
26 t.Error("a freshly opened buffer must not be modified")
27 }
28 if b.CanUndo() {
29 t.Error("opening a file must not leave anything to undo")
30 }
31}
32
33func TestOpenAMissingFileGivesAnEmptyBuffer(t *testing.T) {
34 path := filepath.Join(t.TempDir(), "new.go")
35
36 b, err := Open(path)
37 if err != nil {
38 t.Fatalf("Open() error = %v, want nil for a file that does not exist yet", err)
39 }
40
41 if got := b.LineCount(); got != 1 {
42 t.Errorf("LineCount() = %d, want 1", got)
43 }
44 if got := b.Path(); got != path {
45 t.Errorf("Path() = %q, want the requested path", got)
46 }
47 if b.Modified() {
48 t.Error("an empty new buffer must not be modified")
49 }
50}
51
52func TestOpenADirectoryFails(t *testing.T) {
53 if _, err := Open(t.TempDir()); err == nil {
54 t.Fatal("Open() error = nil, want a failure when the path is a directory")
55 }
56}
57
58func TestSaveWritesTheTextBack(t *testing.T) {
59 path := filepath.Join(t.TempDir(), "main.go")
60 writeTestFile(t, path, "package main\n")
61
62 b, err := Open(path)
63 if err != nil {
64 t.Fatalf("Open() error = %v", err)
65 }
66 b.MoveBufferEnd()
67 b.Insert("\nfunc main() {}")
68
69 if err := b.Save(); err != nil {
70 t.Fatalf("Save() error = %v", err)
71 }
72 if b.Modified() {
73 t.Error("Save must clear the modified flag")
74 }
75
76 want := "package main\nfunc main() {}\n"
77 if got := readTestFile(t, path); got != want {
78 t.Errorf("file content = %q, want %q", got, want)
79 }
80}
81
82func TestSaveRoundTripsAnUnmodifiedFileByteForByte(t *testing.T) {
83 tests := []struct {
84 name string
85 content string
86 }{
87 {"unix endings", "a\nb\n"},
88 {"windows endings", "a\r\nb\r\n"},
89 {"no trailing newline", "a\nb"},
90 {"empty file", ""},
91 }
92
93 for _, tc := range tests {
94 t.Run(tc.name, func(t *testing.T) {
95 path := filepath.Join(t.TempDir(), "f.txt")
96 writeTestFile(t, path, tc.content)
97
98 b, err := Open(path)
99 if err != nil {
100 t.Fatalf("Open() error = %v", err)
101 }
102 if err := b.Save(); err != nil {
103 t.Fatalf("Save() error = %v", err)
104 }
105
106 if got := readTestFile(t, path); got != tc.content {
107 t.Errorf("file content = %q, want %q", got, tc.content)
108 }
109 })
110 }
111}
112
113func TestSaveWithoutAPathReportsErrNoPath(t *testing.T) {
114 b := NewFromString("orphan")
115
116 err := b.Save()
117
118 if !errors.Is(err, ErrNoPath) {
119 t.Errorf("Save() error = %v, want ErrNoPath", err)
120 }
121}
122
123func TestSaveAsAdoptsTheNewPath(t *testing.T) {
124 dir := t.TempDir()
125 path := filepath.Join(dir, "copy.go")
126 b := NewFromString("package main\n")
127
128 if err := b.SaveAs(path); err != nil {
129 t.Fatalf("SaveAs() error = %v", err)
130 }
131
132 if got := b.Path(); got != path {
133 t.Errorf("Path() = %q, want %q", got, path)
134 }
135 if got := readTestFile(t, path); got != "package main\n" {
136 t.Errorf("file content = %q", got)
137 }
138 if entries, _ := os.ReadDir(dir); len(entries) != 1 {
139 t.Errorf("the directory holds %d entries, want 1 — the temporary file must be gone", len(entries))
140 }
141}
142
143func TestSaveKeepsTheExistingFilePermissions(t *testing.T) {
144 path := filepath.Join(t.TempDir(), "script.go")
145 writeTestFile(t, path, "package main\n")
146 if err := os.Chmod(path, 0o640); err != nil {
147 t.Fatalf("Chmod() error = %v", err)
148 }
149
150 b, err := Open(path)
151 if err != nil {
152 t.Fatalf("Open() error = %v", err)
153 }
154 if err := b.Save(); err != nil {
155 t.Fatalf("Save() error = %v", err)
156 }
157
158 info, err := os.Stat(path)
159 if err != nil {
160 t.Fatalf("Stat() error = %v", err)
161 }
162 if got := info.Mode().Perm(); got != 0o640 {
163 t.Errorf("permissions = %o, want 640 — the atomic rename must not tighten them", got)
164 }
165}
166
167func TestSaveIntoAMissingDirectoryFails(t *testing.T) {
168 b := NewFromString("x")
169
170 err := b.SaveAs(filepath.Join(t.TempDir(), "nope", "f.go"))
171
172 if err == nil {
173 t.Fatal("SaveAs() error = nil, want a failure when the directory does not exist")
174 }
175 if b.Path() != "" {
176 t.Errorf("Path() = %q, want it left alone after a failed save", b.Path())
177 }
178}
179
180func TestModeOfFallsBackForAMissingFile(t *testing.T) {
181 if got := modeOf(filepath.Join(t.TempDir(), "absent")); got != defaultFileMode {
182 t.Errorf("modeOf(missing) = %o, want %o", got, defaultFileMode)
183 }
184}
185
186// writeTestFile creates a file with the given content, failing the test if it
187// cannot.
188func writeTestFile(t *testing.T, path, content string) {
189 t.Helper()
190 if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
191 t.Fatalf("writing %s: %v", path, err)
192 }
193}
194
195// readTestFile returns the content of a file, failing the test if it cannot.
196func readTestFile(t *testing.T, path string) string {
197 t.Helper()
198 data, err := os.ReadFile(path)
199 if err != nil {
200 t.Fatalf("reading %s: %v", path, err)
201 }
202 return string(data)
203}
204
205func TestReloadPicksUpAChangeMadeOnDisk(t *testing.T) {
206 // What a formatter run from the Go menu leaves behind.
207 path := filepath.Join(t.TempDir(), "main.go")
208 writeTestFile(t, path, "package main\n")
209 b, err := Open(path)
210 if err != nil {
211 t.Fatalf("Open() error = %v", err)
212 }
213
214 writeTestFile(t, path, "package main\n\nfunc main() {}\n")
215 changed, err := b.Reload()
216
217 if err != nil {
218 t.Fatalf("Reload() error = %v", err)
219 }
220 if !changed {
221 t.Error("Reload() reported no change for a file that was rewritten")
222 }
223 if got := b.Text(); got != "package main\n\nfunc main() {}\n" {
224 t.Errorf("the buffer holds %q", got)
225 }
226 if b.Modified() {
227 t.Error("a reloaded buffer reports itself modified")
228 }
229}
230
231func TestReloadReportsNoChangeWhenTheFileIsTheSame(t *testing.T) {
232 // A caller uses this to tell a file something rewrote from one it did not.
233 path := filepath.Join(t.TempDir(), "main.go")
234 writeTestFile(t, path, "package main\n")
235 b, _ := Open(path)
236
237 changed, err := b.Reload()
238
239 if err != nil {
240 t.Fatalf("Reload() error = %v", err)
241 }
242 if changed {
243 t.Error("Reload() reported a change for a file nobody touched")
244 }
245}
246
247func TestReloadRefusesToThrowAwayUnsavedWork(t *testing.T) {
248 path := filepath.Join(t.TempDir(), "main.go")
249 writeTestFile(t, path, "package main\n")
250 b, _ := Open(path)
251 b.Insert("// mine")
252 before := b.Text()
253
254 writeTestFile(t, path, "something else\n")
255 _, err := b.Reload()
256
257 if !errors.Is(err, ErrModified) {
258 t.Fatalf("Reload() error = %v, want ErrModified", err)
259 }
260 if got := b.Text(); got != before {
261 t.Errorf("the buffer was reloaded anyway: %q", got)
262 }
263}
264
265func TestReloadKeepsTheCursorWhereItWas(t *testing.T) {
266 // A formatter moves lines about; putting the cursor back at the top would
267 // lose the reader's place for no reason.
268 path := filepath.Join(t.TempDir(), "main.go")
269 writeTestFile(t, path, "one\ntwo\nthree\n")
270 b, _ := Open(path)
271 b.SetCursor(Position{Line: 1, Col: 2})
272
273 if _, err := b.Reload(); err != nil {
274 t.Fatalf("Reload() error = %v", err)
275 }
276 writeTestFile(t, path, "one\nTWO!\nthree\n")
277 if _, err := b.Reload(); err != nil {
278 t.Fatalf("Reload() error = %v", err)
279 }
280
281 if got := b.Cursor(); got.Line != 1 || got.Col != 2 {
282 t.Errorf("Cursor() = %+v, want line 1 column 2", got)
283 }
284}
285
286func TestReloadClampsACursorPastTheEndOfTheNewFile(t *testing.T) {
287 path := filepath.Join(t.TempDir(), "main.go")
288 writeTestFile(t, path, "one\ntwo\nthree\nfour\n")
289 b, _ := Open(path)
290 b.SetCursor(Position{Line: 3, Col: 4})
291
292 writeTestFile(t, path, "one\n")
293 if _, err := b.Reload(); err != nil {
294 t.Fatalf("Reload() error = %v", err)
295 }
296
297 cursor := b.Cursor()
298 if cursor.Line >= b.LineCount() {
299 t.Errorf("Cursor() = %+v, past the end of a %d-line file", cursor, b.LineCount())
300 }
301}
302
303func TestReloadForgetsTheUndoHistory(t *testing.T) {
304 // Undoing back past a reload would restore text the file no longer has.
305 path := filepath.Join(t.TempDir(), "main.go")
306 writeTestFile(t, path, "one\n")
307 b, _ := Open(path)
308 b.Insert("x")
309 if err := b.Save(); err != nil {
310 t.Fatalf("Save() error = %v", err)
311 }
312
313 writeTestFile(t, path, "reformatted\n")
314 if _, err := b.Reload(); err != nil {
315 t.Fatalf("Reload() error = %v", err)
316 }
317 b.Undo()
318
319 if got := b.Text(); got != "reformatted\n" {
320 t.Errorf("undo after a reload gave %q", got)
321 }
322}
323
324func TestReloadWithNoPathSaysSo(t *testing.T) {
325 if _, err := New().Reload(); !errors.Is(err, ErrNoPath) {
326 t.Errorf("Reload() error = %v, want ErrNoPath", err)
327 }
328}
329
330func TestReloadOfAFileThatHasGoneIsAnError(t *testing.T) {
331 path := filepath.Join(t.TempDir(), "main.go")
332 writeTestFile(t, path, "package main\n")
333 b, _ := Open(path)
334
335 if err := os.Remove(path); err != nil {
336 t.Fatalf("removing the file: %v", err)
337 }
338 if _, err := b.Reload(); err == nil {
339 t.Error("Reload() accepted a file that no longer exists")
340 }
341}