bug 1361037, part 4: move android check detection from checks to project config, r=flod, stas
MozReview-Commit-ID: JqnRAZz2CE6
--- a/compare_locales/checks.py
+++ b/compare_locales/checks.py
@@ -17,16 +17,19 @@ class Checker(object):
'''Abstract class to implement checks per file type.
'''
pattern = None
@classmethod
def use(cls, file):
return cls.pattern.match(file.file)
+ def __init__(self, extra_tests):
+ self.extra_tests = extra_tests
+
def check(self, refEnt, l10nEnt):
'''Given the reference and localized Entities, performs checks.
This is a generator yielding tuples of
- "warning" or "error", depending on what should be reported,
- tuple of line, column info for the error within the string
- description string to be shown in the report
'''
@@ -186,17 +189,21 @@ class DTDChecker(Checker):
pattern = re.compile('.*\.dtd$')
eref = re.compile('&(%s);' % DTDParser.Name)
tmpl = '''<!DOCTYPE elem [%s]>
<elem>%s</elem>
'''
xmllist = set(('amp', 'lt', 'gt', 'apos', 'quot'))
- def __init__(self, reference):
+ def __init__(self, extra_tests, reference):
+ super(DTDChecker, self).__init__(extra_tests)
+ self.processContent = False
+ if self.extra_tests is not None and 'android-dtd' in self.extra_tests:
+ self.processContent = True
self.reference = reference
self.__known_entities = None
def known_entities(self, refValue):
if self.__known_entities is None and self.reference is not None:
self.__known_entities = set()
for ent in self.reference:
self.__known_entities.update(self.entities_for_value(ent.val))
@@ -223,18 +230,16 @@ class DTDChecker(Checker):
num = re.compile('^%s$' % numPattern)
lengthPattern = '%s(em|px|ch|cm|in)' % numPattern
length = re.compile('^%s$' % lengthPattern)
spec = re.compile(r'((?:min\-)?(?:width|height))\s*:\s*%s' %
lengthPattern)
style = re.compile(r'^%(spec)s\s*(;\s*%(spec)s\s*)*;?$' %
{'spec': spec.pattern})
- processContent = None
-
def check(self, refEnt, l10nEnt):
"""Try to parse the refvalue inside a dummy element, and keep
track of entities that we need to define to make that work.
Return a checker that offers just those entities.
"""
refValue, l10nValue = refEnt.val, l10nEnt.val
# find entities the refValue references,
@@ -258,17 +263,17 @@ class DTDChecker(Checker):
(0, 0),
"can't parse en-US value", 'xmlparse')
# find entities the l10nValue references,
# reusing markup from DTDParser.
l10nlist = self.entities_for_value(l10nValue)
missing = sorted(l10nlist - reflist)
_entities = entities + ''.join('<!ENTITY %s "">' % s for s in missing)
- if self.processContent is not None:
+ if self.processContent:
self.texthandler.textcontent = ''
parser.setContentHandler(self.texthandler)
try:
parser.parse(StringIO(self.tmpl % (_entities,
l10nValue.encode('utf-8'))))
# also catch stray %
# if this fails, we need to substract the entity definition
parser.setContentHandler(self.defaulthandler)
@@ -342,27 +347,20 @@ class DTDChecker(Checker):
if u != ru:
msgs.append("units for %s don't match "
"(%s != %s)" % (s, u, ru))
for s in refMap.iterkeys():
msgs.insert(0, '%s only in reference' % s)
if msgs:
yield ('warning', 0, ', '.join(msgs), 'css')
- if self.processContent is not None:
- for t in self.processContent(self.texthandler.textcontent):
+ if self.extra_tests is not None and 'android-dtd' in self.extra_tests:
+ for t in self.processAndroidContent(self.texthandler.textcontent):
yield t
-
-class PrincessAndroid(DTDChecker):
- """Checker for the string values that Android puts into an XML container.
-
- http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling # noqa
- has more info. Check for unescaped apostrophes and bad unicode escapes.
- """
quoted = re.compile("(?P<q>[\"']).*(?P=q)$")
def unicode_escape(self, str):
"""Helper method to try to decode all unicode escapes in a string.
This code uses the standard python decode for unicode-escape, but
that's somewhat tricky, as its input needs to be ascii. To get to
ascii, the unicode string gets converted to ascii with
@@ -380,25 +378,21 @@ class PrincessAndroid(DTDChecker):
except UnicodeDecodeError, e:
args = list(e.args)
badstring = args[1][args[2]:args[3]]
i = len(args[1][:args[2]].decode('unicode-escape'))
args[2] = i
args[3] = i + len(badstring)
raise UnicodeDecodeError(*args)
- @classmethod
- def use(cls, file):
- """Use this Checker only for DTD files in embedding/android."""
- return (file.module in ("embedding/android",
- "mobile/android/base") and
- cls.pattern.match(file.file))
+ def processAndroidContent(self, val):
+ """Check for the string values that Android puts into an XML container.
- def processContent(self, val):
- """Actual check code.
+ http://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling # noqa
+
Check for unicode escapes and unescaped quotes and apostrophes,
if string's not quoted.
"""
# first, try to decode unicode escapes
try:
self.unicode_escape(val)
except UnicodeDecodeError, e:
yield ('error', e.args[2], e.args[4], 'android')
@@ -423,16 +417,14 @@ class PrincessAndroid(DTDChecker):
u"or \\u0022, or put string in apostrophes."
else:
msg = u"Apostrophes in Android DTDs need escaping with "\
u"\\' or \\u0027, or use \u2019, or put string in "\
u"quotes."
yield ('error', m.end(0)+offset, msg, 'android')
-def getChecker(file, reference=None):
+def getChecker(file, reference=None, extra_tests=None):
if PropertiesChecker.use(file):
- return PropertiesChecker()
- if PrincessAndroid.use(file):
- return PrincessAndroid(reference)
+ return PropertiesChecker(extra_tests)
if DTDChecker.use(file):
- return DTDChecker(reference)
+ return DTDChecker(extra_tests, reference)
return None
--- a/compare_locales/compare.py
+++ b/compare_locales/compare.py
@@ -431,17 +431,17 @@ class ContentComparer:
l10n_list = l10n_map.keys()
l10n_list.sort()
ar = AddRemove()
ar.set_left(ref_list)
ar.set_right(l10n_list)
report = missing = obsolete = changed = unchanged = keys = 0
missings = []
skips = []
- checker = getChecker(l10n, reference=ref[0])
+ checker = getChecker(l10n, reference=ref[0], extra_tests=extra_tests)
for action, item_or_pair in ar:
if action == 'delete':
# missing entity
_rv = self.notify('missingEntity', l10n, item_or_pair)
if _rv == "ignore":
continue
if _rv == "error":
# only add to missing entities for l10n-merge on error,
--- a/compare_locales/tests/test_checks.py
+++ b/compare_locales/tests/test_checks.py
@@ -252,17 +252,17 @@ class TestAndroid(unittest.TestCase):
(14, len(v) + 14), ())
def test_android_dtd(self):
"""Testing the actual android checks. The logic is involved,
so this is a lot of nitty gritty detail tests.
"""
f = File("embedding/android/strings.dtd", "strings.dtd",
"embedding/android")
- checker = getChecker(f)
+ checker = getChecker(f, extra_tests=['android-dtd'])
# good string
ref = self.getDTDEntity("plain string")
l10n = self.getDTDEntity("plain localized string")
self.assertEqual(tuple(checker.check(ref, l10n)),
())
# dtd warning
l10n = self.getDTDEntity("plain localized string &ref;")
self.assertEqual(tuple(checker.check(ref, l10n)),
@@ -328,17 +328,17 @@ class TestAndroid(unittest.TestCase):
l10n = self.getDTDEntity(u"\u9690"*14+"\u006"+" "+"\u0064")
self.assertEqual(tuple(checker.check(ref, l10n)),
(('error', 14, 'truncated \\uXXXX escape',
'android'),))
def test_android_prop(self):
f = File("embedding/android/strings.properties", "strings.properties",
"embedding/android")
- checker = getChecker(f)
+ checker = getChecker(f, extra_tests=['android-dtd'])
# good plain string
ref = self.getEntity("plain string")
l10n = self.getEntity("plain localized string")
self.assertEqual(tuple(checker.check(ref, l10n)),
())
# no dtd warning
ref = self.getEntity("plain string")
l10n = self.getEntity("plain localized string &ref;")