summaryrefslogtreecommitdiff
path: root/mnv/src/testdir/test_clientserver.mnv
blob: a8c8961351db26cfee12db0db2f8edabefd3d324 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
" Tests for the +clientserver feature.

CheckFeature job

if !has('clientserver')
  call assert_fails('call remote_startserver("local")', 'E942:')
endif

CheckFeature clientserver

source util/shared.mnv

" Unlike X11, we need the socket server running if we want to send commands to
" a server via sockets.
RunSocketServer

func Check_X11_Connection()
  if has('x11')
    CheckX11
    try
      call remote_send('xxx', '')
    catch
      if v:exception =~ 'E240:'
        throw 'Skipped: no connection to the X server'
      endif
      " ignore other errors
    endtry
  endif
endfunc

func Test_client_server()
  let g:test_is_flaky = 1
  let cmd = GetMNVCommand()
  if cmd == ''
    throw 'GetMNVCommand() failed'
  endif
  call Check_X11_Connection()

  let name = 'XMNVTEST'
  let cmd .= ' --servername ' . name
  let job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
  call WaitForAssert({-> assert_equal("run", job_status(job))})

  " Takes a short while for the server to be active.
  " When using valgrind it takes much longer.
  call WaitForAssert({-> assert_match(name, serverlist())})

  if !has('win32')
    if RunMNV([], [], '--serverlist >Xtest_serverlist')
      let lines = readfile('Xtest_serverlist')
      call assert_true(index(lines, 'XMNVTEST') >= 0)
    endif
    call delete('Xtest_serverlist')
  endif

  eval name->remote_foreground()

  call remote_send(name, ":let testvar = 'yes'\<CR>")
  call WaitFor('remote_expr("' . name . '", "exists(\"testvar\") ? testvar : \"\"", "", 1) == "yes"')
  call assert_equal('yes', remote_expr(name, "testvar", "", 2))
  call assert_fails("let x=remote_expr(name, '2+x')", 'E449:')
  call assert_fails("let x=remote_expr('[], '2+2')", 'E116:')

  if has('unix') && has('gui') && !has('gui_running')
    " Running in a terminal and the GUI is available: Tell the server to open
    " the GUI and check that the remote command still works.
    " Need to wait for the GUI to start up, otherwise the send hangs in trying
    " to send to the terminal window.
    if has('gui_motif')
      " For this GUI ignore the 'failed to create input context' error.
      call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>")
    else
      call remote_send(name, ":gui -f\<CR>")
    endif
    " Wait for the server to be up and answering requests.
    " When using valgrind this can be very, very slow.
    sleep 1
    call WaitForAssert({-> assert_match('\d', name->remote_expr("v:version", "", 1))}, 10000)

    call remote_send(name, ":let testvar = 'maybe'\<CR>")
    call WaitForAssert({-> assert_equal('maybe', remote_expr(name, "testvar", "", 2))})
  endif

  call assert_fails('call remote_send("XXX", ":let testvar = ''yes''\<CR>")', 'E241:')

  call writefile(['one'], 'Xclientfile')
  let cmd = GetMNVProg() .. ' --servername ' .. name .. ' --remote Xclientfile'
  call system(cmd)
  call WaitForAssert({-> assert_equal('Xclientfile', remote_expr(name, "bufname()", "", 2))})
  call WaitForAssert({-> assert_equal('one', remote_expr(name, "getline(1)", "", 2))})
  call writefile(['one', 'two'], 'Xclientfile')
  call system(cmd)
  call WaitForAssert({-> assert_equal('two', remote_expr(name, "getline(2)", "", 2))})
  call delete('Xclientfile')

  " Expression evaluated locally.
  if v:servername == ''
    eval 'MYSELF'->remote_startserver()
    " May get MYSELF1 when running the test again.
    call assert_match('MYSELF', v:servername)
    call assert_fails("call remote_startserver('MYSELF')", 'E941:')
  endif
  let g:testvar = 'myself'
  call assert_equal('myself', remote_expr(v:servername, 'testvar'))
  call remote_send(v:servername, ":let g:testvar2 = 75\<CR>")
  call feedkeys('', 'x')
  call assert_equal(75, g:testvar2)
  call assert_fails('let v = remote_expr(v:servername, "/2")', ['E15:.*/2'])

  call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
  call assert_equal('got it', g:myserverid->remote_read(2))

  call remote_send(name, ":eval expand('<client>')->server2client('another')\<CR>", 'g:myserverid')
  let peek_result = 'nothing'
  let r = g:myserverid->remote_peek('peek_result')
  " unpredictable whether the result is already available.
  if r > 0
    call assert_equal('another', peek_result)
  elseif r == 0
    call assert_equal('nothing', peek_result)
  else
    call assert_report('remote_peek() failed')
  endif
  let g:peek_result = 'empty'
  call WaitFor('remote_peek(g:myserverid, "g:peek_result") > 0')
  call assert_equal('another', g:peek_result)
  call assert_equal('another', remote_read(g:myserverid, 2))

  if !has('gui_running')
    " In GUI mnv, the following tests display a dialog box

    let cmd = GetMNVProg() .. ' --servername ' .. name

    " Run a separate instance to send a command to the server
    call remote_expr(name, 'execute("only")')
    call system(cmd .. ' --remote-send ":new Xclientfile<CR>"')
    call assert_equal('2', remote_expr(name, 'winnr("$")'))
    call assert_equal('Xclientfile', remote_expr(name, 'winbufnr(1)->bufname()'))
    call remote_expr(name, 'execute("only")')

    " Invoke a remote-expr. On MS-Windows, the returned value has a carriage
    " return.
    let l = system(cmd .. ' --remote-expr "2 + 2"')
    call assert_equal(['4'], split(l, "\n"))

    " Edit multiple files using --remote
    call system(cmd .. ' --remote Xclientfile1 Xclientfile2 Xclientfile3')
    call assert_match(".*Xclientfile1\n.*Xclientfile2\n.*Xclientfile3\n", remote_expr(name, 'argv()'))
    eval name->remote_send(":%bw!\<CR>")

    " Edit files in separate tab pages
    call system(cmd .. ' --remote-tab Xclientfile1 Xclientfile2 Xclientfile3')
    call WaitForAssert({-> assert_equal('3', remote_expr(name, 'tabpagenr("$")'))})
    call assert_match('.*\<Xclientfile2', remote_expr(name, 'bufname(tabpagebuflist(2)[0])'))
    eval name->remote_send(":%bw!\<CR>")

    " Edit a file using --remote-wait
    eval name->remote_send(":source $MNVRUNTIME/plugin/rrhelper.mnv\<CR>")
    call system(cmd .. ' --remote-wait +enew Xclientfile1')
    call assert_match('.*\<Xclientfile1', remote_expr(name, 'bufname("#")'))
    eval name->remote_send(":%bw!\<CR>")

    " Edit files using --remote-tab-wait
    call system(cmd .. ' --remote-tabwait +tabonly\|enew Xclientfile1 Xclientfile2')
    call assert_equal('1', remote_expr(name, 'tabpagenr("$")'))
    eval name->remote_send(":%bw!\<CR>")

    " Error cases
    if v:lang == "C" || v:lang =~ '^[Ee]n'
      let l = split(system(cmd .. ' --remote +pwd'), "\n")
      call assert_equal("Argument missing after: \"+pwd\"", l[1])
    endif
    let l = system(cmd .. ' --remote-expr "abcd"')
    call assert_match('^E449: ', l)
  endif

  eval name->remote_send(":%bw!\<CR>")
  eval name->remote_send(":qa!\<CR>")
  try
    call WaitForAssert({-> assert_equal("dead", job_status(job))})
  finally
    if job_status(job) != 'dead'
      call assert_report('Server did not exit')
      call job_stop(job, 'kill')
    endif
  endtry

  call assert_fails('call remote_startserver("")', 'E1175:')
  call assert_fails('call remote_startserver([])', 'E1174:')
  call assert_fails("let x = remote_peek([])", 'E730:')

  " When using socket server, server id is not a number, but the path to the
  " socket.
  if has('socketserver') && !has('X11')
    call assert_fails("let x = remote_read('mnv/10')", ['E573:.*mnv/10'])
    call assert_fails("call server2client('a/b/c', 'xyz')", ['E573:.*a/b/c'])
  else
    call assert_fails("let x = remote_read('mnv10')",
          \ has('unix') ? ['E573:.*mnv10'] : 'E277:')
    call assert_fails("call server2client('abc', 'xyz')",
          \ has('unix') ? ['E573:.*abc'] : 'E258:')
  endif
