From 3bfa6c669d362221fe08dde546ddcf5f2168b5eb Mon Sep 17 00:00:00 2001 From: Axel Hecht Date: Tue, 27 Oct 2009 13:33:38 +0100 Subject: [PATCH] bug 505713, adding tests for JarMaker.py, better error reporting for missing files in jars, r=ted --HG-- extra : rebase_source : f3d30aab31952398fed9feac4f42491f95ca5043 --- config/JarMaker.py | 2 +- config/Makefile.in | 9 +- config/mozunit.py | 66 ++++++++++++++ config/tests/unit-JarMaker.py | 161 ++++++++++++++++++++++++++++++++++ 4 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 config/mozunit.py create mode 100644 config/tests/unit-JarMaker.py diff --git a/config/JarMaker.py b/config/JarMaker.py index 6e1b562ee0e3..10b5bf20a8e6 100644 --- a/config/JarMaker.py +++ b/config/JarMaker.py @@ -375,7 +375,7 @@ class JarMaker(object): if realsrc is None: if jf is not None: jf.close() - raise RuntimeError("file not found: " + src) + raise RuntimeError('File "%s" not found in %s' % (src, ', '.join(src_base))) if m.group('optPreprocess'): outf = outHelper.getOutput(out) inf = open(realsrc) diff --git a/config/Makefile.in b/config/Makefile.in index 02f1f4b4ede4..54d037c576ac 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -157,8 +157,13 @@ clean clobber realclean clobber_all:: cd $(MKDEPEND_DIR); $(MAKE) $@ endif -PYUNITS := unit-Expression.py unit-Preprocessor.py unit-nsinstall.py \ - unit-printprereleasesuffix.py +PYUNITS := \ + unit-Expression.py \ + unit-Preprocessor.py \ + unit-nsinstall.py \ + unit-printprereleasesuffix.py \ + unit-JarMaker.py \ + $(NULL) check:: check-python-modules check-jar-mn diff --git a/config/mozunit.py b/config/mozunit.py new file mode 100644 index 000000000000..727a7c7d6fa0 --- /dev/null +++ b/config/mozunit.py @@ -0,0 +1,66 @@ +from unittest import TextTestRunner as _TestRunner, TestResult as _TestResult +import inspect + +'''Helper to make python unit tests report the way that the Mozilla +unit test infrastructure expects tests to report. + +Usage: + +import unittest +from mozunit import MozTestRunner + +if __name__ == '__main__': + unittest.main(testRunner=MozTestRunner()) +''' + +class _MozTestResult(_TestResult): + def __init__(self, stream, descriptions): + _TestResult.__init__(self) + self.stream = stream + self.descriptions = descriptions + + def getDescription(self, test): + if self.descriptions: + return test.shortDescription() or str(test) + else: + return str(test) + + def addSuccess(self, test): + _TestResult.addSuccess(self, test) + filename = inspect.getfile(test.__class__) + testname = test._testMethodName + self.stream.writeln("TEST-PASS | %s | %s" % (filename, testname)) + + def addError(self, test, err): + _TestResult.addError(self, test, err) + self.printFail(test, err) + + def addFailure(self, test, err): + _TestResult.addFailure(self, test, err) + self.printFail(test,err) + + def printFail(self, test, err): + exctype, value, tb = err + # Skip test runner traceback levels + while tb and self._is_relevant_tb_level(tb): + tb = tb.tb_next + if not tb: + self.stream.writeln("TEST-UNEXPECTED-FAIL | NO TRACEBACK |") + _f, _ln, _t = inspect.getframeinfo(tb)[:3] + self.stream.writeln("TEST-UNEXPECTED-FAIL | %s | line %d, %s: %s" % + (_f, _ln, _t, value.message)) + + def printErrorList(self): + for test, err in self.errors: + self.stream.writeln("ERROR: %s" % self.getDescription(test)) + self.stream.writeln("%s" % err) + + +class MozTestRunner(_TestRunner): + def _makeResult(self): + return _MozTestResult(self.stream, self.descriptions) + def run(self, test): + result = self._makeResult() + test(result) + result.printErrorList() + return result diff --git a/config/tests/unit-JarMaker.py b/config/tests/unit-JarMaker.py new file mode 100644 index 000000000000..f702105992c5 --- /dev/null +++ b/config/tests/unit-JarMaker.py @@ -0,0 +1,161 @@ +import unittest + +import os, sys, os.path, time, inspect +from filecmp import dircmp +from tempfile import mkdtemp +from shutil import rmtree, copy2 +from zipfile import ZipFile +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) + +from mozunit import MozTestRunner +from JarMaker import JarMaker + + +class _TreeDiff(dircmp): + """Helper to report rich results on difference between two directories. + """ + def _fillDiff(self, dc, rv, basepath="%s"): + rv['right_only'] += map(lambda l: basepath % l, dc.right_only) + rv['left_only'] += map(lambda l: basepath % l, dc.left_only) + rv['diff_files'] += map(lambda l: basepath % l, dc.diff_files) + rv['funny'] += map(lambda l: basepath % l, dc.common_funny) + rv['funny'] += map(lambda l: basepath % l, dc.funny_files) + for subdir, _dc in dc.subdirs.iteritems(): + self._fillDiff(_dc, rv, basepath % (subdir + "/%s")) + def allResults(self, left, right): + rv = {'right_only':[], 'left_only':[], + 'diff_files':[], 'funny': []} + self._fillDiff(self, rv) + chunks = [] + if rv['right_only']: + chunks.append('%s only in %s' % (', '.join(rv['right_only']), + right)) + if rv['left_only']: + chunks.append('%s only in %s' % (', '.join(rv['left_only']), + left)) + if rv['diff_files']: + chunks.append('%s differ' % ', '.join(rv['diff_files'])) + if rv['funny']: + chunks.append("%s don't compare" % ', '.join(rv['funny'])) + return '; '.join(chunks) + +class TestJarMaker(unittest.TestCase): + """ + Unit tests for JarMaker.py + """ + debug = False # set to True to debug failing tests on disk + def setUp(self): + self.tmpdir = mkdtemp() + self.srcdir = os.path.join(self.tmpdir, 'src') + os.mkdir(self.srcdir) + self.builddir = os.path.join(self.tmpdir, 'build') + os.mkdir(self.builddir) + self.refdir = os.path.join(self.tmpdir, 'ref') + os.mkdir(self.refdir) + self.stagedir = os.path.join(self.tmpdir, 'stage') + os.mkdir(self.stagedir) + + def tearDown(self): + if self.debug: + print self.tmpdir + else: + rmtree(self.tmpdir) + + def _jar_and_compare(self, *args, **kwargs): + jm = JarMaker(outputFormat='jar') + kwargs['jardir'] = os.path.join(self.builddir, 'chrome') + if 'topsourcedir' not in kwargs: + kwargs['topsourcedir'] = self.srcdir + jm.makeJars(*args, **kwargs) + cwd = os.getcwd() + os.chdir(self.builddir) + try: + # expand build to stage + for path, dirs, files in os.walk('.'): + stagedir = os.path.join(self.stagedir, path) + if not os.path.isdir(stagedir): + os.mkdir(stagedir) + for file in files: + if file.endswith('.jar'): + # expand jar + stagepath = os.path.join(stagedir, file) + os.mkdir(stagepath) + zf = ZipFile(os.path.join(path, file)) + # extractall is only in 2.6, do this manually :-( + for entry_name in zf.namelist(): + segs = entry_name.split('/') + fname = segs.pop() + dname = os.path.join(stagepath, *segs) + if not os.path.isdir(dname): + os.makedirs(dname) + if not fname: + # directory, we're done + continue + _c = zf.read(entry_name) + open(os.path.join(dname, fname), 'wb').write(_c) + zf.close() + else: + copy2(os.path.join(path, file), stagedir) + # compare both dirs + os.chdir('..') + td = _TreeDiff('ref', 'stage') + return td.allResults('reference', 'build') + finally: + os.chdir(cwd) + + def test_a_simple_jar(self): + '''Test a simple jar.mn''' + # create src content + jarf = open(os.path.join(self.srcdir, 'jar.mn'), 'w') + jarf.write('''test.jar: + dir/foo (bar) +''') + jarf.close() + open(os.path.join(self.srcdir,'bar'),'w').write('content\n') + # create reference + refpath = os.path.join(self.refdir, 'chrome', 'test.jar', 'dir') + os.makedirs(refpath) + open(os.path.join(refpath, 'foo'), 'w').write('content\n') + # call JarMaker + rv = self._jar_and_compare((os.path.join(self.srcdir,'jar.mn'),), + tuple(), + sourcedirs = [self.srcdir]) + self.assertTrue(not rv, rv) + + def test_k_multi_relative_jar(self): + '''Test the API for multiple l10n jars, with different relative paths''' + # create app src content + def _mangle(relpath): + 'method we use to map relpath to srcpaths' + return os.path.join(self.srcdir, 'other-' + relpath) + jars = [] + for relpath in ('foo', 'bar'): + ldir = os.path.join(self.srcdir, relpath, 'locales') + os.makedirs(ldir) + jp = os.path.join(ldir, 'jar.mn') + jars.append(jp) + open(jp, 'w').write('''ab-CD.jar: +% locale app ab-CD %app + app/''' + relpath + ' (%' + relpath + ''') +''') + ldir = _mangle(relpath) + os.mkdir(ldir) + open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n") + # create reference + chrome_ref = os.path.join(self.refdir, 'chrome') + os.mkdir(chrome_ref) + mf = open(os.path.join(chrome_ref, 'ab-CD.manifest'), 'wb') + mf.write('locale app ab-CD jar:ab-CD.jar!/app\n') + mf.close() + ldir = os.path.join(chrome_ref, 'ab-CD.jar', 'app') + os.makedirs(ldir) + for relpath in ('foo', 'bar'): + open(os.path.join(ldir, relpath), 'w').write(relpath+" content\n") + # call JarMaker + difference = self._jar_and_compare(jars, + (_mangle,), + sourcedirs = []) + self.assertTrue(not difference, difference) + +if __name__ == '__main__': + unittest.main(testRunner=MozTestRunner())