python/mozbuild/mozpack/test/test_packager.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 import unittest
michael@0 6 import mozunit
michael@0 7 import os
michael@0 8 from mozpack.packager import (
michael@0 9 preprocess_manifest,
michael@0 10 CallDeque,
michael@0 11 Component,
michael@0 12 SimplePackager,
michael@0 13 SimpleManifestSink,
michael@0 14 )
michael@0 15 from mozpack.files import GeneratedFile
michael@0 16 from mozpack.chrome.manifest import (
michael@0 17 ManifestResource,
michael@0 18 ManifestContent,
michael@0 19 )
michael@0 20 from mozunit import MockedOpen
michael@0 21 from mozbuild.preprocessor import Preprocessor
michael@0 22 from mozpack.errors import (
michael@0 23 errors,
michael@0 24 ErrorMessage,
michael@0 25 )
michael@0 26 import mozpack.path
michael@0 27
michael@0 28 MANIFEST = '''
michael@0 29 bar/*
michael@0 30 [foo]
michael@0 31 foo/*
michael@0 32 -foo/bar
michael@0 33 chrome.manifest
michael@0 34 [zot destdir="destdir"]
michael@0 35 foo/zot
michael@0 36 ; comment
michael@0 37 #ifdef baz
michael@0 38 [baz]
michael@0 39 baz@SUFFIX@
michael@0 40 #endif
michael@0 41 '''
michael@0 42
michael@0 43
michael@0 44 class TestPreprocessManifest(unittest.TestCase):
michael@0 45 MANIFEST_PATH = os.path.join(os.path.abspath(os.curdir), 'manifest')
michael@0 46
michael@0 47 EXPECTED_LOG = [
michael@0 48 ((MANIFEST_PATH, 2), 'add', '', 'bar/*'),
michael@0 49 ((MANIFEST_PATH, 4), 'add', 'foo', 'foo/*'),
michael@0 50 ((MANIFEST_PATH, 5), 'remove', 'foo', 'foo/bar'),
michael@0 51 ((MANIFEST_PATH, 6), 'add', 'foo', 'chrome.manifest'),
michael@0 52 ((MANIFEST_PATH, 8), 'add', 'zot destdir="destdir"', 'foo/zot'),
michael@0 53 ]
michael@0 54
michael@0 55 def setUp(self):
michael@0 56 class MockSink(object):
michael@0 57 def __init__(self):
michael@0 58 self.log = []
michael@0 59
michael@0 60 def add(self, component, path):
michael@0 61 self._log(errors.get_context(), 'add', repr(component), path)
michael@0 62
michael@0 63 def remove(self, component, path):
michael@0 64 self._log(errors.get_context(), 'remove', repr(component), path)
michael@0 65
michael@0 66 def _log(self, *args):
michael@0 67 self.log.append(args)
michael@0 68
michael@0 69 self.sink = MockSink()
michael@0 70
michael@0 71 def test_preprocess_manifest(self):
michael@0 72 with MockedOpen({'manifest': MANIFEST}):
michael@0 73 preprocess_manifest(self.sink, 'manifest')
michael@0 74 self.assertEqual(self.sink.log, self.EXPECTED_LOG)
michael@0 75
michael@0 76 def test_preprocess_manifest_missing_define(self):
michael@0 77 with MockedOpen({'manifest': MANIFEST}):
michael@0 78 self.assertRaises(
michael@0 79 Preprocessor.Error,
michael@0 80 preprocess_manifest,
michael@0 81 self.sink,
michael@0 82 'manifest',
michael@0 83 {'baz': 1}
michael@0 84 )
michael@0 85
michael@0 86 def test_preprocess_manifest_defines(self):
michael@0 87 with MockedOpen({'manifest': MANIFEST}):
michael@0 88 preprocess_manifest(self.sink, 'manifest',
michael@0 89 {'baz': 1, 'SUFFIX': '.exe'})
michael@0 90 self.assertEqual(self.sink.log, self.EXPECTED_LOG +
michael@0 91 [((self.MANIFEST_PATH, 12), 'add', 'baz', 'baz.exe')])
michael@0 92
michael@0 93
michael@0 94 class MockFinder(object):
michael@0 95 def __init__(self, files):
michael@0 96 self.files = files
michael@0 97 self.log = []
michael@0 98
michael@0 99 def find(self, path):
michael@0 100 self.log.append(path)
michael@0 101 for f in sorted(self.files):
michael@0 102 if mozpack.path.match(f, path):
michael@0 103 yield f, self.files[f]
michael@0 104
michael@0 105 def __iter__(self):
michael@0 106 return self.find('')
michael@0 107
michael@0 108
michael@0 109 class MockFormatter(object):
michael@0 110 def __init__(self):
michael@0 111 self.log = []
michael@0 112
michael@0 113 def add_base(self, *args):
michael@0 114 self._log(errors.get_context(), 'add_base', *args)
michael@0 115
michael@0 116 def add_manifest(self, *args):
michael@0 117 self._log(errors.get_context(), 'add_manifest', *args)
michael@0 118
michael@0 119 def add_interfaces(self, *args):
michael@0 120 self._log(errors.get_context(), 'add_interfaces', *args)
michael@0 121
michael@0 122 def add(self, *args):
michael@0 123 self._log(errors.get_context(), 'add', *args)
michael@0 124
michael@0 125 def _log(self, *args):
michael@0 126 self.log.append(args)
michael@0 127
michael@0 128
michael@0 129 class TestSimplePackager(unittest.TestCase):
michael@0 130 def test_simple_packager(self):
michael@0 131 class GeneratedFileWithPath(GeneratedFile):
michael@0 132 def __init__(self, path, content):
michael@0 133 GeneratedFile.__init__(self, content)
michael@0 134 self.path = path
michael@0 135
michael@0 136 formatter = MockFormatter()
michael@0 137 packager = SimplePackager(formatter)
michael@0 138 curdir = os.path.abspath(os.curdir)
michael@0 139 file = GeneratedFileWithPath(os.path.join(curdir, 'foo',
michael@0 140 'bar.manifest'),
michael@0 141 'resource bar bar/\ncontent bar bar/')
michael@0 142 with errors.context('manifest', 1):
michael@0 143 packager.add('foo/bar.manifest', file)
michael@0 144
michael@0 145 file = GeneratedFileWithPath(os.path.join(curdir, 'foo',
michael@0 146 'baz.manifest'),
michael@0 147 'resource baz baz/')
michael@0 148 with errors.context('manifest', 2):
michael@0 149 packager.add('bar/baz.manifest', file)
michael@0 150
michael@0 151 with errors.context('manifest', 3):
michael@0 152 packager.add('qux/qux.manifest',
michael@0 153 GeneratedFile('resource qux qux/'))
michael@0 154 bar_xpt = GeneratedFile('bar.xpt')
michael@0 155 qux_xpt = GeneratedFile('qux.xpt')
michael@0 156 foo_html = GeneratedFile('foo_html')
michael@0 157 bar_html = GeneratedFile('bar_html')
michael@0 158 with errors.context('manifest', 4):
michael@0 159 packager.add('foo/bar.xpt', bar_xpt)
michael@0 160 with errors.context('manifest', 5):
michael@0 161 packager.add('foo/bar/foo.html', foo_html)
michael@0 162 packager.add('foo/bar/bar.html', bar_html)
michael@0 163
michael@0 164 file = GeneratedFileWithPath(os.path.join(curdir, 'foo.manifest'),
michael@0 165 ''.join([
michael@0 166 'manifest foo/bar.manifest\n',
michael@0 167 'manifest bar/baz.manifest\n',
michael@0 168 ]))
michael@0 169 with errors.context('manifest', 6):
michael@0 170 packager.add('foo.manifest', file)
michael@0 171 with errors.context('manifest', 7):
michael@0 172 packager.add('foo/qux.xpt', qux_xpt)
michael@0 173
michael@0 174 self.assertEqual(formatter.log, [])
michael@0 175
michael@0 176 with errors.context('dummy', 1):
michael@0 177 packager.close()
michael@0 178 self.maxDiff = None
michael@0 179 # The formatter is expected to reorder the manifest entries so that
michael@0 180 # chrome entries appear before the others.
michael@0 181 self.assertEqual(formatter.log, [
michael@0 182 (('dummy', 1), 'add_base', 'qux'),
michael@0 183 ((os.path.join(curdir, 'foo', 'bar.manifest'), 2),
michael@0 184 'add_manifest', ManifestContent('foo', 'bar', 'bar/')),
michael@0 185 ((os.path.join(curdir, 'foo', 'bar.manifest'), 1),
michael@0 186 'add_manifest', ManifestResource('foo', 'bar', 'bar/')),
michael@0 187 (('bar/baz.manifest', 1),
michael@0 188 'add_manifest', ManifestResource('bar', 'baz', 'baz/')),
michael@0 189 (('qux/qux.manifest', 1),
michael@0 190 'add_manifest', ManifestResource('qux', 'qux', 'qux/')),
michael@0 191 (('manifest', 4), 'add_interfaces', 'foo/bar.xpt', bar_xpt),
michael@0 192 (('manifest', 7), 'add_interfaces', 'foo/qux.xpt', qux_xpt),
michael@0 193 (('manifest', 5), 'add', 'foo/bar/foo.html', foo_html),
michael@0 194 (('manifest', 5), 'add', 'foo/bar/bar.html', bar_html),
michael@0 195 ])
michael@0 196
michael@0 197 self.assertEqual(packager.get_bases(), set(['', 'qux']))
michael@0 198
michael@0 199
michael@0 200 class TestSimpleManifestSink(unittest.TestCase):
michael@0 201 def test_simple_manifest_parser(self):
michael@0 202 formatter = MockFormatter()
michael@0 203 foobar = GeneratedFile('foobar')
michael@0 204 foobaz = GeneratedFile('foobaz')
michael@0 205 fooqux = GeneratedFile('fooqux')
michael@0 206 foozot = GeneratedFile('foozot')
michael@0 207 finder = MockFinder({
michael@0 208 'bin/foo/bar': foobar,
michael@0 209 'bin/foo/baz': foobaz,
michael@0 210 'bin/foo/qux': fooqux,
michael@0 211 'bin/foo/zot': foozot,
michael@0 212 'bin/foo/chrome.manifest': GeneratedFile('resource foo foo/'),
michael@0 213 'bin/chrome.manifest':
michael@0 214 GeneratedFile('manifest foo/chrome.manifest'),
michael@0 215 })
michael@0 216 parser = SimpleManifestSink(finder, formatter)
michael@0 217 component0 = Component('component0')
michael@0 218 component1 = Component('component1')
michael@0 219 component2 = Component('component2', destdir='destdir')
michael@0 220 parser.add(component0, 'bin/foo/b*')
michael@0 221 parser.add(component1, 'bin/foo/qux')
michael@0 222 parser.add(component1, 'bin/foo/chrome.manifest')
michael@0 223 parser.add(component2, 'bin/foo/zot')
michael@0 224 self.assertRaises(ErrorMessage, parser.add, 'component1', 'bin/bar')
michael@0 225
michael@0 226 self.assertEqual(formatter.log, [])
michael@0 227 parser.close()
michael@0 228 self.assertEqual(formatter.log, [
michael@0 229 (('foo/chrome.manifest', 1),
michael@0 230 'add_manifest', ManifestResource('foo', 'foo', 'foo/')),
michael@0 231 (None, 'add', 'foo/bar', foobar),
michael@0 232 (None, 'add', 'foo/baz', foobaz),
michael@0 233 (None, 'add', 'foo/qux', fooqux),
michael@0 234 (None, 'add', 'destdir/foo/zot', foozot),
michael@0 235 ])
michael@0 236
michael@0 237 self.assertEqual(finder.log, [
michael@0 238 'bin/foo/b*',
michael@0 239 'bin/foo/qux',
michael@0 240 'bin/foo/chrome.manifest',
michael@0 241 'bin/foo/zot',
michael@0 242 'bin/bar',
michael@0 243 'bin/chrome.manifest'
michael@0 244 ])
michael@0 245
michael@0 246
michael@0 247 class TestCallDeque(unittest.TestCase):
michael@0 248 def test_call_deque(self):
michael@0 249 class Logger(object):
michael@0 250 def __init__(self):
michael@0 251 self._log = []
michael@0 252
michael@0 253 def log(self, str):
michael@0 254 self._log.append(str)
michael@0 255
michael@0 256 @staticmethod
michael@0 257 def staticlog(logger, str):
michael@0 258 logger.log(str)
michael@0 259
michael@0 260 def do_log(logger, str):
michael@0 261 logger.log(str)
michael@0 262
michael@0 263 logger = Logger()
michael@0 264 d = CallDeque()
michael@0 265 d.append(logger.log, 'foo')
michael@0 266 d.append(logger.log, 'bar')
michael@0 267 d.append(logger.staticlog, logger, 'baz')
michael@0 268 d.append(do_log, logger, 'qux')
michael@0 269 self.assertEqual(logger._log, [])
michael@0 270 d.execute()
michael@0 271 self.assertEqual(logger._log, ['foo', 'bar', 'baz', 'qux'])
michael@0 272
michael@0 273
michael@0 274 class TestComponent(unittest.TestCase):
michael@0 275 def do_split(self, string, name, options):
michael@0 276 n, o = Component._split_component_and_options(string)
michael@0 277 self.assertEqual(name, n)
michael@0 278 self.assertEqual(options, o)
michael@0 279
michael@0 280 def test_component_split_component_and_options(self):
michael@0 281 self.do_split('component', 'component', {})
michael@0 282 self.do_split('trailingspace ', 'trailingspace', {})
michael@0 283 self.do_split(' leadingspace', 'leadingspace', {})
michael@0 284 self.do_split(' trim ', 'trim', {})
michael@0 285 self.do_split(' trim key="value"', 'trim', {'key':'value'})
michael@0 286 self.do_split(' trim empty=""', 'trim', {'empty':''})
michael@0 287 self.do_split(' trim space=" "', 'trim', {'space':' '})
michael@0 288 self.do_split('component key="value" key2="second" ',
michael@0 289 'component', {'key':'value', 'key2':'second'})
michael@0 290 self.do_split( 'trim key=" value with spaces " key2="spaces again"',
michael@0 291 'trim', {'key':' value with spaces ', 'key2': 'spaces again'})
michael@0 292
michael@0 293 def do_split_error(self, string):
michael@0 294 self.assertRaises(ValueError, Component._split_component_and_options, string)
michael@0 295
michael@0 296 def test_component_split_component_and_options_errors(self):
michael@0 297 self.do_split_error('"component')
michael@0 298 self.do_split_error('comp"onent')
michael@0 299 self.do_split_error('component"')
michael@0 300 self.do_split_error('"component"')
michael@0 301 self.do_split_error('=component')
michael@0 302 self.do_split_error('comp=onent')
michael@0 303 self.do_split_error('component=')
michael@0 304 self.do_split_error('key="val"')
michael@0 305 self.do_split_error('component key=')
michael@0 306 self.do_split_error('component key="val')
michael@0 307 self.do_split_error('component key=val"')
michael@0 308 self.do_split_error('component key="val" x')
michael@0 309 self.do_split_error('component x key="val"')
michael@0 310 self.do_split_error('component key1="val" x key2="val"')
michael@0 311
michael@0 312 def do_from_string(self, string, name, destdir=''):
michael@0 313 component = Component.from_string(string)
michael@0 314 self.assertEqual(name, component.name)
michael@0 315 self.assertEqual(destdir, component.destdir)
michael@0 316
michael@0 317 def test_component_from_string(self):
michael@0 318 self.do_from_string('component', 'component')
michael@0 319 self.do_from_string('component-with-hyphen', 'component-with-hyphen')
michael@0 320 self.do_from_string('component destdir="foo/bar"', 'component', 'foo/bar')
michael@0 321 self.do_from_string('component destdir="bar spc"', 'component', 'bar spc')
michael@0 322 self.assertRaises(ErrorMessage, Component.from_string, '')
michael@0 323 self.assertRaises(ErrorMessage, Component.from_string, 'component novalue=')
michael@0 324 self.assertRaises(ErrorMessage, Component.from_string, 'component badoption=badvalue')
michael@0 325
michael@0 326
michael@0 327 if __name__ == '__main__':
michael@0 328 mozunit.main()

mercurial