diff options
author | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2019-12-09 16:24:54 -0500 |
---|---|---|
committer | Kevin Van Brunt <kmvanbrunt@gmail.com> | 2019-12-09 16:24:54 -0500 |
commit | 6f16e671971a9fac4edfda9c0117ceaeb5e6487e (patch) | |
tree | ee3a78ca7427729ff9d93c2401f2e3c85bea59d6 | |
parent | cda57dc1a1859408fb25d31178ad0f6e77ede902 (diff) | |
download | cmd2-git-6f16e671971a9fac4edfda9c0117ceaeb5e6487e.tar.gz |
Adding unit tests for text alignment functions
-rw-r--r-- | cmd2/utils.py | 28 | ||||
-rw-r--r-- | tests/test_utils.py | 168 |
2 files changed, 165 insertions, 31 deletions
diff --git a/cmd2/utils.py b/cmd2/utils.py index c8ba5816..d7c9ff19 100644 --- a/cmd2/utils.py +++ b/cmd2/utils.py @@ -642,7 +642,7 @@ def align_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, """ Align text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is - supported. Each line in text will be aligned independently. + supported. If text has line breaks, then each line is aligned independently. There are convenience wrappers around this function: ljustify_text(), center_text(), and rjustify_text() @@ -653,9 +653,8 @@ def align_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, be converted to a space. :param alignment: how to align the text :return: aligned text - :raises: ValueError if text or fill_char contains an unprintable character - TypeError if fill_char is more than one character - + :raises: TypeError if fill_char is more than one character + ValueError if text or fill_char contains an unprintable character """ import io import shutil @@ -663,12 +662,12 @@ def align_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, from . import ansi # Handle tabs - text.replace('\t', ' ' * tab_width) + text = text.replace('\t', ' ' * tab_width) if fill_char == '\t': fill_char = ' ' if len(fill_char) != 1: - raise ValueError("Fill character must be exactly one character long") + raise TypeError("Fill character must be exactly one character long") fill_char_width = ansi.ansi_safe_wcswidth(fill_char) if fill_char_width == -1: @@ -679,22 +678,21 @@ def align_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, else: lines = [''] + if width is None: + width = shutil.get_terminal_size().columns + text_buf = io.StringIO() for index, line in enumerate(lines): if index > 0: text_buf.write('\n') - # Use ansi_safe_wcswidth to support characters with display widths greater than 1 - # as well as ANSI escape sequences + # Use ansi_safe_wcswidth to support characters with display widths + # greater than 1 as well as ANSI escape sequences line_width = ansi.ansi_safe_wcswidth(line) if line_width == -1: - # This can happen if text contains characters like newlines or tabs raise(ValueError("Text to align contains an unprintable character")) - if width is None: - width = shutil.get_terminal_size().columns - # Check if line is wider than the desired final width if width <= line_width: text_buf.write(line) @@ -731,7 +729,7 @@ def ljustify_text(text: str, *, fill_char: str = ' ', width: Optional[int] = Non """ Left justify text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is - supported. Each line in text will be aligned independently. + supported. If text has line breaks, then each line is aligned independently. :param text: text to left justify (Can contain multiple lines) :param fill_char: character that fills the alignment gap. Defaults to space. (Cannot be a line breaking character) @@ -748,7 +746,7 @@ def center_text(text: str, *, fill_char: str = ' ', width: Optional[int] = None, """ Center text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is - supported. Each line in text will be aligned independently. + supported. If text has line breaks, then each line is aligned independently. :param text: text to center (Can contain multiple lines) :param fill_char: character that fills the alignment gap. Defaults to space. (Cannot be a line breaking character) @@ -765,7 +763,7 @@ def rjustify_text(text: str, *, fill_char: str = ' ', width: Optional[int] = Non """ Right justify text for display within a given width. Supports characters with display widths greater than 1. ANSI escape sequences are safely ignored and do not count toward the display width. This means colored text is - supported. Each line in text will be aligned independently. + supported. If text has line breaks, then each line is aligned independently. :param text: text to right justify (Can contain multiple lines) :param fill_char: character that fills the alignment gap. Defaults to space. (Cannot be a line breaking character) diff --git a/tests/test_utils.py b/tests/test_utils.py index 2c43371f..1327064f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -293,21 +293,157 @@ def test_context_flag_exit_err(context_flag): context_flag.__exit__() -def test_center_text_pad_equals(): - msg = 'foo' - fill_char = '=' - centered = cu.center_text(msg, fill_char=fill_char) - assert msg in centered - assert centered.startswith(fill_char) - assert centered.endswith(fill_char) - letters_in_centered = set(centered) - letters_in_msg = set(msg) - assert len(letters_in_centered) == len(letters_in_msg) + 1 - - -def test_center_text_pad_blank(): - msg = 'foo' - fill_char = '' +def test_align_text_fill_char_is_tab(): + text = 'foo' + fill_char = '\t' + width = 5 + aligned = cu.align_text(text, fill_char=fill_char, width=width, alignment=cu.TextAlignment.LEFT) + assert aligned == text + ' ' + +def test_align_text_fill_char_is_too_long(): + text = 'foo' + fill_char = 'fill' + width = 5 + with pytest.raises(TypeError): + cu.align_text(text, fill_char=fill_char, width=width, alignment=cu.TextAlignment.LEFT) +def test_align_text_fill_char_is_unprintable(): + text = 'foo' + fill_char = '\n' + width = 5 with pytest.raises(ValueError): - cu.center_text(msg, fill_char=fill_char) + cu.align_text(text, fill_char=fill_char, width=width, alignment=cu.TextAlignment.LEFT) + +def test_align_text_has_tabs(): + text = '\t\tfoo' + fill_char = '-' + width = 10 + aligned = cu.align_text(text, fill_char=fill_char, width=width, alignment=cu.TextAlignment.LEFT, tab_width=2) + assert aligned == ' ' + 'foo' + '---' + +def test_align_text_blank(): + text = '' + fill_char = '-' + width = 5 + aligned = cu.align_text(text, fill_char=fill_char, width=width, alignment=cu.TextAlignment.LEFT) + assert aligned == text + fill_char * width + +def test_align_text_wider_than_width(): + text = 'long' + fill_char = '-' + width = 3 + aligned = cu.align_text(text, fill_char=fill_char, width=width, alignment=cu.TextAlignment.LEFT) + assert aligned == text + +def test_align_text_term_width(): + import shutil + from cmd2 import ansi + text = 'foo' + fill_char = ' ' + + term_width = shutil.get_terminal_size().columns + expected_fill = (term_width - ansi.ansi_safe_wcswidth(text)) * fill_char + + aligned = cu.align_text(text, fill_char=fill_char, alignment=cu.TextAlignment.LEFT) + assert aligned == text + expected_fill + +def test_left_text(): + text = 'foo' + fill_char = '-' + width = 5 + aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + assert aligned == text + fill_char + fill_char + +def test_left_text_multiline(): + text = "foo\nshoes" + fill_char = '-' + width = 7 + aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + assert aligned == ('foo----\n' + 'shoes--') + +def test_left_text_asian_fill(): + """Test fill_char with display width greater than 1""" + text = 'foo' + fill_char = '苹' + width = 5 + aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + assert aligned == text + fill_char + +def test_left_text_asian_fill_needs_padding(): + """Test when fill_char's display width does not divide evenly into gap""" + text = 'foo' + fill_char = '苹' + width = 6 + aligned = cu.ljustify_text(text, fill_char=fill_char, width=width) + assert aligned == text + fill_char + ' ' + +def test_center_text(): + text = 'foo' + fill_char = '-' + width = 5 + aligned = cu.center_text(text,fill_char=fill_char, width=width) + assert aligned == fill_char + text + fill_char + +def test_center_text_multiline(): + text = "foo\nshoes" + fill_char = '-' + width = 7 + aligned = cu.center_text(text, fill_char=fill_char, width=width) + assert aligned == ('--foo--\n' + '-shoes-') + +def test_center_text_asian_fill(): + """Test fill_char with display width greater than 1""" + text = 'foo' + fill_char = '苹' + width = 7 + aligned = cu.center_text(text, fill_char=fill_char, width=width) + assert aligned == fill_char + text + fill_char + +def test_center_text_asian_fill_needs_right_padding(): + """Test when fill_char's display width does not divide evenly into right gap""" + text = 'foo' + fill_char = '苹' + width = 8 + aligned = cu.center_text(text, fill_char=fill_char, width=width) + assert aligned == fill_char + text + fill_char + ' ' + +def test_center_text_asian_fill_needs_left_and_right_padding(): + """Test when fill_char's display width does not divide evenly into either gap""" + text = 'foo' + fill_char = '苹' + width = 9 + aligned = cu.center_text(text, fill_char=fill_char, width=width) + assert aligned == fill_char + ' ' + text + fill_char + ' ' + +def test_right_text(): + text = 'foo' + fill_char = '-' + width = 5 + aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + assert aligned == fill_char + fill_char + text + +def test_right_text_multiline(): + text = "foo\nshoes" + fill_char = '-' + width = 7 + aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + assert aligned == ('----foo\n' + '--shoes') + +def test_right_text_asian_fill(): + """Test fill_char with display width greater than 1""" + text = 'foo' + fill_char = '苹' + width = 5 + aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + assert aligned == fill_char + text + +def test_right_text_asian_fill_needs_padding(): + """Test when fill_char's display width does not divide evenly into gap""" + text = 'foo' + fill_char = '苹' + width = 6 + aligned = cu.rjustify_text(text, fill_char=fill_char, width=width) + assert aligned == fill_char + ' ' + text |