python/mozbuild/mozpack/test/test_packager.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/python/mozbuild/mozpack/test/test_packager.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,328 @@
     1.4 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.7 +
     1.8 +import unittest
     1.9 +import mozunit
    1.10 +import os
    1.11 +from mozpack.packager import (
    1.12 +    preprocess_manifest,
    1.13 +    CallDeque,
    1.14 +    Component,
    1.15 +    SimplePackager,
    1.16 +    SimpleManifestSink,
    1.17 +)
    1.18 +from mozpack.files import GeneratedFile
    1.19 +from mozpack.chrome.manifest import (
    1.20 +    ManifestResource,
    1.21 +    ManifestContent,
    1.22 +)
    1.23 +from mozunit import MockedOpen
    1.24 +from mozbuild.preprocessor import Preprocessor
    1.25 +from mozpack.errors import (
    1.26 +    errors,
    1.27 +    ErrorMessage,
    1.28 +)
    1.29 +import mozpack.path
    1.30 +
    1.31 +MANIFEST = '''
    1.32 +bar/*
    1.33 +[foo]
    1.34 +foo/*
    1.35 +-foo/bar
    1.36 +chrome.manifest
    1.37 +[zot destdir="destdir"]
    1.38 +foo/zot
    1.39 +; comment
    1.40 +#ifdef baz
    1.41 +[baz]
    1.42 +baz@SUFFIX@
    1.43 +#endif
    1.44 +'''
    1.45 +
    1.46 +
    1.47 +class TestPreprocessManifest(unittest.TestCase):
    1.48 +    MANIFEST_PATH = os.path.join(os.path.abspath(os.curdir), 'manifest')
    1.49 +
    1.50 +    EXPECTED_LOG = [
    1.51 +        ((MANIFEST_PATH, 2), 'add', '', 'bar/*'),
    1.52 +        ((MANIFEST_PATH, 4), 'add', 'foo', 'foo/*'),
    1.53 +        ((MANIFEST_PATH, 5), 'remove', 'foo', 'foo/bar'),
    1.54 +        ((MANIFEST_PATH, 6), 'add', 'foo', 'chrome.manifest'),
    1.55 +        ((MANIFEST_PATH, 8), 'add', 'zot destdir="destdir"', 'foo/zot'),
    1.56 +    ]
    1.57 +
    1.58 +    def setUp(self):
    1.59 +        class MockSink(object):
    1.60 +            def __init__(self):
    1.61 +                self.log = []
    1.62 +
    1.63 +            def add(self, component, path):
    1.64 +                self._log(errors.get_context(), 'add', repr(component), path)
    1.65 +
    1.66 +            def remove(self, component, path):
    1.67 +                self._log(errors.get_context(), 'remove', repr(component), path)
    1.68 +
    1.69 +            def _log(self, *args):
    1.70 +                self.log.append(args)
    1.71 +
    1.72 +        self.sink = MockSink()
    1.73 +
    1.74 +    def test_preprocess_manifest(self):
    1.75 +        with MockedOpen({'manifest': MANIFEST}):
    1.76 +            preprocess_manifest(self.sink, 'manifest')
    1.77 +        self.assertEqual(self.sink.log, self.EXPECTED_LOG)
    1.78 +
    1.79 +    def test_preprocess_manifest_missing_define(self):
    1.80 +        with MockedOpen({'manifest': MANIFEST}):
    1.81 +            self.assertRaises(
    1.82 +                Preprocessor.Error,
    1.83 +                preprocess_manifest,
    1.84 +                self.sink,
    1.85 +                'manifest',
    1.86 +                {'baz': 1}
    1.87 +            )
    1.88 +
    1.89 +    def test_preprocess_manifest_defines(self):
    1.90 +        with MockedOpen({'manifest': MANIFEST}):
    1.91 +            preprocess_manifest(self.sink, 'manifest',
    1.92 +                                {'baz': 1, 'SUFFIX': '.exe'})
    1.93 +        self.assertEqual(self.sink.log, self.EXPECTED_LOG +
    1.94 +                         [((self.MANIFEST_PATH, 12), 'add', 'baz', 'baz.exe')])
    1.95 +
    1.96 +
    1.97 +class MockFinder(object):
    1.98 +    def __init__(self, files):
    1.99 +        self.files = files
   1.100 +        self.log = []
   1.101 +
   1.102 +    def find(self, path):
   1.103 +        self.log.append(path)
   1.104 +        for f in sorted(self.files):
   1.105 +            if mozpack.path.match(f, path):
   1.106 +                yield f, self.files[f]
   1.107 +
   1.108 +    def __iter__(self):
   1.109 +        return self.find('')
   1.110 +
   1.111 +
   1.112 +class MockFormatter(object):
   1.113 +    def __init__(self):
   1.114 +        self.log = []
   1.115 +
   1.116 +    def add_base(self, *args):
   1.117 +        self._log(errors.get_context(), 'add_base', *args)
   1.118 +
   1.119 +    def add_manifest(self, *args):
   1.120 +        self._log(errors.get_context(), 'add_manifest', *args)
   1.121 +
   1.122 +    def add_interfaces(self, *args):
   1.123 +        self._log(errors.get_context(), 'add_interfaces', *args)
   1.124 +
   1.125 +    def add(self, *args):
   1.126 +        self._log(errors.get_context(), 'add', *args)
   1.127 +
   1.128 +    def _log(self, *args):
   1.129 +        self.log.append(args)
   1.130 +
   1.131 +
   1.132 +class TestSimplePackager(unittest.TestCase):
   1.133 +    def test_simple_packager(self):
   1.134 +        class GeneratedFileWithPath(GeneratedFile):
   1.135 +            def __init__(self, path, content):
   1.136 +                GeneratedFile.__init__(self, content)
   1.137 +                self.path = path
   1.138 +
   1.139 +        formatter = MockFormatter()
   1.140 +        packager = SimplePackager(formatter)
   1.141 +        curdir = os.path.abspath(os.curdir)
   1.142 +        file = GeneratedFileWithPath(os.path.join(curdir, 'foo',
   1.143 +                                                  'bar.manifest'),
   1.144 +                                     'resource bar bar/\ncontent bar bar/')
   1.145 +        with errors.context('manifest', 1):
   1.146 +            packager.add('foo/bar.manifest', file)
   1.147 +
   1.148 +        file = GeneratedFileWithPath(os.path.join(curdir, 'foo',
   1.149 +                                                  'baz.manifest'),
   1.150 +                                     'resource baz baz/')
   1.151 +        with errors.context('manifest', 2):
   1.152 +            packager.add('bar/baz.manifest', file)
   1.153 +
   1.154 +        with errors.context('manifest', 3):
   1.155 +            packager.add('qux/qux.manifest',
   1.156 +                         GeneratedFile('resource qux qux/'))
   1.157 +        bar_xpt = GeneratedFile('bar.xpt')
   1.158 +        qux_xpt = GeneratedFile('qux.xpt')
   1.159 +        foo_html = GeneratedFile('foo_html')
   1.160 +        bar_html = GeneratedFile('bar_html')
   1.161 +        with errors.context('manifest', 4):
   1.162 +            packager.add('foo/bar.xpt', bar_xpt)
   1.163 +        with errors.context('manifest', 5):
   1.164 +            packager.add('foo/bar/foo.html', foo_html)
   1.165 +            packager.add('foo/bar/bar.html', bar_html)
   1.166 +
   1.167 +        file = GeneratedFileWithPath(os.path.join(curdir, 'foo.manifest'),
   1.168 +                                     ''.join([
   1.169 +                                         'manifest foo/bar.manifest\n',
   1.170 +                                         'manifest bar/baz.manifest\n',
   1.171 +                                     ]))
   1.172 +        with errors.context('manifest', 6):
   1.173 +            packager.add('foo.manifest', file)
   1.174 +        with errors.context('manifest', 7):
   1.175 +            packager.add('foo/qux.xpt', qux_xpt)
   1.176 +
   1.177 +        self.assertEqual(formatter.log, [])
   1.178 +
   1.179 +        with errors.context('dummy', 1):
   1.180 +            packager.close()
   1.181 +        self.maxDiff = None
   1.182 +        # The formatter is expected to reorder the manifest entries so that
   1.183 +        # chrome entries appear before the others.
   1.184 +        self.assertEqual(formatter.log, [
   1.185 +            (('dummy', 1), 'add_base', 'qux'),
   1.186 +            ((os.path.join(curdir, 'foo', 'bar.manifest'), 2),
   1.187 +             'add_manifest', ManifestContent('foo', 'bar', 'bar/')),
   1.188 +            ((os.path.join(curdir, 'foo', 'bar.manifest'), 1),
   1.189 +             'add_manifest', ManifestResource('foo', 'bar', 'bar/')),
   1.190 +            (('bar/baz.manifest', 1),
   1.191 +             'add_manifest', ManifestResource('bar', 'baz', 'baz/')),
   1.192 +            (('qux/qux.manifest', 1),
   1.193 +             'add_manifest', ManifestResource('qux', 'qux', 'qux/')),
   1.194 +            (('manifest', 4), 'add_interfaces', 'foo/bar.xpt', bar_xpt),
   1.195 +            (('manifest', 7), 'add_interfaces', 'foo/qux.xpt', qux_xpt),
   1.196 +            (('manifest', 5), 'add', 'foo/bar/foo.html', foo_html),
   1.197 +            (('manifest', 5), 'add', 'foo/bar/bar.html', bar_html),
   1.198 +        ])
   1.199 +
   1.200 +        self.assertEqual(packager.get_bases(), set(['', 'qux']))
   1.201 +
   1.202 +
   1.203 +class TestSimpleManifestSink(unittest.TestCase):
   1.204 +    def test_simple_manifest_parser(self):
   1.205 +        formatter = MockFormatter()
   1.206 +        foobar = GeneratedFile('foobar')
   1.207 +        foobaz = GeneratedFile('foobaz')
   1.208 +        fooqux = GeneratedFile('fooqux')
   1.209 +        foozot = GeneratedFile('foozot')
   1.210 +        finder = MockFinder({
   1.211 +            'bin/foo/bar': foobar,
   1.212 +            'bin/foo/baz': foobaz,
   1.213 +            'bin/foo/qux': fooqux,
   1.214 +            'bin/foo/zot': foozot,
   1.215 +            'bin/foo/chrome.manifest': GeneratedFile('resource foo foo/'),
   1.216 +            'bin/chrome.manifest':
   1.217 +            GeneratedFile('manifest foo/chrome.manifest'),
   1.218 +        })
   1.219 +        parser = SimpleManifestSink(finder, formatter)
   1.220 +        component0 = Component('component0')
   1.221 +        component1 = Component('component1')
   1.222 +        component2 = Component('component2', destdir='destdir')
   1.223 +        parser.add(component0, 'bin/foo/b*')
   1.224 +        parser.add(component1, 'bin/foo/qux')
   1.225 +        parser.add(component1, 'bin/foo/chrome.manifest')
   1.226 +        parser.add(component2, 'bin/foo/zot')
   1.227 +        self.assertRaises(ErrorMessage, parser.add, 'component1', 'bin/bar')
   1.228 +
   1.229 +        self.assertEqual(formatter.log, [])
   1.230 +        parser.close()
   1.231 +        self.assertEqual(formatter.log, [
   1.232 +            (('foo/chrome.manifest', 1),
   1.233 +             'add_manifest', ManifestResource('foo', 'foo', 'foo/')),
   1.234 +            (None, 'add', 'foo/bar', foobar),
   1.235 +            (None, 'add', 'foo/baz', foobaz),
   1.236 +            (None, 'add', 'foo/qux', fooqux),
   1.237 +            (None, 'add', 'destdir/foo/zot', foozot),
   1.238 +        ])
   1.239 +
   1.240 +        self.assertEqual(finder.log, [
   1.241 +            'bin/foo/b*',
   1.242 +            'bin/foo/qux',
   1.243 +            'bin/foo/chrome.manifest',
   1.244 +            'bin/foo/zot',
   1.245 +            'bin/bar',
   1.246 +            'bin/chrome.manifest'
   1.247 +        ])
   1.248 +
   1.249 +
   1.250 +class TestCallDeque(unittest.TestCase):
   1.251 +    def test_call_deque(self):
   1.252 +        class Logger(object):
   1.253 +            def __init__(self):
   1.254 +                self._log = []
   1.255 +
   1.256 +            def log(self, str):
   1.257 +                self._log.append(str)
   1.258 +
   1.259 +            @staticmethod
   1.260 +            def staticlog(logger, str):
   1.261 +                logger.log(str)
   1.262 +
   1.263 +        def do_log(logger, str):
   1.264 +            logger.log(str)
   1.265 +
   1.266 +        logger = Logger()
   1.267 +        d = CallDeque()
   1.268 +        d.append(logger.log, 'foo')
   1.269 +        d.append(logger.log, 'bar')
   1.270 +        d.append(logger.staticlog, logger, 'baz')
   1.271 +        d.append(do_log, logger, 'qux')
   1.272 +        self.assertEqual(logger._log, [])
   1.273 +        d.execute()
   1.274 +        self.assertEqual(logger._log, ['foo', 'bar', 'baz', 'qux'])
   1.275 +
   1.276 +
   1.277 +class TestComponent(unittest.TestCase):
   1.278 +    def do_split(self, string, name, options):
   1.279 +        n, o = Component._split_component_and_options(string)
   1.280 +        self.assertEqual(name, n)
   1.281 +        self.assertEqual(options, o)
   1.282 +
   1.283 +    def test_component_split_component_and_options(self):
   1.284 +        self.do_split('component', 'component', {})
   1.285 +        self.do_split('trailingspace ', 'trailingspace', {})
   1.286 +        self.do_split(' leadingspace', 'leadingspace', {})
   1.287 +        self.do_split(' trim ', 'trim', {})
   1.288 +        self.do_split(' trim key="value"', 'trim', {'key':'value'})
   1.289 +        self.do_split(' trim empty=""', 'trim', {'empty':''})
   1.290 +        self.do_split(' trim space=" "', 'trim', {'space':' '})
   1.291 +        self.do_split('component key="value"  key2="second" ',
   1.292 +                      'component', {'key':'value', 'key2':'second'})
   1.293 +        self.do_split( 'trim key="  value with spaces   "  key2="spaces again"',
   1.294 +                       'trim', {'key':'  value with spaces   ', 'key2': 'spaces again'})
   1.295 +
   1.296 +    def do_split_error(self, string):
   1.297 +        self.assertRaises(ValueError, Component._split_component_and_options, string)
   1.298 +
   1.299 +    def test_component_split_component_and_options_errors(self):
   1.300 +        self.do_split_error('"component')
   1.301 +        self.do_split_error('comp"onent')
   1.302 +        self.do_split_error('component"')
   1.303 +        self.do_split_error('"component"')
   1.304 +        self.do_split_error('=component')
   1.305 +        self.do_split_error('comp=onent')
   1.306 +        self.do_split_error('component=')
   1.307 +        self.do_split_error('key="val"')
   1.308 +        self.do_split_error('component key=')
   1.309 +        self.do_split_error('component key="val')
   1.310 +        self.do_split_error('component key=val"')
   1.311 +        self.do_split_error('component key="val" x')
   1.312 +        self.do_split_error('component x key="val"')
   1.313 +        self.do_split_error('component key1="val" x key2="val"')
   1.314 +
   1.315 +    def do_from_string(self, string, name, destdir=''):
   1.316 +        component = Component.from_string(string)
   1.317 +        self.assertEqual(name, component.name)
   1.318 +        self.assertEqual(destdir, component.destdir)
   1.319 +
   1.320 +    def test_component_from_string(self):
   1.321 +        self.do_from_string('component', 'component')
   1.322 +        self.do_from_string('component-with-hyphen', 'component-with-hyphen')
   1.323 +        self.do_from_string('component destdir="foo/bar"', 'component', 'foo/bar')
   1.324 +        self.do_from_string('component destdir="bar spc"', 'component', 'bar spc')
   1.325 +        self.assertRaises(ErrorMessage, Component.from_string, '')
   1.326 +        self.assertRaises(ErrorMessage, Component.from_string, 'component novalue=')
   1.327 +        self.assertRaises(ErrorMessage, Component.from_string, 'component badoption=badvalue')
   1.328 +
   1.329 +
   1.330 +if __name__ == '__main__':
   1.331 +    mozunit.main()

mercurial