endfunc

func Test_client_server_stopinsert()
  " test does not work on MS-Windows
  CheckNotMSWindows
  CheckNotMac
  let g:test_is_flaky = 1
  let cmd = GetMNVCommand()
  if cmd == ''
    throw 'GetMNVCommand() failed'
  endif
  call Check_X11_Connection()
  let fname = 'Xclientserver_stop.txt'
  let name = 'XMNVTEST2'
  call writefile(['one two three'], fname, 'D')

  let cmd .= ' -c "set virtualedit=onemore"'
  let cmd .= ' -c "call cursor(1, 14)"'
  let cmd .= ' -c "startinsert"'
  let cmd .= ' --servername ' . name
  let cmd .= ' ' .. fname
  let job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
  call WaitForAssert({-> assert_equal("run", job_status(job))})

  " Takes a short while for the server to be active.
  " When using valgrind it takes much longer.
  call WaitForAssert({-> assert_match(name, serverlist())})

  call remote_send(name, "\<C-\>\<C-N>")

  " Wait for the mode to change to Normal ('n')
  call WaitForAssert({-> assert_equal('n', name->remote_expr("mode(1)"))})
  call WaitForAssert({-> assert_equal('13', name->remote_expr("col('.')"))})

  call remote_send(name, "\<C-\>\<C-N>:qa!\<CR>")
  try
    call WaitForAssert({-> assert_equal("dead", job_status(job))})
  finally
    if job_status(job) != 'dead'
      call assert_report('Server did not exit')
      call job_stop(job, 'kill')
    endif
  endtry
