]> git.lizzy.rs Git - micro.git/blob - cmd/micro/micro_test.go
c5b64ef9d77af83fdd5f0f58e540b897c2404877
[micro.git] / cmd / micro / micro_test.go
1 package main
2
3 import (
4         "fmt"
5         "io/ioutil"
6         "log"
7         "os"
8         "testing"
9
10         "github.com/go-errors/errors"
11         "github.com/stretchr/testify/assert"
12         "github.com/zyedidia/micro/v2/internal/action"
13         "github.com/zyedidia/micro/v2/internal/buffer"
14         "github.com/zyedidia/micro/v2/internal/config"
15         "github.com/zyedidia/micro/v2/internal/screen"
16         "github.com/zyedidia/tcell/v2"
17 )
18
19 var tempDir string
20 var sim tcell.SimulationScreen
21
22 func init() {
23         screen.Events = make(chan tcell.Event, 8)
24 }
25
26 func startup(args []string) (tcell.SimulationScreen, error) {
27         var err error
28
29         tempDir, err = ioutil.TempDir("", "micro_test")
30         if err != nil {
31                 return nil, err
32         }
33         err = config.InitConfigDir(tempDir)
34         if err != nil {
35                 return nil, err
36         }
37
38         config.InitRuntimeFiles()
39         err = config.ReadSettings()
40         if err != nil {
41                 return nil, err
42         }
43         err = config.InitGlobalSettings()
44         if err != nil {
45                 return nil, err
46         }
47
48         s, err := screen.InitSimScreen()
49         if err != nil {
50                 return nil, err
51         }
52
53         defer func() {
54                 if err := recover(); err != nil {
55                         screen.Screen.Fini()
56                         fmt.Println("Micro encountered an error:", err)
57                         // backup all open buffers
58                         for _, b := range buffer.OpenBuffers {
59                                 b.Backup()
60                         }
61                         // Print the stack trace too
62                         log.Fatalf(errors.Wrap(err, 2).ErrorStack())
63                         os.Exit(1)
64                 }
65         }()
66
67         err = config.LoadAllPlugins()
68         if err != nil {
69                 screen.TermMessage(err)
70         }
71
72         action.InitBindings()
73         action.InitCommands()
74
75         err = config.InitColorscheme()
76         if err != nil {
77                 return nil, err
78         }
79
80         b := LoadInput(args)
81
82         if len(b) == 0 {
83                 return nil, errors.New("No buffers opened")
84         }
85
86         action.InitTabs(b)
87         action.InitGlobals()
88
89         err = config.RunPluginFn("init")
90         if err != nil {
91                 return nil, err
92         }
93
94         s.InjectResize()
95         handleEvent()
96
97         return s, nil
98 }
99
100 func cleanup() {
101         os.RemoveAll(tempDir)
102 }
103
104 func handleEvent() {
105         screen.Lock()
106         e := screen.Screen.PollEvent()
107         screen.Unlock()
108         if e != nil {
109                 screen.Events <- e
110         }
111         DoEvent()
112 }
113
114 func injectKey(key tcell.Key, r rune, mod tcell.ModMask) {
115         sim.InjectKey(key, r, mod)
116         handleEvent()
117 }
118
119 func injectMouse(x, y int, buttons tcell.ButtonMask, mod tcell.ModMask) {
120         sim.InjectMouse(x, y, buttons, mod)
121         handleEvent()
122 }
123
124 func injectString(str string) {
125         // the tcell simulation screen event channel can only handle
126         // 10 events at once, so we need to divide up the key events
127         // into chunks of 10 and handle the 10 events before sending
128         // another chunk of events
129         iters := len(str) / 10
130         extra := len(str) % 10
131
132         for i := 0; i < iters; i++ {
133                 s := i * 10
134                 e := i*10 + 10
135                 sim.InjectKeyBytes([]byte(str[s:e]))
136                 for i := 0; i < 10; i++ {
137                         handleEvent()
138                 }
139         }
140
141         sim.InjectKeyBytes([]byte(str[len(str)-extra:]))
142         for i := 0; i < extra; i++ {
143                 handleEvent()
144         }
145 }
146
147 func openFile(file string) {
148         injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl)
149         injectString(fmt.Sprintf("open %s", file))
150         injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
151 }
152
153 func createTestFile(name string, content string) (string, error) {
154         testf, err := ioutil.TempFile("", name)
155         if err != nil {
156                 return "", err
157         }
158
159         if _, err := testf.Write([]byte(content)); err != nil {
160                 return "", err
161         }
162         if err := testf.Close(); err != nil {
163                 return "", err
164         }
165
166         return testf.Name(), nil
167 }
168
169 func TestMain(m *testing.M) {
170         var err error
171         sim, err = startup([]string{})
172         if err != nil {
173                 log.Fatalln(err)
174                 os.Exit(1)
175         }
176
177         retval := m.Run()
178         cleanup()
179
180         os.Exit(retval)
181 }
182
183 func TestSimpleEdit(t *testing.T) {
184         file, err := createTestFile("micro_simple_edit_test", "base content")
185         if err != nil {
186                 t.Error(err)
187                 return
188         }
189         defer os.Remove(file)
190
191         openFile(file)
192
193         var buf *buffer.Buffer
194         for _, b := range buffer.OpenBuffers {
195                 if b.Path == file {
196                         buf = b
197                 }
198         }
199
200         if buf == nil {
201                 t.Errorf("Could not find buffer %s", file)
202                 return
203         }
204
205         injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
206         injectKey(tcell.KeyUp, 0, tcell.ModNone)
207         injectString("first line")
208
209         // test both kinds of backspace
210         for i := 0; i < len("ne"); i++ {
211                 injectKey(tcell.KeyBackspace, rune(tcell.KeyBackspace), tcell.ModNone)
212         }
213         for i := 0; i < len(" li"); i++ {
214                 injectKey(tcell.KeyBackspace2, rune(tcell.KeyBackspace2), tcell.ModNone)
215         }
216         injectString("foobar")
217
218         injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)
219
220         data, err := ioutil.ReadFile(file)
221         if err != nil {
222                 t.Error(err)
223                 return
224         }
225
226         assert.Equal(t, "firstfoobar\nbase content\n", string(data))
227 }
228
229 func TestMouse(t *testing.T) {
230         file, err := createTestFile("micro_mouse_test", "base content")
231         if err != nil {
232                 t.Error(err)
233                 return
234         }
235         defer os.Remove(file)
236
237         openFile(file)
238
239         // buffer:
240         // base content
241         // the selections need to happen at different locations to avoid a double click
242         injectMouse(3, 0, tcell.Button1, tcell.ModNone)
243         injectKey(tcell.KeyLeft, 0, tcell.ModNone)
244         injectMouse(0, 0, tcell.ButtonNone, tcell.ModNone)
245         injectString("secondline")
246         // buffer:
247         // secondlinebase content
248         injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
249         // buffer:
250         // secondline
251         // base content
252         injectMouse(2, 0, tcell.Button1, tcell.ModNone)
253         injectMouse(0, 0, tcell.ButtonNone, tcell.ModNone)
254         injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
255         // buffer:
256         //
257         // secondline
258         // base content
259         injectKey(tcell.KeyUp, 0, tcell.ModNone)
260         injectString("firstline")
261         // buffer:
262         // firstline
263         // secondline
264         // base content
265         injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)
266
267         data, err := ioutil.ReadFile(file)
268         if err != nil {
269                 t.Error(err)
270                 return
271         }
272
273         assert.Equal(t, "firstline\nsecondline\nbase content\n", string(data))
274 }
275
276 var srTestStart = `foo
277 foo
278 foofoofoo
279 Ernleȝe foo æðelen
280 `
281 var srTest2 = `test_string
282 test_string
283 test_stringtest_stringtest_string
284 Ernleȝe test_string æðelen
285 `
286 var srTest3 = `test_foo
287 test_string
288 test_footest_stringtest_foo
289 Ernleȝe test_string æðelen
290 `
291
292 func TestSearchAndReplace(t *testing.T) {
293         file, err := createTestFile("micro_search_replace_test", srTestStart)
294         if err != nil {
295                 t.Error(err)
296                 return
297         }
298         defer os.Remove(file)
299
300         openFile(file)
301
302         injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl)
303         injectString(fmt.Sprintf("replaceall %s %s", "foo", "test_string"))
304         injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
305
306         injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)
307
308         data, err := ioutil.ReadFile(file)
309         if err != nil {
310                 t.Error(err)
311                 return
312         }
313
314         assert.Equal(t, srTest2, string(data))
315
316         injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl)
317         injectString(fmt.Sprintf("replace %s %s", "string", "foo"))
318         injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
319         injectString("ynyny")
320         injectKey(tcell.KeyEscape, 0, tcell.ModNone)
321
322         injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)
323
324         data, err = ioutil.ReadFile(file)
325         if err != nil {
326                 t.Error(err)
327                 return
328         }
329
330         assert.Equal(t, srTest3, string(data))
331 }
332
333 func TestMultiCursor(t *testing.T) {
334         // TODO
335 }
336
337 func TestSettingsPersistence(t *testing.T) {
338         // TODO
339 }
340
341 // more tests (rendering, tabs, plugins)?