diff -r 5a46ebfa5d90 Lib/idlelib/HyperParser.py --- a/Lib/idlelib/HyperParser.py Fri Jun 06 17:43:19 2014 -0400 +++ b/Lib/idlelib/HyperParser.py Sat Jun 07 20:18:16 2014 +0530 @@ -64,7 +64,7 @@ self.bracketing = parser.get_last_stmt_bracketing() # find which pairs of bracketing are openers. These always correspond # to a character of rawtext. - self.isopener = [i>0 and self.bracketing[i][1] > self.bracketing[i-1][1] + self.isopener = [i>0 and self.bracketing[i][1]>self.bracketing[i-1][1] for i in range(len(self.bracketing))] self.set_index(index) @@ -76,7 +76,8 @@ indexinrawtext = \ len(self.rawtext) - len(self.text.get(index, self.stopatindex)) if indexinrawtext < 0: - raise ValueError("The index given is before the analyzed statement") + raise ValueError("The index given is before the analyzed " + "statement") self.indexinrawtext = indexinrawtext # find the rightmost bracket to which index belongs self.indexbracket = 0 @@ -93,7 +94,7 @@ # The bracket to which we belong should be an opener. # If it's an opener, it has to have a character. return self.isopener[self.indexbracket] and \ - self.rawtext[self.bracketing[self.indexbracket][0]] in ('"', "'") + self.rawtext[self.bracketing[self.indexbracket][0]] in ('"', "'") def is_in_code(self): """Is the index given to the HyperParser is in a normal code?""" @@ -143,7 +144,7 @@ _whitespace_chars = " \t\n\\" # This string includes all chars that may be in an identifier _id_chars = string.ascii_letters + string.digits + "_" - # This string includes all chars that may be the first char of an identifier + # This string includes all chars that may be the 1st char of an identifier _id_first_chars = string.ascii_letters + "_" # Given a string and pos, return the number of chars in the identifier @@ -177,7 +178,7 @@ postdot_phase = True while 1: - # Eat whitespaces, comments, and if postdot_phase is False - one dot + # Eat whitespaces, comments, and if postdot_phase is False - a dot while 1: if pos>brck_limit and rawtext[pos-1] in self._whitespace_chars: # Eat a whitespace @@ -244,3 +245,7 @@ break return rawtext[last_identifier_pos:self.indexinrawtext] + +if __name__ == '__main__': + import unittest + unittest.main('idlelib.idle_test.test_hyperparser', verbosity=2) diff -r 5a46ebfa5d90 Lib/idlelib/idle_test/test_hyperparser.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/idlelib/idle_test/test_hyperparser.py Sat Jun 07 20:18:16 2014 +0530 @@ -0,0 +1,177 @@ +"""Unittest for idlelib.HyperParser""" +from test.support import requires +requires('gui') + +import unittest +from idlelib.HyperParser import HyperParser +from tkinter import Text + +class DummyEditwin: + def __init__(self, text): + self.text = text + self.indentwidth = 8 + self.tabwidth = 8 + self.context_use_ps1 = True + + # existing code from EditorWindow + def _build_char_in_string_func(self, startindex): + def inner(offset, _startindex=startindex, + _icis=self.is_char_in_string): + return _icis(_startindex + "+%dc" % offset) + return inner + + # existing code from EditorWindow + def is_char_in_string(self, text_index): + if self.color: + # Return true iff colorizer hasn't (re)gotten this far + # yet, or the character is tagged as being in a string + return self.text.tag_prevrange("TODO", text_index) or \ + "STRING" in self.text.tag_names(text_index) + else: + # The colorizer is missing: assume the worst + return 1 + +class HyperParserTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.text = Text() + cls.editwin = DummyEditwin(cls.text) + + @classmethod + def tearDownClass(cls): + cls.text.destroy() + del cls.text + + def setUp(self): + code = [] + code.append('"""This is a module docstring"""') + code.append('# this line is a comment') + code.append('x = "this is a string"') + code.append("y = 'this is also a string'") + code.append('l = [i for i in range(10)]') + code.append('m = [py*py for') + code.append(' py in l]') + code.append('x.__len__') + code.append("z = ((r'asdf')+('asdf')))") + self.text.insert('insert', '\n'.join(code)) + + def tearDown(self): + self.text.delete('1.0', 'end') + self.editwin.context_use_ps1 = True + + def get_parser(self, index): + """ + Return a parser object with index at 'index' + """ + return HyperParser(self.editwin, index) + + def test_init(self): + """ + test corner cases in the init method + """ + with self.assertRaises(ValueError) as ve: + self.text.tag_add('console', '1.0', '1.end') + p = self.get_parser('1.5') + self.assertIn('before the analyzed', str(ve.exception)) + + # test without ps1 + self.editwin.context_use_ps1 = False + # reason for the constants explained in EditorWindow + self.editwin.num_context_lines = 50, 500, 5000000 + p = self.get_parser('end') + self.assertEqual(p.rawtext, self.text.get('1.0', 'end')) + + def test_is_in_string(self): + get = self.get_parser + + p = get('1.0') + self.assertFalse(p.is_in_string()) + p = get('1.4') + self.assertTrue(p.is_in_string()) + p = get('2.3') + self.assertFalse(p.is_in_string()) + p = get('3.3') + self.assertFalse(p.is_in_string()) + p = get('3.7') + self.assertTrue(p.is_in_string()) + p = get('4.6') + self.assertTrue(p.is_in_string()) + + def test_is_in_code(self): + get = self.get_parser + + p = get('1.0') + self.assertTrue(p.is_in_code()) + p = get('1.1') + self.assertFalse(p.is_in_code()) + p = get('2.5') + self.assertFalse(p.is_in_code()) + p = get('3.4') + self.assertTrue(p.is_in_code()) + p = get('3.6') + self.assertFalse(p.is_in_code()) + p = get('4.14') + self.assertFalse(p.is_in_code()) + + def test_get_surrounding_bracket(self): + get = self.get_parser + + def without_mustclose(parser): + # a utility function to get surrounding bracket + # with mustclose=False + return parser.get_surrounding_brackets(mustclose=False) + + def with_mustclose(parser): + # a utility function to get surrounding bracket + # with mustclose=True + return parser.get_surrounding_brackets(mustclose=True) + + p = get('3.2') + self.assertIsNone(with_mustclose(p)) + self.assertIsNone(without_mustclose(p)) + + p = get('5.6') + self.assertTupleEqual(without_mustclose(p), ('5.4', '5.25')) + self.assertTupleEqual(without_mustclose(p), with_mustclose(p)) + + p = get('5.23') + self.assertTupleEqual(without_mustclose(p), ('5.21', '5.24')) + self.assertTupleEqual(without_mustclose(p), with_mustclose(p)) + + p = get('6.15') + self.assertTupleEqual(without_mustclose(p), ('6.4', '6.end')) + self.assertIsNone(with_mustclose(p)) + + p = get('9.end') + self.assertIsNone(with_mustclose(p)) + self.assertIsNone(without_mustclose(p)) + + def test_get_expression(self): + get = self.get_parser + + p = get('4.7') + with self.assertRaises(ValueError) as ve: + p.get_expression() + self.assertIn('is inside a code', str(ve.exception)) + + p = get('4.2') + self.assertEqual(p.get_expression(), 'y ') + + p = get('5.25') + self.assertEqual(p.get_expression(), 'range(10)') + + p = get('6.7') + self.assertEqual(p.get_expression(), 'py') + + p = get('6.8') + self.assertEqual(p.get_expression(), '') + + p = get('8.end') + self.assertEqual(p.get_expression(), 'x.__len__') + + p = get('9.13') + self.assertEqual(p.get_expression(), "r'asdf'") + +if __name__ == '__main__': + unittest.main(verbosity=2)