Home | History | Annotate | Download | only in idle_test
      1 # Test the functions and main class method of FormatParagraph.py
      2 import unittest
      3 from idlelib import FormatParagraph as fp
      4 from idlelib.EditorWindow import EditorWindow
      5 from Tkinter import Tk, Text
      6 from test.test_support import requires
      7 
      8 
      9 class Is_Get_Test(unittest.TestCase):
     10     """Test the is_ and get_ functions"""
     11     test_comment = '# This is a comment'
     12     test_nocomment = 'This is not a comment'
     13     trailingws_comment = '# This is a comment   '
     14     leadingws_comment = '    # This is a comment'
     15     leadingws_nocomment = '    This is not a comment'
     16 
     17     def test_is_all_white(self):
     18         self.assertTrue(fp.is_all_white(''))
     19         self.assertTrue(fp.is_all_white('\t\n\r\f\v'))
     20         self.assertFalse(fp.is_all_white(self.test_comment))
     21 
     22     def test_get_indent(self):
     23         Equal = self.assertEqual
     24         Equal(fp.get_indent(self.test_comment), '')
     25         Equal(fp.get_indent(self.trailingws_comment), '')
     26         Equal(fp.get_indent(self.leadingws_comment), '    ')
     27         Equal(fp.get_indent(self.leadingws_nocomment), '    ')
     28 
     29     def test_get_comment_header(self):
     30         Equal = self.assertEqual
     31         # Test comment strings
     32         Equal(fp.get_comment_header(self.test_comment), '#')
     33         Equal(fp.get_comment_header(self.trailingws_comment), '#')
     34         Equal(fp.get_comment_header(self.leadingws_comment), '    #')
     35         # Test non-comment strings
     36         Equal(fp.get_comment_header(self.leadingws_nocomment), '    ')
     37         Equal(fp.get_comment_header(self.test_nocomment), '')
     38 
     39 
     40 class FindTest(unittest.TestCase):
     41     """Test the find_paragraph function in FormatParagraph.
     42 
     43     Using the runcase() function, find_paragraph() is called with 'mark' set at
     44     multiple indexes before and inside the test paragraph.
     45 
     46     It appears that code with the same indentation as a quoted string is grouped
     47     as part of the same paragraph, which is probably incorrect behavior.
     48     """
     49 
     50     @classmethod
     51     def setUpClass(cls):
     52         from idlelib.idle_test.mock_tk import Text
     53         cls.text = Text()
     54 
     55     def runcase(self, inserttext, stopline, expected):
     56         # Check that find_paragraph returns the expected paragraph when
     57         # the mark index is set to beginning, middle, end of each line
     58         # up to but not including the stop line
     59         text = self.text
     60         text.insert('1.0', inserttext)
     61         for line in range(1, stopline):
     62             linelength = int(text.index("%d.end" % line).split('.')[1])
     63             for col in (0, linelength//2, linelength):
     64                 tempindex = "%d.%d" % (line, col)
     65                 self.assertEqual(fp.find_paragraph(text, tempindex), expected)
     66         text.delete('1.0', 'end')
     67 
     68     def test_find_comment(self):
     69         comment = (
     70             "# Comment block with no blank lines before\n"
     71             "# Comment line\n"
     72             "\n")
     73         self.runcase(comment, 3, ('1.0', '3.0', '#', comment[0:58]))
     74 
     75         comment = (
     76             "\n"
     77             "# Comment block with whitespace line before and after\n"
     78             "# Comment line\n"
     79             "\n")
     80         self.runcase(comment, 4, ('2.0', '4.0', '#', comment[1:70]))
     81 
     82         comment = (
     83             "\n"
     84             "    # Indented comment block with whitespace before and after\n"
     85             "    # Comment line\n"
     86             "\n")
     87         self.runcase(comment, 4, ('2.0', '4.0', '    #', comment[1:82]))
     88 
     89         comment = (
     90             "\n"
     91             "# Single line comment\n"
     92             "\n")
     93         self.runcase(comment, 3, ('2.0', '3.0', '#', comment[1:23]))
     94 
     95         comment = (
     96             "\n"
     97             "    # Single line comment with leading whitespace\n"
     98             "\n")
     99         self.runcase(comment, 3, ('2.0', '3.0', '    #', comment[1:51]))
    100 
    101         comment = (
    102             "\n"
    103             "# Comment immediately followed by code\n"
    104             "x = 42\n"
    105             "\n")
    106         self.runcase(comment, 3, ('2.0', '3.0', '#', comment[1:40]))
    107 
    108         comment = (
    109             "\n"
    110             "    # Indented comment immediately followed by code\n"
    111             "x = 42\n"
    112             "\n")
    113         self.runcase(comment, 3, ('2.0', '3.0', '    #', comment[1:53]))
    114 
    115         comment = (
    116             "\n"
    117             "# Comment immediately followed by indented code\n"
    118             "    x = 42\n"
    119             "\n")
    120         self.runcase(comment, 3, ('2.0', '3.0', '#', comment[1:49]))
    121 
    122     def test_find_paragraph(self):
    123         teststring = (
    124             '"""String with no blank lines before\n'
    125             'String line\n'
    126             '"""\n'
    127             '\n')
    128         self.runcase(teststring, 4, ('1.0', '4.0', '', teststring[0:53]))
    129 
    130         teststring = (
    131             "\n"
    132             '"""String with whitespace line before and after\n'
    133             'String line.\n'
    134             '"""\n'
    135             '\n')
    136         self.runcase(teststring, 5, ('2.0', '5.0', '', teststring[1:66]))
    137 
    138         teststring = (
    139             '\n'
    140             '    """Indented string with whitespace before and after\n'
    141             '    Comment string.\n'
    142             '    """\n'
    143             '\n')
    144         self.runcase(teststring, 5, ('2.0', '5.0', '    ', teststring[1:85]))
    145 
    146         teststring = (
    147             '\n'
    148             '"""Single line string."""\n'
    149             '\n')
    150         self.runcase(teststring, 3, ('2.0', '3.0', '', teststring[1:27]))
    151 
    152         teststring = (
    153             '\n'
    154             '    """Single line string with leading whitespace."""\n'
    155             '\n')
    156         self.runcase(teststring, 3, ('2.0', '3.0', '    ', teststring[1:55]))
    157 
    158 
    159 class ReformatFunctionTest(unittest.TestCase):
    160     """Test the reformat_paragraph function without the editor window."""
    161 
    162     def test_reformat_paragraph(self):
    163         Equal = self.assertEqual
    164         reform = fp.reformat_paragraph
    165         hw = "O hello world"
    166         Equal(reform(' ', 1), ' ')
    167         Equal(reform("Hello    world", 20), "Hello  world")
    168 
    169         # Test without leading newline
    170         Equal(reform(hw, 1), "O\nhello\nworld")
    171         Equal(reform(hw, 6), "O\nhello\nworld")
    172         Equal(reform(hw, 7), "O hello\nworld")
    173         Equal(reform(hw, 12), "O hello\nworld")
    174         Equal(reform(hw, 13), "O hello world")
    175 
    176         # Test with leading newline
    177         hw = "\nO hello world"
    178         Equal(reform(hw, 1), "\nO\nhello\nworld")
    179         Equal(reform(hw, 6), "\nO\nhello\nworld")
    180         Equal(reform(hw, 7), "\nO hello\nworld")
    181         Equal(reform(hw, 12), "\nO hello\nworld")
    182         Equal(reform(hw, 13), "\nO hello world")
    183 
    184 
    185 class ReformatCommentTest(unittest.TestCase):
    186     """Test the reformat_comment function without the editor window."""
    187 
    188     def test_reformat_comment(self):
    189         Equal = self.assertEqual
    190 
    191         # reformat_comment formats to a minimum of 20 characters
    192         test_string = (
    193             "    \"\"\"this is a test of a reformat for a triple quoted string"
    194             " will it reformat to less than 70 characters for me?\"\"\"")
    195         result = fp.reformat_comment(test_string, 70, "    ")
    196         expected = (
    197             "    \"\"\"this is a test of a reformat for a triple quoted string will it\n"
    198             "    reformat to less than 70 characters for me?\"\"\"")
    199         Equal(result, expected)
    200 
    201         test_comment = (
    202             "# this is a test of a reformat for a triple quoted string will "
    203             "it reformat to less than 70 characters for me?")
    204         result = fp.reformat_comment(test_comment, 70, "#")
    205         expected = (
    206             "# this is a test of a reformat for a triple quoted string will it\n"
    207             "# reformat to less than 70 characters for me?")
    208         Equal(result, expected)
    209 
    210 
    211 class FormatClassTest(unittest.TestCase):
    212     def test_init_close(self):
    213         instance = fp.FormatParagraph('editor')
    214         self.assertEqual(instance.editwin, 'editor')
    215         instance.close()
    216         self.assertEqual(instance.editwin, None)
    217 
    218 
    219 # For testing format_paragraph_event, Initialize FormatParagraph with
    220 # a mock Editor with .text and  .get_selection_indices.  The text must
    221 # be a Text wrapper that adds two methods
    222 
    223 # A real EditorWindow creates unneeded, time-consuming baggage and
    224 # sometimes emits shutdown warnings like this:
    225 # "warning: callback failed in WindowList <class '_tkinter.TclError'>
    226 # : invalid command name ".55131368.windows".
    227 # Calling EditorWindow._close in tearDownClass prevents this but causes
    228 # other problems (windows left open).
    229 
    230 class TextWrapper:
    231     def __init__(self, master):
    232         self.text = Text(master=master)
    233     def __getattr__(self, name):
    234         return getattr(self.text, name)
    235     def undo_block_start(self): pass
    236     def undo_block_stop(self): pass
    237 
    238 class Editor:
    239     def __init__(self, root):
    240         self.text = TextWrapper(root)
    241     get_selection_indices = EditorWindow. get_selection_indices.im_func
    242 
    243 class FormatEventTest(unittest.TestCase):
    244     """Test the formatting of text inside a Text widget.
    245 
    246     This is done with FormatParagraph.format.paragraph_event,
    247     which calls functions in the module as appropriate.
    248     """
    249     test_string = (
    250         "    '''this is a test of a reformat for a triple "
    251         "quoted string will it reformat to less than 70 "
    252         "characters for me?'''\n")
    253     multiline_test_string = (
    254         "    '''The first line is under the max width.\n"
    255         "    The second line's length is way over the max width. It goes "
    256         "on and on until it is over 100 characters long.\n"
    257         "    Same thing with the third line. It is also way over the max "
    258         "width, but FormatParagraph will fix it.\n"
    259         "    '''\n")
    260     multiline_test_comment = (
    261         "# The first line is under the max width.\n"
    262         "# The second line's length is way over the max width. It goes on "
    263         "and on until it is over 100 characters long.\n"
    264         "# Same thing with the third line. It is also way over the max "
    265         "width, but FormatParagraph will fix it.\n"
    266         "# The fourth line is short like the first line.")
    267 
    268     @classmethod
    269     def setUpClass(cls):
    270         requires('gui')
    271         cls.root = Tk()
    272         editor = Editor(root=cls.root)
    273         cls.text = editor.text.text  # Test code does not need the wrapper.
    274         cls.formatter = fp.FormatParagraph(editor).format_paragraph_event
    275         # Sets the insert mark just after the re-wrapped and inserted  text.
    276 
    277     @classmethod
    278     def tearDownClass(cls):
    279         del cls.text, cls.formatter
    280         cls.root.destroy()
    281         del cls.root
    282 
    283     def test_short_line(self):
    284         self.text.insert('1.0', "Short line\n")
    285         self.formatter("Dummy")
    286         self.assertEqual(self.text.get('1.0', 'insert'), "Short line\n" )
    287         self.text.delete('1.0', 'end')
    288 
    289     def test_long_line(self):
    290         text = self.text
    291 
    292         # Set cursor ('insert' mark) to '1.0', within text.
    293         text.insert('1.0', self.test_string)
    294         text.mark_set('insert', '1.0')
    295         self.formatter('ParameterDoesNothing', limit=70)
    296         result = text.get('1.0', 'insert')
    297         # find function includes \n
    298         expected = (
    299 "    '''this is a test of a reformat for a triple quoted string will it\n"
    300 "    reformat to less than 70 characters for me?'''\n")  # yes
    301         self.assertEqual(result, expected)
    302         text.delete('1.0', 'end')
    303 
    304         # Select from 1.11 to line end.
    305         text.insert('1.0', self.test_string)
    306         text.tag_add('sel', '1.11', '1.end')
    307         self.formatter('ParameterDoesNothing', limit=70)
    308         result = text.get('1.0', 'insert')
    309         # selection excludes \n
    310         expected = (
    311 "    '''this is a test of a reformat for a triple quoted string will it reformat\n"
    312 " to less than 70 characters for me?'''")  # no
    313         self.assertEqual(result, expected)
    314         text.delete('1.0', 'end')
    315 
    316     def test_multiple_lines(self):
    317         text = self.text
    318         #  Select 2 long lines.
    319         text.insert('1.0', self.multiline_test_string)
    320         text.tag_add('sel', '2.0', '4.0')
    321         self.formatter('ParameterDoesNothing', limit=70)
    322         result = text.get('2.0', 'insert')
    323         expected = (
    324 "    The second line's length is way over the max width. It goes on and\n"
    325 "    on until it is over 100 characters long. Same thing with the third\n"
    326 "    line. It is also way over the max width, but FormatParagraph will\n"
    327 "    fix it.\n")
    328         self.assertEqual(result, expected)
    329         text.delete('1.0', 'end')
    330 
    331     def test_comment_block(self):
    332         text = self.text
    333 
    334         # Set cursor ('insert') to '1.0', within block.
    335         text.insert('1.0', self.multiline_test_comment)
    336         self.formatter('ParameterDoesNothing', limit=70)
    337         result = text.get('1.0', 'insert')
    338         expected = (
    339 "# The first line is under the max width. The second line's length is\n"
    340 "# way over the max width. It goes on and on until it is over 100\n"
    341 "# characters long. Same thing with the third line. It is also way over\n"
    342 "# the max width, but FormatParagraph will fix it. The fourth line is\n"
    343 "# short like the first line.\n")
    344         self.assertEqual(result, expected)
    345         text.delete('1.0', 'end')
    346 
    347         # Select line 2, verify line 1 unaffected.
    348         text.insert('1.0', self.multiline_test_comment)
    349         text.tag_add('sel', '2.0', '3.0')
    350         self.formatter('ParameterDoesNothing', limit=70)
    351         result = text.get('1.0', 'insert')
    352         expected = (
    353 "# The first line is under the max width.\n"
    354 "# The second line's length is way over the max width. It goes on and\n"
    355 "# on until it is over 100 characters long.\n")
    356         self.assertEqual(result, expected)
    357         text.delete('1.0', 'end')
    358 
    359 # The following block worked with EditorWindow but fails with the mock.
    360 # Lines 2 and 3 get pasted together even though the previous block left
    361 # the previous line alone. More investigation is needed.
    362 ##        # Select lines 3 and 4
    363 ##        text.insert('1.0', self.multiline_test_comment)
    364 ##        text.tag_add('sel', '3.0', '5.0')
    365 ##        self.formatter('ParameterDoesNothing')
    366 ##        result = text.get('3.0', 'insert')
    367 ##        expected = (
    368 ##"# Same thing with the third line. It is also way over the max width,\n"
    369 ##"# but FormatParagraph will fix it. The fourth line is short like the\n"
    370 ##"# first line.\n")
    371 ##        self.assertEqual(result, expected)
    372 ##        text.delete('1.0', 'end')
    373 
    374 
    375 if __name__ == '__main__':
    376     unittest.main(verbosity=2, exit=2)
    377