##// END OF EJS Templates
created test for reset_search_buffer
Abdullah Habib -
Show More
@@ -1,468 +1,487
1 1 import pytest
2 2 from IPython.terminal.shortcuts.auto_suggest import (
3 3 accept,
4 4 accept_or_jump_to_end,
5 5 accept_token,
6 6 accept_character,
7 7 accept_word,
8 8 accept_and_keep_cursor,
9 9 discard,
10 10 NavigableAutoSuggestFromHistory,
11 11 swap_autosuggestion_up,
12 12 swap_autosuggestion_down,
13 13 )
14 14 from IPython.terminal.shortcuts.auto_match import skip_over
15 from IPython.terminal.shortcuts import create_ipython_shortcuts
15 from IPython.terminal.shortcuts import create_ipython_shortcuts,reset_search_buffer
16 16
17 17 from prompt_toolkit.history import InMemoryHistory
18 18 from prompt_toolkit.buffer import Buffer
19 19 from prompt_toolkit.document import Document
20 20 from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
21 21
22 22 from unittest.mock import patch, Mock
23 from prompt_toolkit.enums import DEFAULT_BUFFER
23 24
24 25
25 26 def test_deprected():
26 27 import IPython.terminal.shortcuts.auto_suggest as iptsa
27 28
28 29 with pytest.warns(DeprecationWarning, match=r"8\.12.+accept_or_jump_to_end"):
29 30 iptsa.accept_in_vi_insert_mode
30 31
31 32
32 33 def make_event(text, cursor, suggestion):
33 34 event = Mock()
34 35 event.current_buffer = Mock()
35 36 event.current_buffer.suggestion = Mock()
36 37 event.current_buffer.text = text
37 38 event.current_buffer.cursor_position = cursor
38 39 event.current_buffer.suggestion.text = suggestion
39 40 event.current_buffer.document = Document(text=text, cursor_position=cursor)
40 41 return event
41 42
42 43
43 44 @pytest.mark.parametrize(
44 45 "text, suggestion, expected",
45 46 [
46 47 ("", "def out(tag: str, n=50):", "def out(tag: str, n=50):"),
47 48 ("def ", "out(tag: str, n=50):", "out(tag: str, n=50):"),
48 49 ],
49 50 )
50 51 def test_accept(text, suggestion, expected):
51 52 event = make_event(text, len(text), suggestion)
52 53 buffer = event.current_buffer
53 54 buffer.insert_text = Mock()
54 55 accept(event)
55 56 assert buffer.insert_text.called
56 57 assert buffer.insert_text.call_args[0] == (expected,)
57 58
58 59
59 60 @pytest.mark.parametrize(
60 61 "text, suggestion",
61 62 [
62 63 ("", "def out(tag: str, n=50):"),
63 64 ("def ", "out(tag: str, n=50):"),
64 65 ],
65 66 )
66 67 def test_discard(text, suggestion):
67 68 event = make_event(text, len(text), suggestion)
68 69 buffer = event.current_buffer
69 70 buffer.insert_text = Mock()
70 71 discard(event)
71 72 assert not buffer.insert_text.called
72 73 assert buffer.suggestion is None
73 74
74 75
75 76 @pytest.mark.parametrize(
76 77 "text, cursor, suggestion, called",
77 78 [
78 79 ("123456", 6, "123456789", True),
79 80 ("123456", 3, "123456789", False),
80 81 ("123456 \n789", 6, "123456789", True),
81 82 ],
82 83 )
83 84 def test_autosuggest_at_EOL(text, cursor, suggestion, called):
84 85 """
85 86 test that autosuggest is only applied at end of line.
86 87 """
87 88
88 89 event = make_event(text, cursor, suggestion)
89 90 event.current_buffer.insert_text = Mock()
90 91 accept_or_jump_to_end(event)
91 92 if called:
92 93 event.current_buffer.insert_text.assert_called()
93 94 else:
94 95 event.current_buffer.insert_text.assert_not_called()
95 96 # event.current_buffer.document.get_end_of_line_position.assert_called()
96 97
97 98
98 99 @pytest.mark.parametrize(
99 100 "text, suggestion, expected",
100 101 [
101 102 ("", "def out(tag: str, n=50):", "def "),
102 103 ("d", "ef out(tag: str, n=50):", "ef "),
103 104 ("de ", "f out(tag: str, n=50):", "f "),
104 105 ("def", " out(tag: str, n=50):", " "),
105 106 ("def ", "out(tag: str, n=50):", "out("),
106 107 ("def o", "ut(tag: str, n=50):", "ut("),
107 108 ("def ou", "t(tag: str, n=50):", "t("),
108 109 ("def out", "(tag: str, n=50):", "("),
109 110 ("def out(", "tag: str, n=50):", "tag: "),
110 111 ("def out(t", "ag: str, n=50):", "ag: "),
111 112 ("def out(ta", "g: str, n=50):", "g: "),
112 113 ("def out(tag", ": str, n=50):", ": "),
113 114 ("def out(tag:", " str, n=50):", " "),
114 115 ("def out(tag: ", "str, n=50):", "str, "),
115 116 ("def out(tag: s", "tr, n=50):", "tr, "),
116 117 ("def out(tag: st", "r, n=50):", "r, "),
117 118 ("def out(tag: str", ", n=50):", ", n"),
118 119 ("def out(tag: str,", " n=50):", " n"),
119 120 ("def out(tag: str, ", "n=50):", "n="),
120 121 ("def out(tag: str, n", "=50):", "="),
121 122 ("def out(tag: str, n=", "50):", "50)"),
122 123 ("def out(tag: str, n=5", "0):", "0)"),
123 124 ("def out(tag: str, n=50", "):", "):"),
124 125 ("def out(tag: str, n=50)", ":", ":"),
125 126 ],
126 127 )
127 128 def test_autosuggest_token(text, suggestion, expected):
128 129 event = make_event(text, len(text), suggestion)
129 130 event.current_buffer.insert_text = Mock()
130 131 accept_token(event)
131 132 assert event.current_buffer.insert_text.called
132 133 assert event.current_buffer.insert_text.call_args[0] == (expected,)
133 134
134 135
135 136 @pytest.mark.parametrize(
136 137 "text, suggestion, expected",
137 138 [
138 139 ("", "def out(tag: str, n=50):", "d"),
139 140 ("d", "ef out(tag: str, n=50):", "e"),
140 141 ("de ", "f out(tag: str, n=50):", "f"),
141 142 ("def", " out(tag: str, n=50):", " "),
142 143 ],
143 144 )
144 145 def test_accept_character(text, suggestion, expected):
145 146 event = make_event(text, len(text), suggestion)
146 147 event.current_buffer.insert_text = Mock()
147 148 accept_character(event)
148 149 assert event.current_buffer.insert_text.called
149 150 assert event.current_buffer.insert_text.call_args[0] == (expected,)
150 151
151 152
152 153 @pytest.mark.parametrize(
153 154 "text, suggestion, expected",
154 155 [
155 156 ("", "def out(tag: str, n=50):", "def "),
156 157 ("d", "ef out(tag: str, n=50):", "ef "),
157 158 ("de", "f out(tag: str, n=50):", "f "),
158 159 ("def", " out(tag: str, n=50):", " "),
159 160 # (this is why we also have accept_token)
160 161 ("def ", "out(tag: str, n=50):", "out(tag: "),
161 162 ],
162 163 )
163 164 def test_accept_word(text, suggestion, expected):
164 165 event = make_event(text, len(text), suggestion)
165 166 event.current_buffer.insert_text = Mock()
166 167 accept_word(event)
167 168 assert event.current_buffer.insert_text.called
168 169 assert event.current_buffer.insert_text.call_args[0] == (expected,)
169 170
170 171
171 172 @pytest.mark.parametrize(
172 173 "text, suggestion, expected, cursor",
173 174 [
174 175 ("", "def out(tag: str, n=50):", "def out(tag: str, n=50):", 0),
175 176 ("def ", "out(tag: str, n=50):", "out(tag: str, n=50):", 4),
176 177 ],
177 178 )
178 179 def test_accept_and_keep_cursor(text, suggestion, expected, cursor):
179 180 event = make_event(text, cursor, suggestion)
180 181 buffer = event.current_buffer
181 182 buffer.insert_text = Mock()
182 183 accept_and_keep_cursor(event)
183 184 assert buffer.insert_text.called
184 185 assert buffer.insert_text.call_args[0] == (expected,)
185 186 assert buffer.cursor_position == cursor
186 187
187 188
188 189 def test_autosuggest_token_empty():
189 190 full = "def out(tag: str, n=50):"
190 191 event = make_event(full, len(full), "")
191 192 event.current_buffer.insert_text = Mock()
192 193
193 194 with patch(
194 195 "prompt_toolkit.key_binding.bindings.named_commands.forward_word"
195 196 ) as forward_word:
196 197 accept_token(event)
197 198 assert not event.current_buffer.insert_text.called
198 199 assert forward_word.called
199 200
200 201
202 def test_reset_search_buffer():
203 event_with_text = Mock()
204 event_with_text.current_buffer.document.text = "some text"
205 event_with_text.current_buffer.reset = Mock()
206
207 event_empty = Mock()
208 event_empty.current_buffer.document.text = ""
209 event_empty.app.layout.focus = Mock()
210
211 reset_search_buffer(event_with_text)
212 event_with_text.current_buffer.reset.assert_called_once()
213
214 reset_search_buffer(event_empty)
215 event_empty.app.layout.focus.assert_called_once_with(DEFAULT_BUFFER)
216
217
218
219
201 220 def test_other_providers():
202 221 """Ensure that swapping autosuggestions does not break with other providers"""
203 222 provider = AutoSuggestFromHistory()
204 223 ip = get_ipython()
205 224 ip.auto_suggest = provider
206 225 event = Mock()
207 226 event.current_buffer = Buffer()
208 227 assert swap_autosuggestion_up(event) is None
209 228 assert swap_autosuggestion_down(event) is None
210 229
211 230
212 231 async def test_navigable_provider():
213 232 provider = NavigableAutoSuggestFromHistory()
214 233 history = InMemoryHistory(history_strings=["very_a", "very", "very_b", "very_c"])
215 234 buffer = Buffer(history=history)
216 235 ip = get_ipython()
217 236 ip.auto_suggest = provider
218 237
219 238 async for _ in history.load():
220 239 pass
221 240
222 241 buffer.cursor_position = 5
223 242 buffer.text = "very"
224 243
225 244 up = swap_autosuggestion_up
226 245 down = swap_autosuggestion_down
227 246
228 247 event = Mock()
229 248 event.current_buffer = buffer
230 249
231 250 def get_suggestion():
232 251 suggestion = provider.get_suggestion(buffer, buffer.document)
233 252 buffer.suggestion = suggestion
234 253 return suggestion
235 254
236 255 assert get_suggestion().text == "_c"
237 256
238 257 # should go up
239 258 up(event)
240 259 assert get_suggestion().text == "_b"
241 260
242 261 # should skip over 'very' which is identical to buffer content
243 262 up(event)
244 263 assert get_suggestion().text == "_a"
245 264
246 265 # should cycle back to beginning
247 266 up(event)
248 267 assert get_suggestion().text == "_c"
249 268
250 269 # should cycle back through end boundary
251 270 down(event)
252 271 assert get_suggestion().text == "_a"
253 272
254 273 down(event)
255 274 assert get_suggestion().text == "_b"
256 275
257 276 down(event)
258 277 assert get_suggestion().text == "_c"
259 278
260 279 down(event)
261 280 assert get_suggestion().text == "_a"
262 281
263 282
264 283 async def test_navigable_provider_multiline_entries():
265 284 provider = NavigableAutoSuggestFromHistory()
266 285 history = InMemoryHistory(history_strings=["very_a\nvery_b", "very_c"])
267 286 buffer = Buffer(history=history)
268 287 ip = get_ipython()
269 288 ip.auto_suggest = provider
270 289
271 290 async for _ in history.load():
272 291 pass
273 292
274 293 buffer.cursor_position = 5
275 294 buffer.text = "very"
276 295 up = swap_autosuggestion_up
277 296 down = swap_autosuggestion_down
278 297
279 298 event = Mock()
280 299 event.current_buffer = buffer
281 300
282 301 def get_suggestion():
283 302 suggestion = provider.get_suggestion(buffer, buffer.document)
284 303 buffer.suggestion = suggestion
285 304 return suggestion
286 305
287 306 assert get_suggestion().text == "_c"
288 307
289 308 up(event)
290 309 assert get_suggestion().text == "_b"
291 310
292 311 up(event)
293 312 assert get_suggestion().text == "_a"
294 313
295 314 down(event)
296 315 assert get_suggestion().text == "_b"
297 316
298 317 down(event)
299 318 assert get_suggestion().text == "_c"
300 319
301 320
302 321 def create_session_mock():
303 322 session = Mock()
304 323 session.default_buffer = Buffer()
305 324 return session
306 325
307 326
308 327 def test_navigable_provider_connection():
309 328 provider = NavigableAutoSuggestFromHistory()
310 329 provider.skip_lines = 1
311 330
312 331 session_1 = create_session_mock()
313 332 provider.connect(session_1)
314 333
315 334 assert provider.skip_lines == 1
316 335 session_1.default_buffer.on_text_insert.fire()
317 336 assert provider.skip_lines == 0
318 337
319 338 session_2 = create_session_mock()
320 339 provider.connect(session_2)
321 340 provider.skip_lines = 2
322 341
323 342 assert provider.skip_lines == 2
324 343 session_2.default_buffer.on_text_insert.fire()
325 344 assert provider.skip_lines == 0
326 345
327 346 provider.skip_lines = 3
328 347 provider.disconnect()
329 348 session_1.default_buffer.on_text_insert.fire()
330 349 session_2.default_buffer.on_text_insert.fire()
331 350 assert provider.skip_lines == 3
332 351
333 352
334 353 @pytest.fixture
335 354 def ipython_with_prompt():
336 355 ip = get_ipython()
337 356 ip.pt_app = Mock()
338 357 ip.pt_app.key_bindings = create_ipython_shortcuts(ip)
339 358 try:
340 359 yield ip
341 360 finally:
342 361 ip.pt_app = None
343 362
344 363
345 364 def find_bindings_by_command(command):
346 365 ip = get_ipython()
347 366 return [
348 367 binding
349 368 for binding in ip.pt_app.key_bindings.bindings
350 369 if binding.handler == command
351 370 ]
352 371
353 372
354 373 def test_modify_unique_shortcut(ipython_with_prompt):
355 374 original = find_bindings_by_command(accept_token)
356 375 assert len(original) == 1
357 376
358 377 ipython_with_prompt.shortcuts = [
359 378 {"command": "IPython:auto_suggest.accept_token", "new_keys": ["a", "b", "c"]}
360 379 ]
361 380 matched = find_bindings_by_command(accept_token)
362 381 assert len(matched) == 1
363 382 assert list(matched[0].keys) == ["a", "b", "c"]
364 383 assert list(matched[0].keys) != list(original[0].keys)
365 384 assert matched[0].filter == original[0].filter
366 385
367 386 ipython_with_prompt.shortcuts = [
368 387 {"command": "IPython:auto_suggest.accept_token", "new_filter": "always"}
369 388 ]
370 389 matched = find_bindings_by_command(accept_token)
371 390 assert len(matched) == 1
372 391 assert list(matched[0].keys) != ["a", "b", "c"]
373 392 assert list(matched[0].keys) == list(original[0].keys)
374 393 assert matched[0].filter != original[0].filter
375 394
376 395
377 396 def test_disable_shortcut(ipython_with_prompt):
378 397 matched = find_bindings_by_command(accept_token)
379 398 assert len(matched) == 1
380 399
381 400 ipython_with_prompt.shortcuts = [
382 401 {"command": "IPython:auto_suggest.accept_token", "new_keys": []}
383 402 ]
384 403 matched = find_bindings_by_command(accept_token)
385 404 assert len(matched) == 0
386 405
387 406 ipython_with_prompt.shortcuts = []
388 407 matched = find_bindings_by_command(accept_token)
389 408 assert len(matched) == 1
390 409
391 410
392 411 def test_modify_shortcut_with_filters(ipython_with_prompt):
393 412 matched = find_bindings_by_command(skip_over)
394 413 matched_keys = {m.keys[0] for m in matched}
395 414 assert matched_keys == {")", "]", "}", "'", '"'}
396 415
397 416 with pytest.raises(ValueError, match="Multiple shortcuts matching"):
398 417 ipython_with_prompt.shortcuts = [
399 418 {"command": "IPython:auto_match.skip_over", "new_keys": ["x"]}
400 419 ]
401 420
402 421 ipython_with_prompt.shortcuts = [
403 422 {
404 423 "command": "IPython:auto_match.skip_over",
405 424 "new_keys": ["x"],
406 425 "match_filter": "focused_insert & auto_match & followed_by_single_quote",
407 426 }
408 427 ]
409 428 matched = find_bindings_by_command(skip_over)
410 429 matched_keys = {m.keys[0] for m in matched}
411 430 assert matched_keys == {")", "]", "}", "x", '"'}
412 431
413 432
414 433 def example_command():
415 434 pass
416 435
417 436
418 437 def test_add_shortcut_for_new_command(ipython_with_prompt):
419 438 matched = find_bindings_by_command(example_command)
420 439 assert len(matched) == 0
421 440
422 441 with pytest.raises(ValueError, match="example_command is not a known"):
423 442 ipython_with_prompt.shortcuts = [
424 443 {"command": "example_command", "new_keys": ["x"]}
425 444 ]
426 445 matched = find_bindings_by_command(example_command)
427 446 assert len(matched) == 0
428 447
429 448
430 449 def test_modify_shortcut_failure(ipython_with_prompt):
431 450 with pytest.raises(ValueError, match="No shortcuts matching"):
432 451 ipython_with_prompt.shortcuts = [
433 452 {
434 453 "command": "IPython:auto_match.skip_over",
435 454 "match_keys": ["x"],
436 455 "new_keys": ["y"],
437 456 }
438 457 ]
439 458
440 459
441 460 def test_add_shortcut_for_existing_command(ipython_with_prompt):
442 461 matched = find_bindings_by_command(skip_over)
443 462 assert len(matched) == 5
444 463
445 464 with pytest.raises(ValueError, match="Cannot add a shortcut without keys"):
446 465 ipython_with_prompt.shortcuts = [
447 466 {"command": "IPython:auto_match.skip_over", "new_keys": [], "create": True}
448 467 ]
449 468
450 469 ipython_with_prompt.shortcuts = [
451 470 {"command": "IPython:auto_match.skip_over", "new_keys": ["x"], "create": True}
452 471 ]
453 472 matched = find_bindings_by_command(skip_over)
454 473 assert len(matched) == 6
455 474
456 475 ipython_with_prompt.shortcuts = []
457 476 matched = find_bindings_by_command(skip_over)
458 477 assert len(matched) == 5
459 478
460 479
461 480 def test_setting_shortcuts_before_pt_app_init():
462 481 ipython = get_ipython()
463 482 assert ipython.pt_app is None
464 483 shortcuts = [
465 484 {"command": "IPython:auto_match.skip_over", "new_keys": ["x"], "create": True}
466 485 ]
467 486 ipython.shortcuts = shortcuts
468 487 assert ipython.shortcuts == shortcuts
General Comments 0
You need to be logged in to leave comments. Login now