Fri, 16 Jan 2015 18:13:44 +0100
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() |