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()