mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
426 lines
15 KiB
Python
Executable File
426 lines
15 KiB
Python
Executable File
# ***** BEGIN LICENSE BLOCK *****
|
|
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
#
|
|
# The contents of this file are subject to the Mozilla Public License Version
|
|
# 1.1 (the "License"); you may not use this file except in compliance with
|
|
# the License. You may obtain a copy of the License at
|
|
# http://www.mozilla.org/MPL/
|
|
#
|
|
# Software distributed under the License is distributed on an "AS IS" basis,
|
|
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
# for the specific language governing rights and limitations under the
|
|
# License.
|
|
#
|
|
# The Original Code is l10n test automation.
|
|
#
|
|
# The Initial Developer of the Original Code is
|
|
# Mozilla Foundation
|
|
# Portions created by the Initial Developer are Copyright (C) 2006
|
|
# the Initial Developer. All Rights Reserved.
|
|
#
|
|
# Contributor(s):
|
|
# Axel Hecht <l10n@mozilla.com>
|
|
#
|
|
# Alternatively, the contents of this file may be used under the terms of
|
|
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
# in which case the provisions of the GPL or the LGPL are applicable instead
|
|
# of those above. If you wish to allow use of your version of this file only
|
|
# under the terms of either the GPL or the LGPL, and not to allow others to
|
|
# use your version of this file under the terms of the MPL, indicate your
|
|
# decision by deleting the provisions above and replace them with the notice
|
|
# and other provisions required by the GPL or the LGPL. If you do not delete
|
|
# the provisions above, a recipient may use your version of this file under
|
|
# the terms of any one of the MPL, the GPL or the LGPL.
|
|
#
|
|
# ***** END LICENSE BLOCK *****
|
|
|
|
import logging
|
|
import Paths
|
|
import Parser
|
|
|
|
class Base:
|
|
'''Base class for all tests'''
|
|
def __init__(self):
|
|
if not hasattr(self, 'leafName'):
|
|
self.leafName = 'TODO'
|
|
logging.warning(' ' + self + ' does not have leafName set, writing to TODO')
|
|
def run(self):
|
|
'''Run this test for all locales, returns a dictionary with results'''
|
|
pass
|
|
def serialize(self, result, saveHandler):
|
|
'''Serialize the previously generated result, writes the dictionary
|
|
by default'''
|
|
return saveHandler(result, self.leafName)
|
|
pass
|
|
def failureTest(self, myResult, failureResult):
|
|
pass
|
|
|
|
import CompareLocales
|
|
class CompareTest(Base):
|
|
'''Test class to compare locales'''
|
|
def __init__(self, apps = ['browser', 'mail']):
|
|
'''Initializes the test object'''
|
|
self.apps = apps
|
|
pass
|
|
def run(self):
|
|
'''Runs CompareLocales.compare()'''
|
|
return CompareLocales.compare(apps=self.apps)
|
|
def serialize(self, result, saveHandler):
|
|
'''Serialize the CompareLocales result by locale into
|
|
cmp-details-ab-CD
|
|
and a compacted version into
|
|
cmp-data
|
|
|
|
'''
|
|
class Separator:
|
|
def __init__(self):
|
|
self.leafBase = 'cmp-details-'
|
|
self.components = Paths.Components(['browser','mail'])
|
|
def getDetails(self, res, locale):
|
|
dic = {}
|
|
res[locale]['tested'].sort()
|
|
self.collectList('missing', res[locale], dic)
|
|
self.collectList('obsolete', res[locale], dic)
|
|
saveHandler(dic, self.leafBase + locale + '.json')
|
|
def collectList(self, name, res, dic):
|
|
dic[name] = {}
|
|
if not res.has_key(name):
|
|
res[name] = []
|
|
counts = dict([(mod,0) for mod in res['tested']])
|
|
counts['total'] = len(res[name])
|
|
for mod, path, key in res[name]:
|
|
counts[self.components[mod]] +=1
|
|
if not dic[name].has_key(mod):
|
|
dic[name][mod] = {path:[key]}
|
|
continue
|
|
if not dic[name][mod].has_key(path):
|
|
dic[name][mod][path] = [key]
|
|
else:
|
|
dic[name][mod][path].append(key)
|
|
res[name] = counts
|
|
name += 'Files'
|
|
dic[name] = {}
|
|
if not res.has_key(name):
|
|
res[name] = []
|
|
counts = dict([(mod,0) for mod in res['tested']])
|
|
counts['total'] = len(res[name])
|
|
for mod, path in res[name]:
|
|
counts[self.components[mod]] +=1
|
|
if not dic[name].has_key(mod):
|
|
dic[name][mod] = [path]
|
|
else:
|
|
dic[name][mod].append(path)
|
|
res[name] = counts
|
|
|
|
s = Separator()
|
|
for loc, lResult in result.iteritems():
|
|
s.getDetails(result, loc)
|
|
|
|
saveHandler(result, 'cmp-data.json')
|
|
|
|
def failureTest(self, myResult, failureResult):
|
|
'''signal pass/warn/failure for each locale'''
|
|
def sumdata(data, part):
|
|
res = 0
|
|
for mod in [u'browser', u'toolkit']:
|
|
res += data[part][mod] + data[part + u'Files'][mod]
|
|
return res
|
|
def getState(data):
|
|
ret = 0
|
|
if sumdata(data, u'obsolete') > 0:
|
|
ret |= 1
|
|
if sumdata(data, u'missing') > 0:
|
|
ret |= 2
|
|
return ret
|
|
for loc, val in myResult.iteritems():
|
|
if not failureResult.has_key(loc):
|
|
failureResult[loc] = getState(val)
|
|
else:
|
|
failureResult |= getState(val)
|
|
|
|
from xml import sax
|
|
from types import DictType, FunctionType
|
|
import md5
|
|
from codecs import utf_8_encode
|
|
import re
|
|
import os
|
|
|
|
class SearchTest(Base):
|
|
"""Test class to collect information from search plugins and to
|
|
verify that they're doing something good.
|
|
|
|
"""
|
|
def __init__(self):
|
|
'''Set up the test class with a good leaf name'''
|
|
self.leafName = 'search-results.json'
|
|
pass
|
|
def run(self):
|
|
'''Collect all data from the MozSearch plugins in both the /cvsroot
|
|
repository for en-US and the /l10n repository for locales
|
|
|
|
'''
|
|
class DummyHandler(sax.handler.ContentHandler):
|
|
def startDocument(self):
|
|
self.md5 = md5.new()
|
|
self.indent = ''
|
|
self.engine = {'urls':[]}
|
|
self.lNames = []
|
|
self.textField = None
|
|
self.content = ''
|
|
return
|
|
def endDocument(self):
|
|
self.engine['md5'] = self.md5.hexdigest()
|
|
return
|
|
def startElementNS(self, (ns, local), qname, attrs):
|
|
if self.textField:
|
|
logging.warning('Found Element, but expected CDATA.')
|
|
self.indent += ' '
|
|
if ns != u'http://www.mozilla.org/2006/browser/search/':
|
|
raise UserWarning, ('bad namespace: ' + ns)
|
|
self.lNames.append(local)
|
|
handler = self.getOpenHandler()
|
|
if handler:
|
|
handler(self, attrs)
|
|
self.update(ns+local)
|
|
for qna in attrs.getQNames():
|
|
self.update(qna[0] + qna[1] + attrs.getValueByQName(qna))
|
|
return
|
|
def endElementNS(self, (ns, local), qname):
|
|
if self.textField:
|
|
self.engine[self.textField] = self.content
|
|
self.textField = None
|
|
self.content = ''
|
|
self.lNames.pop()
|
|
self.indent = self.indent[0:-2]
|
|
def characters(self, content):
|
|
self.update(content)
|
|
if not self.textField:
|
|
return
|
|
self.content += content
|
|
def update(self, content):
|
|
self.md5.update(utf_8_encode(content)[0])
|
|
def openURL(self, attrs):
|
|
entry = {'params':{},
|
|
'type': attrs.getValueByQName(u'type'),
|
|
'template': attrs.getValueByQName(u'template')}
|
|
self.engine['urls'].append(entry)
|
|
def handleParam(self, attrs):
|
|
try:
|
|
self.engine['urls'][-1]['params'][attrs.getValueByQName(u'name')] = attrs.getValueByQName(u'value')
|
|
except KeyError:
|
|
raise UserWarning, 'bad param'
|
|
return
|
|
def handleMozParam(self, attrs):
|
|
mp = None
|
|
try:
|
|
mp = { 'name': attrs.getValueByQName(u'name'),
|
|
'condition': attrs.getValueByQName(u'condition'),
|
|
'trueValue': attrs.getValueByQName(u'trueValue'),
|
|
'falseValue': attrs.getValueByQName(u'falseValue')}
|
|
except KeyError:
|
|
try:
|
|
mp = {'name': attrs.getValueByQName(u'name'),
|
|
'condition': attrs.getValueByQName(u'condition'),
|
|
'pref': attrs.getValueByQName(u'pref')}
|
|
except KeyError:
|
|
raise UserWarning, 'bad mozParam'
|
|
if self.engine['urls'][-1].has_key('MozParams'):
|
|
self.engine['urls'][-1]['MozParams'].append(mp)
|
|
else:
|
|
self.engine['urls'][-1]['MozParams'] = [mp]
|
|
return
|
|
def handleShortName(self, attrs):
|
|
self.textField = 'ShortName'
|
|
return
|
|
def handleImage(self, attrs):
|
|
self.textField = 'Image'
|
|
return
|
|
def getOpenHandler(self):
|
|
return self.getHandler(DummyHandler.openHandlers)
|
|
def getHandler(self, handlers):
|
|
for local in self.lNames:
|
|
if type(handlers) != DictType or not handlers.has_key(local):
|
|
return
|
|
handlers = handlers[local]
|
|
if handlers.has_key('_handler'):
|
|
return handlers['_handler']
|
|
return
|
|
openHandlers = {'SearchPlugin':
|
|
{'ShortName': {'_handler': handleShortName},
|
|
'Image': {'_handler': handleImage},
|
|
'Url':{'_handler': openURL,
|
|
'Param': {'_handler':handleParam},
|
|
'MozParam': {'_handler':handleMozParam}
|
|
}
|
|
}
|
|
}
|
|
|
|
handler = DummyHandler()
|
|
parser = sax.make_parser()
|
|
parser.setContentHandler(handler)
|
|
parser.setFeature(sax.handler.feature_namespaces, True)
|
|
|
|
locales = [loc.strip() for loc in open('mozilla/browser/locales/all-locales')]
|
|
locales.insert(0, 'en-US')
|
|
sets = {}
|
|
details = {}
|
|
|
|
for loc in locales:
|
|
l = logging.getLogger('locales.' + loc)
|
|
try:
|
|
lst = open(Paths.get_path('browser',loc,'searchplugins/list.txt'),'r')
|
|
except IOError:
|
|
l.error("Locale " + loc + " doesn't have search plugins")
|
|
details[Paths.get_path('browser',loc,'searchplugins/list.txt')] = {
|
|
'error': 'not found'
|
|
}
|
|
continue
|
|
sets[loc] = {'list': []}
|
|
regprop = Paths.get_path('browser', loc, 'chrome/browser-region/region.properties')
|
|
p = Parser.getParser(regprop)
|
|
p.read(regprop)
|
|
orders = {}
|
|
for key, val in p:
|
|
m = re.match('browser.search.order.([1-9])', key)
|
|
if m:
|
|
orders[val.strip()] = int(m.group(1))
|
|
elif key == 'browser.search.defaultenginename':
|
|
sets[loc]['default'] = val.strip()
|
|
sets[loc]['orders'] = orders
|
|
for fn in lst:
|
|
name = fn.strip()
|
|
if len(name) == 0:
|
|
continue
|
|
leaf = 'searchplugins/' + name + '.xml'
|
|
_path = Paths.get_path('browser','en-US', leaf)
|
|
if not os.access(_path, os.R_OK):
|
|
_path = Paths.get_path('browser', loc, leaf)
|
|
l.debug('testing ' + _path)
|
|
sets[loc]['list'].append(_path)
|
|
try:
|
|
parser.parse(_path)
|
|
except IOError:
|
|
l.error("can't open " + _path)
|
|
details[_path] = {'_name': name, 'error': 'not found'}
|
|
continue
|
|
except UserWarning, ex:
|
|
l.error("error in searchplugin " + _path)
|
|
details[_path] = {'_name': name, 'error': ex.args[0]}
|
|
continue
|
|
except sax._exceptions.SAXParseException, ex:
|
|
l.error("error in searchplugin " + _path)
|
|
details[_path] = {'_name': name, 'error': ex.args[0]}
|
|
continue
|
|
details[_path] = handler.engine
|
|
details[_path]['_name'] = name
|
|
|
|
engines = {'locales': sets,
|
|
'details': details}
|
|
return engines
|
|
def failureTest(self, myResult, failureResult):
|
|
'''signal pass/warn/failure for each locale
|
|
Just signaling errors in individual plugins for now.
|
|
|
|
'''
|
|
for loc, val in myResult['locales'].iteritems():
|
|
l = logging.getLogger('locales.' + loc)
|
|
# Verify that there are no errors in the engine parsing,
|
|
# and that there default engine is the first one.
|
|
if (not val['orders'].has_key(val['default'])) or val['orders'][val['default']] != 1:
|
|
l.error('Default engine is not first in order in locale ' + loc)
|
|
if not failureResult.has_key(loc):
|
|
failureResult[loc] = 2
|
|
else:
|
|
failureResult[loc] |= 2
|
|
for p in val['list']:
|
|
# no logging, that is already reported above
|
|
if myResult['details'][p].has_key('error'):
|
|
if not failureResult.has_key(loc):
|
|
failureResult[loc] = 2
|
|
else:
|
|
failureResult[loc] |= 2
|
|
|
|
class RSSReaderTest(Base):
|
|
"""Test class to collect information about RSS readers and to
|
|
verify that they might be working.
|
|
|
|
"""
|
|
def __init__(self):
|
|
'''Set up the test class with a good leaf name'''
|
|
self.leafName = 'feed-reader-results.json'
|
|
pass
|
|
def run(self):
|
|
'''Collect the data from browsers region.properties for all locales
|
|
|
|
'''
|
|
locales = [loc.strip() for loc in open('mozilla/browser/locales/all-locales')]
|
|
uri = re.compile('browser\\.contentHandlers\\.types\\.([0-5])\\.uri')
|
|
title = re.compile('browser\\.contentHandlers\\.types\\.([0-5])\\.title')
|
|
res = {}
|
|
for loc in locales:
|
|
l = logging.getLogger('locales.' + loc)
|
|
regprop = Paths.get_path('browser', loc, 'chrome/browser-region/region.properties')
|
|
p = Parser.getParser(regprop)
|
|
p.read(regprop)
|
|
uris = {}
|
|
titles = {}
|
|
for key, val in p:
|
|
m = uri.match(key)
|
|
if m:
|
|
o = int(m.group(1))
|
|
if uris.has_key(o):
|
|
l.error('Double definition of RSS reader ' + o)
|
|
uris[o] = val.strip()
|
|
else:
|
|
m = title.match(key)
|
|
if m:
|
|
o = int(m.group(1))
|
|
if titles.has_key(o):
|
|
l.error('Double definition of RSS reader ' + o)
|
|
titles[o] = val.strip()
|
|
ind = sorted(uris.keys())
|
|
if ind != range(len(ind)) or ind != sorted(titles.keys()):
|
|
l.error('RSS Readers are badly set up')
|
|
res[loc] = [(titles[o], uris[o]) for o in ind]
|
|
return res
|
|
|
|
class BookmarksTest(Base):
|
|
"""Test class to collect information about bookmarks and check their
|
|
structure.
|
|
|
|
"""
|
|
def __init__(self):
|
|
'''Set up the test class with a good leaf name'''
|
|
self.leafName = 'bookmarks-results.json'
|
|
pass
|
|
def run(self):
|
|
'''Collect the data from bookmarks.html for all locales
|
|
|
|
'''
|
|
locales = [loc.strip() for loc in open('mozilla/browser/locales/all-locales')]
|
|
bm = Parser.BookmarksParser()
|
|
res = {}
|
|
for loc in locales:
|
|
try:
|
|
bm.read('l10n/%s/browser/profile/bookmarks.html'%loc)
|
|
res[loc] = bm.getDetails()
|
|
except Exception, e:
|
|
logging.getLogger('locale.%s'%loc).error('Bookmarks are busted, %s'%e)
|
|
return res
|
|
def failureTest(self, myResult, failureResult):
|
|
'''signal pass/warn/failure for each locale
|
|
Just signaling errors for now.
|
|
|
|
'''
|
|
locales = [loc.strip() for loc in open('mozilla/browser/locales/all-locales')]
|
|
bm = Parser.BookmarksParser()
|
|
bm.read('mozilla/browser/locales/en-US/profile/bookmarks.html')
|
|
enUSDetails = bm.getDetails()
|
|
for loc in locales:
|
|
if not myResult.has_key(loc):
|
|
if not failureResult.has_key(loc):
|
|
failureResult[loc] = 2
|
|
else:
|
|
failureResult[loc] |= 2
|