bug 1310980, part 8: defined and tested behaviour for all-whitespace files
MozReview-Commit-ID: ARYGW2hrHkw
--- a/compare_locales/parser.py
+++ b/compare_locales/parser.py
@@ -156,18 +156,34 @@ class Junk(object):
# getters
all = property(get_all)
val = property(get_all)
def __repr__(self):
return self.key
+class Whitespace(Entity):
+ '''Entity-like object representing an empty file with whitespace,
+ if allowed
+ '''
+ def __init__(self, ctx, span):
+ self.ctx = ctx
+ self.key_span = self.val_span = self.span = span
+ self.def_span = self.pre_ws_span = (span[0], span[0])
+ self.post_span = (span[1], span[1])
+ self.pp = lambda v: v
+
+ def __repr__(self):
+ return self.raw_val
+
+
class Parser:
canMerge = True
+ tail = re.compile('\s+\Z')
class Context(object):
"Fixture for content and line numbers"
def __init__(self, contents):
self.contents = contents
self._lines = None
def lines(self, *positions):
@@ -244,19 +260,23 @@ class Parser:
return self.getTrailing(ctx, offset, self.reKey, self.reComment)
def getTrailing(self, ctx, offset, *expressions):
junkend = None
for exp in expressions:
m = exp.search(ctx.contents, offset)
if m:
junkend = min(junkend, m.start()) if junkend else m.start()
- if junkend is not None:
- return (Junk(ctx, (offset, junkend)), junkend)
- return (None, offset)
+ if junkend is None:
+ if self.tail.match(ctx.contents, offset):
+ white_end = len(ctx.contents)
+ return (Whitespace(ctx, (offset, white_end)), white_end)
+ else:
+ return (None, offset)
+ return (Junk(ctx, (offset, junkend)), junkend)
def createEntity(self, ctx, m):
pre_comment = str(self.last_comment) if self.last_comment else ''
self.last_comment = ''
return Entity(ctx, self.postProcessValue, pre_comment,
*[m.span(i) for i in xrange(6)])
@@ -434,16 +454,17 @@ class DefinesInstruction(Entity):
def __repr__(self):
return self.raw_val
class DefinesParser(Parser):
# can't merge, #unfilter needs to be the last item, which we don't support
canMerge = False
+ tail = re.compile(r'(?!)') # never match
def __init__(self):
self.reComment = re.compile(
'((?:[ \t]*\n)*)'
'((?:^# .*?(?:\n|\Z))+)'
'((?:[ \t]*(?:\n|\Z))*)', re.M)
self.reKey = re.compile('((?:[ \t]*\n)*)'
'(#define[ \t]+(\w+)[ \t]+(.*?)(?:\n|\Z))'
--- a/compare_locales/tests/test_defines.py
+++ b/compare_locales/tests/test_defines.py
@@ -60,11 +60,21 @@ class TestDefinesParser(ParserTestMixin,
def testToolkit(self):
self._test('''#define MOZ_LANG_TITLE English (US)
''', (
('MOZ_LANG_TITLE', 'English (US)'),))
def testToolkitEmpty(self):
self._test('', tuple())
+ def test_empty_file(self):
+ '''Test that empty files generate errors
+
+ defines.inc are interesting that way, as their
+ content is added to the generated file.
+ '''
+ self._test('\n', (('Junk', '\n'),))
+ self._test('\n\n', (('Junk', '\n\n'),))
+ self._test(' \n\n', (('Junk', ' \n\n'),))
+
if __name__ == '__main__':
unittest.main()
--- a/compare_locales/tests/test_dtd.py
+++ b/compare_locales/tests/test_dtd.py
@@ -98,16 +98,22 @@ class TestDTD(ParserTestMixin, unittest.
def test_trailing_whitespace(self):
self._test('<!ENTITY foo.label "stuff">\n \n',
(('foo.label', 'stuff'),))
def test_unicode_comment(self):
self._test('<!-- \xe5\x8f\x96 -->',
(('Comment', u'\u53d6'),))
+ def test_empty_file(self):
+ self._test('', tuple())
+ self._test('\n', (('Whitespace', '\n'),))
+ self._test('\n\n', (('Whitespace', '\n\n'),))
+ self._test(' \n\n', (('Whitespace', ' \n\n'),))
+
def test_positions(self):
self.parser.readContents('''\
<!ENTITY one "value">
<!ENTITY two "other
escaped value">
''')
one, two = list(self.parser)
self.assertEqual(one.position(), (1, 1))
--- a/compare_locales/tests/test_ini.py
+++ b/compare_locales/tests/test_ini.py
@@ -124,10 +124,16 @@ Junk
Good=other string
''', (
('Comment', mpl2),
('IniSection', 'Strings'),
('TitleText', 'Some Title'),
('Junk', 'Junk'),
('Good', 'other string')))
+ def test_empty_file(self):
+ self._test('', tuple())
+ self._test('\n', (('Whitespace', '\n'),))
+ self._test('\n\n', (('Whitespace', '\n\n'),))
+ self._test(' \n\n', (('Whitespace', ' \n\n'),))
+
if __name__ == '__main__':
unittest.main()
--- a/compare_locales/tests/test_properties.py
+++ b/compare_locales/tests/test_properties.py
@@ -121,16 +121,22 @@ foo = bar
self._test('''\
# LOCALIZATION NOTE These strings are used inside the Promise debugger
# which is available as a panel in the Debugger.
''', (('Comment', 'LOCALIZATION NOTE'),))
+ def test_empty_file(self):
+ self._test('', tuple())
+ self._test('\n', (('Whitespace', '\n'),))
+ self._test('\n\n', (('Whitespace', '\n\n'),))
+ self._test(' \n\n', (('Whitespace', ' \n\n'),))
+
def test_positions(self):
self.parser.readContents('''\
one = value
two = other \\
escaped value
''')
one, two = list(self.parser)
self.assertEqual(one.position(), (1, 1))