| 
									
										
										
										
											2018-06-18 04:47:59 -04:00
										 |  |  | "Test pyparse, coverage 96%." | 
					
						
							| 
									
										
										
										
											2018-02-22 01:19:02 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | from idlelib import pyparse | 
					
						
							| 
									
										
										
										
											2018-06-18 04:47:59 -04:00
										 |  |  | import unittest | 
					
						
							|  |  |  | from collections import namedtuple | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-28 17:23:58 -05:00
										 |  |  | class ParseMapTest(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_parsemap(self): | 
					
						
							|  |  |  |         keepwhite = {ord(c): ord(c) for c in ' \t\n\r'} | 
					
						
							|  |  |  |         mapping = pyparse.ParseMap(keepwhite) | 
					
						
							|  |  |  |         self.assertEqual(mapping[ord('\t')], ord('\t')) | 
					
						
							|  |  |  |         self.assertEqual(mapping[ord('a')], ord('x')) | 
					
						
							|  |  |  |         self.assertEqual(mapping[1000], ord('x')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_trans(self): | 
					
						
							|  |  |  |         # trans is the production instance of ParseMap, used in _study1 | 
					
						
							|  |  |  |         parser = pyparse.Parser(4, 4) | 
					
						
							|  |  |  |         self.assertEqual('\t a([{b}])b"c\'d\n'.translate(pyparse.trans), | 
					
						
							| 
									
										
										
										
											2020-01-21 05:11:26 -05:00
										 |  |  |                          'xxx(((x)))x"x\'x\n') | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PyParseTest(unittest.TestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def setUpClass(cls): | 
					
						
							|  |  |  |         cls.parser = pyparse.Parser(indentwidth=4, tabwidth=4) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     def tearDownClass(cls): | 
					
						
							|  |  |  |         del cls.parser | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_init(self): | 
					
						
							|  |  |  |         self.assertEqual(self.parser.indentwidth, 4) | 
					
						
							|  |  |  |         self.assertEqual(self.parser.tabwidth, 4) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |     def test_set_code(self): | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Not empty and doesn't end with newline. | 
					
						
							|  |  |  |         with self.assertRaises(AssertionError): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |             setcode('a') | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         tests = ('', | 
					
						
							|  |  |  |                  'a\n') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for string in tests: | 
					
						
							|  |  |  |             with self.subTest(string=string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(string) | 
					
						
							|  |  |  |                 eq(p.code, string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 eq(p.study_level, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_find_good_parse_start(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         start = p.find_good_parse_start | 
					
						
							| 
									
										
										
										
											2020-02-17 21:47:52 -05:00
										 |  |  |         def char_in_string_false(index): return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # First line starts with 'def' and ends with ':', then 0 is the pos. | 
					
						
							|  |  |  |         setcode('def spam():\n') | 
					
						
							|  |  |  |         eq(start(char_in_string_false), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # First line begins with a keyword in the list and ends | 
					
						
							|  |  |  |         # with an open brace, then 0 is the pos.  This is how | 
					
						
							|  |  |  |         # hyperparser calls this function as the newline is not added | 
					
						
							|  |  |  |         # in the editor, but rather on the call to setcode. | 
					
						
							|  |  |  |         setcode('class spam( ' + ' \n') | 
					
						
							|  |  |  |         eq(start(char_in_string_false), 0) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Split def across lines. | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode('"""This is a module docstring"""\n' | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |                 'class C:\n' | 
					
						
							| 
									
										
										
										
											2020-01-21 05:11:26 -05:00
										 |  |  |                 '    def __init__(self, a,\n' | 
					
						
							|  |  |  |                 '                 b=True):\n' | 
					
						
							|  |  |  |                 '        pass\n' | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         pos0, pos = 33, 42  # Start of 'class...', '    def' lines. | 
					
						
							| 
									
										
										
										
											2020-01-21 05:11:26 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Passing no value or non-callable should fail (issue 32989). | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             start() | 
					
						
							|  |  |  |         with self.assertRaises(TypeError): | 
					
						
							|  |  |  |             start(False) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Make text look like a string.  This returns pos as the start | 
					
						
							|  |  |  |         # position, but it's set to None. | 
					
						
							|  |  |  |         self.assertIsNone(start(is_char_in_string=lambda index: True)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Make all text look like it's not in a string.  This means that it | 
					
						
							|  |  |  |         # found a good start position. | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         eq(start(char_in_string_false), pos) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # If the beginning of the def line is not in a string, then it | 
					
						
							|  |  |  |         # returns that as the index. | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         eq(start(is_char_in_string=lambda index: index > pos), pos) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         # If the beginning of the def line is in a string, then it | 
					
						
							|  |  |  |         # looks for a previous index. | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         eq(start(is_char_in_string=lambda index: index >= pos), pos0) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         # If everything before the 'def' is in a string, then returns None. | 
					
						
							|  |  |  |         # The non-continuation def line returns 44 (see below). | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         eq(start(is_char_in_string=lambda index: index < pos), None) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Code without extra line break in def line - mostly returns the same | 
					
						
							|  |  |  |         # values. | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode('"""This is a module docstring"""\n' | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |                 'class C:\n' | 
					
						
							| 
									
										
										
										
											2020-01-21 05:11:26 -05:00
										 |  |  |                 '    def __init__(self, a, b=True):\n' | 
					
						
							|  |  |  |                 '        pass\n' | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |                 )  # Does not affect class, def positions. | 
					
						
							|  |  |  |         eq(start(char_in_string_false), pos) | 
					
						
							|  |  |  |         eq(start(is_char_in_string=lambda index: index > pos), pos) | 
					
						
							|  |  |  |         eq(start(is_char_in_string=lambda index: index >= pos), pos0) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         # When the def line isn't split, this returns which doesn't match the | 
					
						
							|  |  |  |         # split line test. | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         eq(start(is_char_in_string=lambda index: index < pos), pos) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_set_lo(self): | 
					
						
							|  |  |  |         code = ( | 
					
						
							|  |  |  |                 '"""This is a module docstring"""\n' | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |                 'class C:\n' | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 '    def __init__(self, a,\n' | 
					
						
							|  |  |  |                 '                 b=True):\n' | 
					
						
							|  |  |  |                 '        pass\n' | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         pos = 42 | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         p.set_code(code) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Previous character is not a newline. | 
					
						
							|  |  |  |         with self.assertRaises(AssertionError): | 
					
						
							|  |  |  |             p.set_lo(5) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         # A value of 0 doesn't change self.code. | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         p.set_lo(0) | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         self.assertEqual(p.code, code) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # An index that is preceded by a newline. | 
					
						
							| 
									
										
										
										
											2021-01-24 15:36:02 -08:00
										 |  |  |         p.set_lo(pos) | 
					
						
							|  |  |  |         self.assertEqual(p.code, code[pos:]) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_study1(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         study = p._study1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         (NONE, BACKSLASH, FIRST, NEXT, BRACKET) = range(5) | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'goodlines', | 
					
						
							|  |  |  |                                            'continuation']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('', [0], NONE), | 
					
						
							|  |  |  |             # Docstrings. | 
					
						
							|  |  |  |             TestInfo('"""This is a complete docstring."""\n', [0, 1], NONE), | 
					
						
							|  |  |  |             TestInfo("'''This is a complete docstring.'''\n", [0, 1], NONE), | 
					
						
							|  |  |  |             TestInfo('"""This is a continued docstring.\n', [0, 1], FIRST), | 
					
						
							|  |  |  |             TestInfo("'''This is a continued docstring.\n", [0, 1], FIRST), | 
					
						
							|  |  |  |             TestInfo('"""Closing quote does not match."\n', [0, 1], FIRST), | 
					
						
							|  |  |  |             TestInfo('"""Bracket in docstring [\n', [0, 1], FIRST), | 
					
						
							|  |  |  |             TestInfo("'''Incomplete two line docstring.\n\n", [0, 2], NEXT), | 
					
						
							|  |  |  |             # Single-quoted strings. | 
					
						
							|  |  |  |             TestInfo('"This is a complete string."\n', [0, 1], NONE), | 
					
						
							|  |  |  |             TestInfo('"This is an incomplete string.\n', [0, 1], NONE), | 
					
						
							|  |  |  |             TestInfo("'This is more incomplete.\n\n", [0, 1, 2], NONE), | 
					
						
							|  |  |  |             # Comment (backslash does not continue comments). | 
					
						
							|  |  |  |             TestInfo('# Comment\\\n', [0, 1], NONE), | 
					
						
							|  |  |  |             # Brackets. | 
					
						
							|  |  |  |             TestInfo('("""Complete string in bracket"""\n', [0, 1], BRACKET), | 
					
						
							|  |  |  |             TestInfo('("""Open string in bracket\n', [0, 1], FIRST), | 
					
						
							|  |  |  |             TestInfo('a = (1 + 2) - 5 *\\\n', [0, 1], BACKSLASH),  # No bracket. | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\n                 b):\n', | 
					
						
							|  |  |  |                      [0, 1, 3], NONE), | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\\\n', [0, 1, 2], BRACKET), | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\n', [0, 1, 2], BRACKET), | 
					
						
							|  |  |  |             TestInfo('())\n', [0, 1], NONE),                    # Extra closer. | 
					
						
							|  |  |  |             TestInfo(')(\n', [0, 1], BRACKET),                  # Extra closer. | 
					
						
							| 
									
										
										
										
											2019-06-03 09:51:15 +05:30
										 |  |  |             # For the mismatched example, it doesn't look like continuation. | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |             TestInfo('{)(]\n', [0, 1], NONE),                   # Mismatched. | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string)  # resets study_level | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 study() | 
					
						
							|  |  |  |                 eq(p.study_level, 1) | 
					
						
							|  |  |  |                 eq(p.goodlines, test.goodlines) | 
					
						
							|  |  |  |                 eq(p.continuation, test.continuation) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Called again, just returns without reprocessing. | 
					
						
							|  |  |  |         self.assertIsNone(study()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_get_continuation_type(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         gettype = p.get_continuation_type | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         (NONE, BACKSLASH, FIRST, NEXT, BRACKET) = range(5) | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'continuation']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('', NONE), | 
					
						
							|  |  |  |             TestInfo('"""This is a continuation docstring.\n', FIRST), | 
					
						
							|  |  |  |             TestInfo("'''This is a multiline-continued docstring.\n\n", NEXT), | 
					
						
							|  |  |  |             TestInfo('a = (1 + 2) - 5 *\\\n', BACKSLASH), | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\\\n', BRACKET) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 eq(gettype(), test.continuation) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_study2(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         study = p._study2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'start', 'end', 'lastch', | 
					
						
							|  |  |  |                                            'openbracket', 'bracketing']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('', 0, 0, '', None, ((0, 0),)), | 
					
						
							| 
									
										
										
										
											2019-07-30 18:14:58 -04:00
										 |  |  |             TestInfo("'''This is a multiline continuation docstring.\n\n", | 
					
						
							|  |  |  |                      0, 48, "'", None, ((0, 0), (0, 1), (48, 0))), | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |             TestInfo(' # Comment\\\n', | 
					
						
							|  |  |  |                      0, 12, '', None, ((0, 0), (1, 1), (12, 0))), | 
					
						
							|  |  |  |             # A comment without a space is a special case | 
					
						
							|  |  |  |             TestInfo(' #Comment\\\n', | 
					
						
							|  |  |  |                      0, 0, '', None, ((0, 0),)), | 
					
						
							|  |  |  |             # Backslash continuation. | 
					
						
							|  |  |  |             TestInfo('a = (1 + 2) - 5 *\\\n', | 
					
						
							|  |  |  |                      0, 19, '*', None, ((0, 0), (4, 1), (11, 0))), | 
					
						
							|  |  |  |             # Bracket continuation with close. | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\n                 b):\n', | 
					
						
							|  |  |  |                      1, 48, ':', None, ((1, 0), (17, 1), (46, 0))), | 
					
						
							|  |  |  |             # Bracket continuation with unneeded backslash. | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\\\n', | 
					
						
							|  |  |  |                      1, 28, ',', 17, ((1, 0), (17, 1))), | 
					
						
							|  |  |  |             # Bracket continuation. | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\n', | 
					
						
							|  |  |  |                      1, 27, ',', 17, ((1, 0), (17, 1))), | 
					
						
							|  |  |  |             # Bracket continuation with comment at end of line with text. | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,  # End of line comment.\n', | 
					
						
							|  |  |  |                      1, 51, ',', 17, ((1, 0), (17, 1), (28, 2), (51, 1))), | 
					
						
							|  |  |  |             # Multi-line statement with comment line in between code lines. | 
					
						
							|  |  |  |             TestInfo('  a = ["first item",\n  # Comment line\n    "next item",\n', | 
					
						
							|  |  |  |                      0, 55, ',', 6, ((0, 0), (6, 1), (7, 2), (19, 1), | 
					
						
							|  |  |  |                                      (23, 2), (38, 1), (42, 2), (53, 1))), | 
					
						
							|  |  |  |             TestInfo('())\n', | 
					
						
							|  |  |  |                      0, 4, ')', None, ((0, 0), (0, 1), (2, 0), (3, 0))), | 
					
						
							|  |  |  |             TestInfo(')(\n', 0, 3, '(', 1, ((0, 0), (1, 0), (1, 1))), | 
					
						
							|  |  |  |             # Wrong closers still decrement stack level. | 
					
						
							|  |  |  |             TestInfo('{)(]\n', | 
					
						
							|  |  |  |                      0, 5, ']', None, ((0, 0), (0, 1), (2, 0), (2, 1), (4, 0))), | 
					
						
							|  |  |  |             # Character after backslash. | 
					
						
							|  |  |  |             TestInfo(':\\a\n', 0, 4, '\\a', None, ((0, 0),)), | 
					
						
							|  |  |  |             TestInfo('\n', 0, 0, '', None, ((0, 0),)), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 study() | 
					
						
							|  |  |  |                 eq(p.study_level, 2) | 
					
						
							|  |  |  |                 eq(p.stmt_start, test.start) | 
					
						
							|  |  |  |                 eq(p.stmt_end, test.end) | 
					
						
							|  |  |  |                 eq(p.lastch, test.lastch) | 
					
						
							|  |  |  |                 eq(p.lastopenbracketpos, test.openbracket) | 
					
						
							|  |  |  |                 eq(p.stmt_bracketing, test.bracketing) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Called again, just returns without reprocessing. | 
					
						
							|  |  |  |         self.assertIsNone(study()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_get_num_lines_in_stmt(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         getlines = p.get_num_lines_in_stmt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'lines']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('[x for x in a]\n', 1),      # Closed on one line. | 
					
						
							|  |  |  |             TestInfo('[x\nfor x in a\n', 2),      # Not closed. | 
					
						
							| 
									
										
										
										
											2021-10-07 17:42:38 +02:00
										 |  |  |             TestInfo('[x\\\nfor x in a\\\n', 2),  # "", unneeded backslashes. | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |             TestInfo('[x\nfor x in a\n]\n', 3),   # Closed on multi-line. | 
					
						
							|  |  |  |             TestInfo('\n"""Docstring comment L1"""\nL2\nL3\nL4\n', 1), | 
					
						
							|  |  |  |             TestInfo('\n"""Docstring comment L1\nL2"""\nL3\nL4\n', 1), | 
					
						
							|  |  |  |             TestInfo('\n"""Docstring comment L1\\\nL2\\\nL3\\\nL4\\\n', 4), | 
					
						
							|  |  |  |             TestInfo('\n\n"""Docstring comment L1\\\nL2\\\nL3\\\nL4\\\n"""\n', 5) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Blank string doesn't have enough elements in goodlines. | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode('') | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         with self.assertRaises(IndexError): | 
					
						
							|  |  |  |             getlines() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 eq(getlines(), test.lines) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_compute_bracket_indent(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         indent = p.compute_bracket_indent | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'spaces']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('def function1(self, a,\n', 14), | 
					
						
							|  |  |  |             # Characters after bracket. | 
					
						
							|  |  |  |             TestInfo('\n    def function1(self, a,\n', 18), | 
					
						
							|  |  |  |             TestInfo('\n\tdef function1(self, a,\n', 18), | 
					
						
							|  |  |  |             # No characters after bracket. | 
					
						
							|  |  |  |             TestInfo('\n    def function1(\n', 8), | 
					
						
							|  |  |  |             TestInfo('\n\tdef function1(\n', 8), | 
					
						
							|  |  |  |             TestInfo('\n    def function1(  \n', 8),  # Ignore extra spaces. | 
					
						
							|  |  |  |             TestInfo('[\n"first item",\n  # Comment line\n    "next item",\n', 0), | 
					
						
							|  |  |  |             TestInfo('[\n  "first item",\n  # Comment line\n    "next item",\n', 2), | 
					
						
							|  |  |  |             TestInfo('["first item",\n  # Comment line\n    "next item",\n', 1), | 
					
						
							|  |  |  |             TestInfo('(\n', 4), | 
					
						
							|  |  |  |             TestInfo('(a\n', 1), | 
					
						
							|  |  |  |              ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Must be C_BRACKET continuation type. | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode('def function1(self, a, b):\n') | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         with self.assertRaises(AssertionError): | 
					
						
							|  |  |  |             indent() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |             setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |             eq(indent(), test.spaces) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_compute_backslash_indent(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         indent = p.compute_backslash_indent | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Must be C_BACKSLASH continuation type. | 
					
						
							|  |  |  |         errors = (('def function1(self, a, b\\\n'),  # Bracket. | 
					
						
							|  |  |  |                   ('    """ (\\\n'),                 # Docstring. | 
					
						
							|  |  |  |                   ('a = #\\\n'),                     # Inline comment. | 
					
						
							|  |  |  |                   ) | 
					
						
							|  |  |  |         for string in errors: | 
					
						
							|  |  |  |             with self.subTest(string=string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 with self.assertRaises(AssertionError): | 
					
						
							|  |  |  |                     indent() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ('string', 'spaces')) | 
					
						
							|  |  |  |         tests = (TestInfo('a = (1 + 2) - 5 *\\\n', 4), | 
					
						
							|  |  |  |                  TestInfo('a = 1 + 2 - 5 *\\\n', 4), | 
					
						
							|  |  |  |                  TestInfo('    a = 1 + 2 - 5 *\\\n', 8), | 
					
						
							|  |  |  |                  TestInfo('  a = "spam"\\\n', 6), | 
					
						
							|  |  |  |                  TestInfo('  a = \\\n"a"\\\n', 4), | 
					
						
							|  |  |  |                  TestInfo('  a = #\\\n"a"\\\n', 5), | 
					
						
							|  |  |  |                  TestInfo('a == \\\n', 2), | 
					
						
							|  |  |  |                  TestInfo('a != \\\n', 2), | 
					
						
							|  |  |  |                  # Difference between containing = and those not. | 
					
						
							|  |  |  |                  TestInfo('\\\n', 2), | 
					
						
							|  |  |  |                  TestInfo('    \\\n', 6), | 
					
						
							|  |  |  |                  TestInfo('\t\\\n', 6), | 
					
						
							|  |  |  |                  TestInfo('a\\\n', 3), | 
					
						
							|  |  |  |                  TestInfo('{}\\\n', 4), | 
					
						
							|  |  |  |                  TestInfo('(1 + 2) - 5 *\\\n', 3), | 
					
						
							|  |  |  |                  ) | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 eq(indent(), test.spaces) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_get_base_indent_string(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         baseindent = p.get_base_indent_string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'indent']) | 
					
						
							|  |  |  |         tests = (TestInfo('', ''), | 
					
						
							|  |  |  |                  TestInfo('def a():\n', ''), | 
					
						
							|  |  |  |                  TestInfo('\tdef a():\n', '\t'), | 
					
						
							|  |  |  |                  TestInfo('    def a():\n', '    '), | 
					
						
							|  |  |  |                  TestInfo('    def a(\n', '    '), | 
					
						
							|  |  |  |                  TestInfo('\t\n    def a(\n', '    '), | 
					
						
							|  |  |  |                  TestInfo('\t\n    # Comment.\n', '    '), | 
					
						
							|  |  |  |                  ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 eq(baseindent(), test.indent) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_is_block_opener(self): | 
					
						
							|  |  |  |         yes = self.assertTrue | 
					
						
							|  |  |  |         no = self.assertFalse | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         opener = p.is_block_opener | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'assert_']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('def a():\n', yes), | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\n                 b):\n', yes), | 
					
						
							|  |  |  |             TestInfo(':\n', yes), | 
					
						
							|  |  |  |             TestInfo('a:\n', yes), | 
					
						
							|  |  |  |             TestInfo('):\n', yes), | 
					
						
							|  |  |  |             TestInfo('(:\n', yes), | 
					
						
							|  |  |  |             TestInfo('":\n', no), | 
					
						
							|  |  |  |             TestInfo('\n   def function1(self, a,\n', no), | 
					
						
							|  |  |  |             TestInfo('def function1(self, a):\n    pass\n', no), | 
					
						
							|  |  |  |             TestInfo('# A comment:\n', no), | 
					
						
							|  |  |  |             TestInfo('"""A docstring:\n', no), | 
					
						
							|  |  |  |             TestInfo('"""A docstring:\n', no), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 test.assert_(opener()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_is_block_closer(self): | 
					
						
							|  |  |  |         yes = self.assertTrue | 
					
						
							|  |  |  |         no = self.assertFalse | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         closer = p.is_block_closer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'assert_']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('return\n', yes), | 
					
						
							|  |  |  |             TestInfo('\tbreak\n', yes), | 
					
						
							|  |  |  |             TestInfo('  continue\n', yes), | 
					
						
							|  |  |  |             TestInfo('     raise\n', yes), | 
					
						
							|  |  |  |             TestInfo('pass    \n', yes), | 
					
						
							|  |  |  |             TestInfo('pass\t\n', yes), | 
					
						
							|  |  |  |             TestInfo('return #\n', yes), | 
					
						
							|  |  |  |             TestInfo('raised\n', no), | 
					
						
							|  |  |  |             TestInfo('returning\n', no), | 
					
						
							|  |  |  |             TestInfo('# return\n', no), | 
					
						
							|  |  |  |             TestInfo('"""break\n', no), | 
					
						
							|  |  |  |             TestInfo('"continue\n', no), | 
					
						
							|  |  |  |             TestInfo('def function1(self, a):\n    pass\n', yes), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 test.assert_(closer()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_get_last_stmt_bracketing(self): | 
					
						
							|  |  |  |         eq = self.assertEqual | 
					
						
							|  |  |  |         p = self.parser | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |         setcode = p.set_code | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |         bracketing = p.get_last_stmt_bracketing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         TestInfo = namedtuple('TestInfo', ['string', 'bracket']) | 
					
						
							|  |  |  |         tests = ( | 
					
						
							|  |  |  |             TestInfo('', ((0, 0),)), | 
					
						
							|  |  |  |             TestInfo('a\n', ((0, 0),)), | 
					
						
							|  |  |  |             TestInfo('()()\n', ((0, 0), (0, 1), (2, 0), (2, 1), (4, 0))), | 
					
						
							|  |  |  |             TestInfo('(\n)()\n', ((0, 0), (0, 1), (3, 0), (3, 1), (5, 0))), | 
					
						
							|  |  |  |             TestInfo('()\n()\n', ((3, 0), (3, 1), (5, 0))), | 
					
						
							|  |  |  |             TestInfo('()(\n)\n', ((0, 0), (0, 1), (2, 0), (2, 1), (5, 0))), | 
					
						
							|  |  |  |             TestInfo('(())\n', ((0, 0), (0, 1), (1, 2), (3, 1), (4, 0))), | 
					
						
							|  |  |  |             TestInfo('(\n())\n', ((0, 0), (0, 1), (2, 2), (4, 1), (5, 0))), | 
					
						
							|  |  |  |             # Same as matched test. | 
					
						
							|  |  |  |             TestInfo('{)(]\n', ((0, 0), (0, 1), (2, 0), (2, 1), (4, 0))), | 
					
						
							|  |  |  |             TestInfo('(((())\n', | 
					
						
							|  |  |  |                      ((0, 0), (0, 1), (1, 2), (2, 3), (3, 4), (5, 3), (6, 2))), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for test in tests: | 
					
						
							|  |  |  |             with self.subTest(string=test.string): | 
					
						
							| 
									
										
										
										
											2018-02-23 21:35:27 -05:00
										 |  |  |                 setcode(test.string) | 
					
						
							| 
									
										
										
										
											2018-02-21 22:48:36 -05:00
										 |  |  |                 eq(bracketing(), test.bracket) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     unittest.main(verbosity=2) |