1" Tests for search_stats, when "S" is not in 'shortmess'
2
3source check.vim
4source screendump.vim
5
6func Test_search_stat()
7  new
8  set shortmess-=S
9  " Append 50 lines with text to search for, "foobar" appears 20 times
10  call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 10))
11
12  call cursor(1, 1)
13
14  " searchcount() returns an empty dictionary when previous pattern was not set
15  call assert_equal({}, searchcount(#{pattern: ''}))
16  " but setting @/ should also work (even 'n' nor 'N' was executed)
17  " recompute the count when the last position is different.
18  call assert_equal(
19    \ #{current: 1, exact_match: 1, total: 40, incomplete: 0, maxcount: 99},
20    \ searchcount(#{pattern: 'foo'}))
21  call assert_equal(
22    \ #{current: 0, exact_match: 0, total: 10, incomplete: 0, maxcount: 99},
23    \ searchcount(#{pattern: 'fooooobar'}))
24  call assert_equal(
25    \ #{current: 0, exact_match: 0, total: 10, incomplete: 0, maxcount: 99},
26    \ searchcount(#{pattern: 'fooooobar', pos: [2, 1, 0]}))
27  call assert_equal(
28    \ #{current: 1, exact_match: 1, total: 10, incomplete: 0, maxcount: 99},
29    \ searchcount(#{pattern: 'fooooobar', pos: [3, 1, 0]}))
30  " on last char of match
31  call assert_equal(
32    \ #{current: 1, exact_match: 1, total: 10, incomplete: 0, maxcount: 99},
33    \ searchcount(#{pattern: 'fooooobar', pos: [3, 9, 0]}))
34  " on char after match
35  call assert_equal(
36    \ #{current: 1, exact_match: 0, total: 10, incomplete: 0, maxcount: 99},
37    \ searchcount(#{pattern: 'fooooobar', pos: [3, 10, 0]}))
38  call assert_equal(
39    \ #{current: 1, exact_match: 0, total: 10, incomplete: 0, maxcount: 99},
40    \ searchcount(#{pattern: 'fooooobar', pos: [4, 1, 0]}))
41  call assert_equal(
42    \ #{current: 1, exact_match: 0, total: 2, incomplete: 2, maxcount: 1},
43    \ searchcount(#{pattern: 'fooooobar', pos: [4, 1, 0], maxcount: 1}))
44  call assert_equal(
45    \ #{current: 0, exact_match: 0, total: 2, incomplete: 2, maxcount: 1},
46    \ searchcount(#{pattern: 'fooooobar', maxcount: 1}))
47
48  " match at second line
49  let messages_before = execute('messages')
50  let @/ = 'fo*\(bar\?\)\?'
51  let g:a = execute(':unsilent :norm! n')
52  let stat = '\[2/50\]'
53  let pat = escape(@/, '()*?'). '\s\+'
54  call assert_match(pat .. stat, g:a)
55  call assert_equal(
56    \ #{current: 2, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
57    \ searchcount(#{recompute: 0}))
58  " didn't get added to message history
59  call assert_equal(messages_before, execute('messages'))
60
61  " Match at last line
62  call cursor(line('$')-2, 1)
63  let g:a = execute(':unsilent :norm! n')
64  let stat = '\[50/50\]'
65  call assert_match(pat .. stat, g:a)
66  call assert_equal(
67    \ #{current: 50, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
68    \ searchcount(#{recompute: 0}))
69
70  " No search stat
71  set shortmess+=S
72  call cursor(1, 1)
73  let stat = '\[2/50\]'
74  let g:a = execute(':unsilent :norm! n')
75  call assert_notmatch(pat .. stat, g:a)
76  " n does not update search stat
77  call assert_equal(
78    \ #{current: 50, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
79    \ searchcount(#{recompute: 0}))
80  call assert_equal(
81    \ #{current: 2, exact_match: 1, total: 50, incomplete: 0, maxcount: 99},
82    \ searchcount(#{recompute: v:true}))
83  set shortmess-=S
84
85  " Many matches
86  call cursor(line('$')-2, 1)
87  let @/ = '.'
88  let pat = escape(@/, '()*?'). '\s\+'
89  let g:a = execute(':unsilent :norm! n')
90  let stat = '\[>99/>99\]'
91  call assert_match(pat .. stat, g:a)
92  call assert_equal(
93    \ #{current: 100, exact_match: 0, total: 100, incomplete: 2, maxcount: 99},
94    \ searchcount(#{recompute: 0}))
95  call assert_equal(
96    \ #{current: 272, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
97    \ searchcount(#{recompute: v:true, maxcount: 0, timeout: 200}))
98  call assert_equal(
99    \ #{current: 1, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
100    \ searchcount(#{recompute: 1, maxcount: 0, pos: [1, 1, 0], timeout: 200}))
101  call cursor(line('$'), 1)
102  let g:a = execute(':unsilent :norm! n')
103  let stat = 'W \[1/>99\]'
104  call assert_match(pat .. stat, g:a)
105  call assert_equal(
106    \ #{current: 1, exact_match: 1, total: 100, incomplete: 2, maxcount: 99},
107    \ searchcount(#{recompute: 0}))
108  call assert_equal(
109    \ #{current: 1, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
110    \ searchcount(#{recompute: 1, maxcount: 0, timeout: 200}))
111  call assert_equal(
112    \ #{current: 271, exact_match: 1, total: 280, incomplete: 0, maxcount: 0},
113    \ searchcount(#{recompute: 1, maxcount: 0, pos: [line('$')-2, 1, 0], timeout: 200}))
114
115  " Many matches
116  call cursor(1, 1)
117  let g:a = execute(':unsilent :norm! n')
118  let stat = '\[2/>99\]'
119  call assert_match(pat .. stat, g:a)
120  call cursor(1, 1)
121  let g:a = execute(':unsilent :norm! N')
122  let stat = 'W \[>99/>99\]'
123  call assert_match(pat .. stat, g:a)
124
125  " right-left
126  if exists("+rightleft")
127    set rl
128    call cursor(1,1)
129    let @/ = 'foobar'
130    let pat = 'raboof/\s\+'
131    let g:a = execute(':unsilent :norm! n')
132    let stat = '\[20/2\]'
133    call assert_match(pat .. stat, g:a)
134    set norl
135  endif
136
137  " right-left bottom
138  if exists("+rightleft")
139    set rl
140    call cursor('$',1)
141    let pat = 'raboof?\s\+'
142    let g:a = execute(':unsilent :norm! N')
143    let stat = '\[20/20\]'
144    call assert_match(pat .. stat, g:a)
145    set norl
146  endif
147
148  " right-left back at top
149  if exists("+rightleft")
150    set rl
151    call cursor('$',1)
152    let pat = 'raboof/\s\+'
153    let g:a = execute(':unsilent :norm! n')
154    let stat = 'W \[20/1\]'
155    call assert_match(pat .. stat, g:a)
156    call assert_match('search hit BOTTOM, continuing at TOP', g:a)
157    set norl
158  endif
159
160  " normal, back at bottom
161  call cursor(1,1)
162  let @/ = 'foobar'
163  let pat = '?foobar\s\+'
164  let g:a = execute(':unsilent :norm! N')
165  let stat = 'W \[20/20\]'
166  call assert_match(pat .. stat, g:a)
167  call assert_match('search hit TOP, continuing at BOTTOM', g:a)
168  call assert_match('W \[20/20\]', Screenline(&lines))
169
170  " normal, no match
171  call cursor(1,1)
172  let @/ = 'zzzzzz'
173  let g:a = ''
174  try
175    let g:a = execute(':unsilent :norm! n')
176  catch /^Vim\%((\a\+)\)\=:E486/
177    let stat = ''
178    " error message is not redir'ed to g:a, it is empty
179    call assert_true(empty(g:a))
180  catch
181    call assert_false(1)
182  endtry
183
184  " with count
185  call cursor(1, 1)
186  let @/ = 'fo*\(bar\?\)\?'
187  let g:a = execute(':unsilent :norm! 2n')
188  let stat = '\[3/50\]'
189  let pat = escape(@/, '()*?'). '\s\+'
190  call assert_match(pat .. stat, g:a)
191  let g:a = execute(':unsilent :norm! 2n')
192  let stat = '\[5/50\]'
193  call assert_match(pat .. stat, g:a)
194
195  " with offset
196  call cursor(1, 1)
197  call feedkeys("/fo*\\(bar\\?\\)\\?/+1\<cr>", 'tx')
198  let g:a = execute(':unsilent :norm! n')
199  let stat = '\[5/50\]'
200  let pat = escape(@/ .. '/+1', '()*?'). '\s\+'
201  call assert_match(pat .. stat, g:a)
202
203  " normal, n comes from a mapping
204  "     Need to move over more than 64 lines to trigger char_avail(.
205  nnoremap n nzv
206  call cursor(1,1)
207  call append(50, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 10))
208  call setline(2, 'find this')
209  call setline(70, 'find this')
210  let @/ = 'find this'
211  let pat = '/find this\s\+'
212  let g:a = execute(':unsilent :norm n')
213  " g:a will contain several lines
214  let g:b = split(g:a, "\n")[-1]
215  let stat = '\[1/2\]'
216  call assert_match(pat .. stat, g:b)
217  unmap n
218
219  " normal, but silent
220  call cursor(1,1)
221  let @/ = 'find this'
222  let pat = '/find this\s\+'
223  let g:a = execute(':norm! n')
224  let stat = '\[1/2\]'
225  call assert_notmatch(pat .. stat, g:a)
226
227  " normal, n comes from a silent mapping
228  " First test a normal mapping, then a silent mapping
229  call cursor(1,1)
230  nnoremap n n
231  let @/ = 'find this'
232  let pat = '/find this\s\+'
233  let g:a = execute(':unsilent :norm n')
234  let g:b = split(g:a, "\n")[-1]
235  let stat = '\[1/2\]'
236  call assert_match(pat .. stat, g:b)
237  nnoremap <silent> n n
238  call cursor(1,1)
239  let g:a = execute(':unsilent :norm n')
240  let g:b = split(g:a, "\n")[-1]
241  let stat = '\[1/2\]'
242  call assert_notmatch(pat .. stat, g:b)
243  call assert_match(stat, g:b)
244  " Test that the message is not truncated
245  " it would insert '...' into the output.
246  call assert_match('^\s\+' .. stat, g:b)
247  unmap n
248
249  " Time out
250  %delete _
251  call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 100000))
252  call cursor(1, 1)
253  call assert_equal(1, searchcount(#{pattern: 'foo', maxcount: 0, timeout: 1}).incomplete)
254
255  " Clean up
256  set shortmess+=S
257  " close the window
258  bwipe!
259endfunc
260
261func Test_searchcount_fails()
262  call assert_fails('echo searchcount("boo!")', 'E715:')
263  call assert_fails('echo searchcount({"timeout" : []})', 'E745:')
264  call assert_fails('echo searchcount({"maxcount" : []})', 'E745:')
265  call assert_fails('echo searchcount({"pattern" : []})', 'E730:')
266  call assert_fails('echo searchcount({"pos" : 1})', 'E475:')
267  call assert_fails('echo searchcount({"pos" : [1]})', 'E475:')
268  call assert_fails('echo searchcount({"pos" : [[], 2, 3]})', 'E745:')
269  call assert_fails('echo searchcount({"pos" : [1, [], 3]})', 'E745:')
270  call assert_fails('echo searchcount({"pos" : [1, 2, []]})', 'E745:')
271endfunc
272
273func Test_searchcount_in_statusline()
274  CheckScreendump
275
276  let lines =<< trim END
277    set shortmess-=S
278    call append(0, 'this is something')
279    function TestSearchCount() abort
280      let search_count = searchcount()
281      if !empty(search_count)
282	return '[' . search_count.current . '/' . search_count.total . ']'
283      else
284	return ''
285      endif
286    endfunction
287    set hlsearch
288    set laststatus=2 statusline+=%{TestSearchCount()}
289  END
290  call writefile(lines, 'Xsearchstatusline')
291  let buf = RunVimInTerminal('-S Xsearchstatusline', #{rows: 10})
292  call TermWait(buf)
293  call term_sendkeys(buf, "/something")
294  call VerifyScreenDump(buf, 'Test_searchstat_4', {})
295
296  call term_sendkeys(buf, "\<Esc>")
297  call StopVimInTerminal(buf)
298  call delete('Xsearchstatusline')
299endfunc
300
301func Test_search_stat_foldopen()
302  CheckScreendump
303
304  let lines =<< trim END
305    set shortmess-=S
306    setl foldenable foldmethod=indent foldopen-=search
307    call append(0, ['if', "\tfoo", "\tfoo", 'endif'])
308    let @/ = 'foo'
309    call cursor(1,1)
310    norm n
311  END
312  call writefile(lines, 'Xsearchstat1')
313
314  let buf = RunVimInTerminal('-S Xsearchstat1', #{rows: 10})
315  call TermWait(buf)
316  call VerifyScreenDump(buf, 'Test_searchstat_3', {})
317
318  call term_sendkeys(buf, "n")
319  call TermWait(buf)
320  call VerifyScreenDump(buf, 'Test_searchstat_3', {})
321
322  call term_sendkeys(buf, "n")
323  call TermWait(buf)
324  call VerifyScreenDump(buf, 'Test_searchstat_3', {})
325
326  call StopVimInTerminal(buf)
327  call delete('Xsearchstat1')
328endfunc
329
330func! Test_search_stat_screendump()
331  CheckScreendump
332
333  let lines =<< trim END
334    set shortmess-=S
335    " Append 50 lines with text to search for, "foobar" appears 20 times
336    call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 20))
337    call setline(2, 'find this')
338    call setline(70, 'find this')
339    nnoremap n n
340    let @/ = 'find this'
341    call cursor(1,1)
342    norm n
343  END
344  call writefile(lines, 'Xsearchstat')
345  let buf = RunVimInTerminal('-S Xsearchstat', #{rows: 10})
346  call TermWait(buf)
347  call VerifyScreenDump(buf, 'Test_searchstat_1', {})
348
349  call term_sendkeys(buf, ":nnoremap <silent> n n\<cr>")
350  call term_sendkeys(buf, "gg0n")
351  call TermWait(buf)
352  call VerifyScreenDump(buf, 'Test_searchstat_2', {})
353
354  call StopVimInTerminal(buf)
355  call delete('Xsearchstat')
356endfunc
357
358func Test_search_stat_then_gd()
359  CheckScreendump
360
361  let lines =<< trim END
362    call setline(1, ['int cat;', 'int dog;', 'cat = dog;'])
363    set shortmess-=S
364    set hlsearch
365  END
366  call writefile(lines, 'Xsearchstatgd')
367
368  let buf = RunVimInTerminal('-S Xsearchstatgd', #{rows: 10})
369  call term_sendkeys(buf, "/dog\<CR>")
370  call TermWait(buf)
371  call VerifyScreenDump(buf, 'Test_searchstatgd_1', {})
372
373  call term_sendkeys(buf, "G0gD")
374  call TermWait(buf)
375  call VerifyScreenDump(buf, 'Test_searchstatgd_2', {})
376
377  call StopVimInTerminal(buf)
378  call delete('Xsearchstatgd')
379endfunc
380
381
382
383" vim: shiftwidth=2 sts=2 expandtab
384