endfunc

" Test if socket server and X11 backends can be chosen and work properly.
func Test_client_server_x11_and_socket_server()
  CheckNotMSWindows
  CheckFeature socketserver
  CheckFeature x11

  let g:test_is_flaky = 1
  let cmd = GetMNVCommand()

  if cmd == ''
    throw 'GetMNVCommand() failed'
  endif
  call Check_X11_Connection()

  let types = ['socket', 'x11']

  for type in types
    let name = 'MNVTEST_' .. toupper(type)
    let actual_cmd = cmd .. ' --clientserver ' .. type
    let actual_cmd .= ' --servername ' .. name
    let job = job_start(actual_cmd, {'stoponexit': 'kill', 'out_io': 'null'})

    call WaitForAssert({-> assert_equal("run", job_status(job))})
    call WaitForAssert({-> assert_match(name, system(cmd .. ' --clientserver ' .. type .. ' --serverlist'))})

    call assert_match(name, system(actual_cmd .. ' --remote-expr "v:servername"'))

    call system(actual_cmd .. " --remote-expr 'execute(\"qa!\")'")
    try
      call WaitForAssert({-> assert_equal("dead", job_status(job))})
    finally
      if job_status(job) != 'dead'
        call assert_report('Server did not exit')
        call job_stop(job, 'kill')
      endif
    endtry
  endfor
endfunc

" Test if socket server works in the GUI
func Test_client_server_socket_server_gui()
  CheckNotMSWindows
  CheckFeature socketserver
  CheckFeature gui_gtk

  let g:test_is_flaky = 1
  let cmd = GetMNVCommand()

  if cmd == ''
    throw 'GetMNVCommand() failed'
  endif
  call Check_X11_Connection()

  let name = 'MNVTESTSOCKET'
  let cmd .= ' --clientserver socket'
  let cmd .= ' --servername ' .. name

  let job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})

  call WaitForAssert({-> assert_equal("run", job_status(job))})
  call WaitForAssert({-> assert_match(name, system(cmd .. ' --serverlist'))})

  call system(cmd .. " --remote-expr 'execute(\"gui\")'")

  call assert_match('1', system(cmd .. " --remote-expr 'has(\"gui_running\")'"))
  call assert_match(name, system(cmd .. ' --remote-expr "v:servername"'))

  call system(cmd .. " --remote-expr 'execute(\"qa!\")'")
  try
    call WaitForAssert({-> assert_equal("dead", job_status(job))})
  finally
    if job_status(job) != 'dead'
      call assert_report('Server did not exit')
      call job_stop(job, 'kill')
    endif
  endtry
endfunc

" Test if custom paths work for socketserver
func Test_client_socket_server_custom_path()
  CheckNotMSWindows
  CheckFeature socketserver
  CheckNotFeature x11

  let g:test_is_flaky = 1
  let cmd = GetMNVCommand()

  if cmd == ''
    throw 'GetMNVCommand() failed'
  endif

  let name = 'MNVTESTSOCKET2'

  let paths = ['./' .. name, '../testdir/' .. name, getcwd(-1) .. '/' .. name]

  for path in paths
    let actual = cmd .. ' --servername ' .. path

    let job = job_start(actual, {'stoponexit': 'kill', 'out_io': 'null'})

    call WaitForAssert({-> assert_equal("run", job_status(job))})
    call WaitForAssert({-> assert_equal(path, glob(path))})

    call system(actual .. " --remote-expr 'execute(\"qa!\")'")
    try
      call WaitForAssert({-> assert_equal("dead", job_status(job))})
    finally
      if job_status(job) != 'dead'
        call assert_report('Server did not exit')
        call job_stop(job, 'kill')
      endif
    endtry
  endfor
endfunc

" Uncomment this line to get a debugging log
" call ch_logfile('channellog', 'w')

" mnv: shiftwidth=2 sts=2 expandtab