Skip to content

Commit f5ba956

Browse files
test existing suggestion box behavior
1 parent f21a68b commit f5ba956

File tree

2 files changed

+151
-15
lines changed

2 files changed

+151
-15
lines changed

bpython/curtsiesfrontend/repl.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ def paint(self, about_to_exit=False, user_quit=False):
12601260
the idea is that we don't need to worry about that here, instead every
12611261
frame is completely redrawn because less state is cool!
12621262
"""
1263-
# The hairiest function in the curtsies - a cleanup would be great.
1263+
# The hairiest function in the curtsies
12641264
if about_to_exit:
12651265
# exception to not changing state!
12661266
self.clean_up_current_line_for_exit()
@@ -1501,6 +1501,7 @@ def _set_current_line(self, line, update_completion=True,
15011501
if clear_special_mode:
15021502
self.special_mode = None
15031503
self.unhighlight_paren()
1504+
15041505
current_line = property(_get_current_line, _set_current_line, None,
15051506
"The current line")
15061507

bpython/test/test_curtsies_painting.py

Lines changed: 149 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# coding: utf8
22
from __future__ import unicode_literals
3-
import sys
3+
import itertools
4+
import string
45
import os
6+
import sys
57
from contextlib import contextmanager
68

79
from curtsies.formatstringarray import FormatStringTest, fsarray
@@ -21,6 +23,7 @@
2123
def setup_config():
2224
config_struct = config.Struct()
2325
config.loadini(config_struct, os.devnull)
26+
config_struct.cli_suggestion_width = 1
2427
return config_struct
2528

2629

@@ -48,13 +51,18 @@ def _request_refresh(inner_self):
4851
self.repl.rl_history = History()
4952
self.repl.height, self.repl.width = (5, 10)
5053

54+
@property
55+
def locals(self):
56+
return self.repl.coderunner.interp.locals
57+
5158
def assert_paint(self, screen, cursor_row_col):
5259
array, cursor_pos = self.repl.paint()
5360
self.assertFSArraysEqual(array, screen)
5461
self.assertEqual(cursor_pos, cursor_row_col)
5562

56-
def assert_paint_ignoring_formatting(self, screen, cursor_row_col=None):
57-
array, cursor_pos = self.repl.paint()
63+
def assert_paint_ignoring_formatting(self, screen, cursor_row_col=None,
64+
**paint_kwargs):
65+
array, cursor_pos = self.repl.paint(**paint_kwargs)
5866
self.assertFSArraysEqualIgnoringFormatting(array, screen)
5967
if cursor_row_col is not None:
6068
self.assertEqual(cursor_pos, cursor_row_col)
@@ -96,15 +104,15 @@ def test_completion(self):
96104
self.cursor_offset = 2
97105
if config.supports_box_chars():
98106
screen = ['>>> an',
99-
'┌───────────────────────┐',
100-
'│ and any( │',
101-
'└───────────────────────┘',
107+
'┌──────────────────────────────┐',
108+
'│ and any( │',
109+
'└──────────────────────────────┘',
102110
'Welcome to bpython! Press <F1> f']
103111
else:
104112
screen = ['>>> an',
105-
'+-----------------------+',
106-
'| and any( |',
107-
'+-----------------------+',
113+
'+------------------------------+',
114+
'| and any( |',
115+
'+------------------------------+',
108116
'Welcome to bpython! Press <F1> f']
109117
self.assert_paint_ignoring_formatting(screen, (0, 4))
110118

@@ -155,7 +163,7 @@ def output_to_repl(repl):
155163
sys.stdout, sys.stderr = old_out, old_err
156164

157165

158-
class TestCurtsiesRewindRedraw(CurtsiesPaintingTest):
166+
class HigherLevelCurtsiesPaintingTest(CurtsiesPaintingTest):
159167
def refresh(self):
160168
self.refresh_requests.append(RefreshRequestEvent())
161169

@@ -194,6 +202,12 @@ def _request_refresh(inner_self):
194202
self.repl.rl_history = History()
195203
self.repl.height, self.repl.width = (5, 32)
196204

205+
def send_key(self, key):
206+
self.repl.process_event('<SPACE>' if key == ' ' else key)
207+
self.repl.paint() # has some side effects we need to be wary of
208+
209+
210+
class TestCurtsiesRewindRedraw(HigherLevelCurtsiesPaintingTest):
197211
def test_rewind(self):
198212
self.repl.current_line = '1 + 1'
199213
self.enter()
@@ -564,10 +578,6 @@ def test_unhighlight_paren_bugs(self):
564578
green("... ") + yellow(')') + bold(cyan(" "))])
565579
self.assert_paint(screen, (1, 6))
566580

567-
def send_key(self, key):
568-
self.repl.process_event('<SPACE>' if key == ' ' else key)
569-
self.repl.paint() # has some side effects we need to be wary of
570-
571581
def test_472(self):
572582
[self.send_key(c) for c in "(1, 2, 3)"]
573583
with output_to_repl(self.repl):
@@ -586,3 +596,128 @@ def test_472(self):
586596
'(1, 4, 3)',
587597
'>>> ']
588598
self.assert_paint_ignoring_formatting(screen, (4, 4))
599+
600+
601+
def completion_target(num_names, chars_in_first_name=1):
602+
class Class(object):
603+
pass
604+
605+
if chars_in_first_name < 1:
606+
raise ValueError('need at least one char in each name')
607+
elif chars_in_first_name == 1 and num_names > len(string.ascii_letters):
608+
raise ValueError('need more chars to make so many names')
609+
610+
names = gen_names()
611+
if num_names > 0:
612+
setattr(Class, 'a' * chars_in_first_name, 1)
613+
next(names) # use the above instead of first name
614+
for _, name in zip(range(num_names - 1), names):
615+
setattr(Class, name, 0)
616+
617+
return Class()
618+
619+
620+
def gen_names():
621+
for letters in itertools.chain(
622+
itertools.combinations_with_replacement(string.ascii_letters, 1),
623+
itertools.combinations_with_replacement(string.ascii_letters, 2)):
624+
yield ''.join(letters)
625+
626+
627+
class TestCompletionHelpers(TestCase):
628+
def test_gen_names(self):
629+
self.assertEqual(list(zip([1, 2, 3], gen_names())),
630+
[(1, 'a'), (2, 'b'), (3, 'c')])
631+
632+
def test_completion_target(self):
633+
target = completion_target(14)
634+
self.assertEqual(len([x for x in dir(target)
635+
if not x.startswith('_')]),
636+
14)
637+
638+
639+
class TestCurtsiesInfoboxPaint(HigherLevelCurtsiesPaintingTest):
640+
def test_simple(self):
641+
self.repl.width, self.repl.height = (20, 30)
642+
self.locals['abc'] = completion_target(3, 50)
643+
self.repl.current_line = 'abc'
644+
self.repl.cursor_offset = 3
645+
self.repl.process_event('.')
646+
screen = ['>>> abc.',
647+
'+------------------+',
648+
'| aaaaaaaaaaaaaaaa |',
649+
'| b |',
650+
'| c |',
651+
'+------------------+']
652+
self.assert_paint_ignoring_formatting(screen, (0, 8))
653+
654+
def test_fill_screen(self):
655+
self.repl.width, self.repl.height = (20, 15)
656+
self.locals['abc'] = completion_target(20, 100)
657+
self.repl.current_line = 'abc'
658+
self.repl.cursor_offset = 3
659+
self.repl.process_event('.')
660+
screen = ['>>> abc.',
661+
'+------------------+',
662+
'| aaaaaaaaaaaaaaaa |',
663+
'| b |',
664+
'| c |',
665+
'| d |',
666+
'| e |',
667+
'| f |',
668+
'| g |',
669+
'| h |',
670+
'| i |',
671+
'| j |',
672+
'| k |',
673+
'| l |',
674+
'+------------------+']
675+
self.assert_paint_ignoring_formatting(screen, (0, 8))
676+
677+
def test_lower_on_screen(self):
678+
self.repl.get_top_usable_line = lambda: 10 # halfway down terminal
679+
self.repl.width, self.repl.height = (20, 15)
680+
self.locals['abc'] = completion_target(20, 100)
681+
self.repl.current_line = 'abc'
682+
self.repl.cursor_offset = 3
683+
self.repl.process_event('.')
684+
screen = ['>>> abc.',
685+
'+------------------+',
686+
'| aaaaaaaaaaaaaaaa |',
687+
'| b |',
688+
'| c |',
689+
'| d |',
690+
'| e |',
691+
'| f |',
692+
'| g |',
693+
'| h |',
694+
'| i |',
695+
'| j |',
696+
'| k |',
697+
'| l |',
698+
'+------------------+']
699+
self.assert_paint_ignoring_formatting(screen, (0, 8))
700+
701+
def test_at_bottom_of_screen(self):
702+
self.repl.get_top_usable_line = lambda: 17 # two lines from bottom
703+
self.repl.width, self.repl.height = (20, 15)
704+
self.locals['abc'] = completion_target(20, 100)
705+
self.repl.current_line = 'abc'
706+
self.repl.cursor_offset = 3
707+
self.repl.process_event('.')
708+
screen = ['>>> abc.',
709+
'+------------------+',
710+
'| aaaaaaaaaaaaaaaa |',
711+
'| b |',
712+
'| c |',
713+
'| d |',
714+
'| e |',
715+
'| f |',
716+
'| g |',
717+
'| h |',
718+
'| i |',
719+
'| j |',
720+
'| k |',
721+
'| l |',
722+
'+------------------+']
723+
self.assert_paint_ignoring_formatting(screen, (0, 8))

0 commit comments

Comments
 (0)