python/mozbuild/mozpack/test/test_mozjar.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/python/mozbuild/mozpack/test/test_mozjar.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,315 @@
     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 +from mozpack.mozjar import (
     1.9 +    JarReaderError,
    1.10 +    JarWriterError,
    1.11 +    JarStruct,
    1.12 +    JarReader,
    1.13 +    JarWriter,
    1.14 +    Deflater,
    1.15 +    JarLog,
    1.16 +)
    1.17 +from collections import OrderedDict
    1.18 +from mozpack.test.test_files import MockDest
    1.19 +import unittest
    1.20 +import mozunit
    1.21 +from cStringIO import StringIO
    1.22 +from urllib import pathname2url
    1.23 +import mozpack.path
    1.24 +import os
    1.25 +
    1.26 +
    1.27 +class TestJarStruct(unittest.TestCase):
    1.28 +    class Foo(JarStruct):
    1.29 +        MAGIC = 0x01020304
    1.30 +        STRUCT = OrderedDict([
    1.31 +            ('foo', 'uint32'),
    1.32 +            ('bar', 'uint16'),
    1.33 +            ('qux', 'uint16'),
    1.34 +            ('length', 'uint16'),
    1.35 +            ('length2', 'uint16'),
    1.36 +            ('string', 'length'),
    1.37 +            ('string2', 'length2'),
    1.38 +        ])
    1.39 +
    1.40 +    def test_jar_struct(self):
    1.41 +        foo = TestJarStruct.Foo()
    1.42 +        self.assertEqual(foo.signature, TestJarStruct.Foo.MAGIC)
    1.43 +        self.assertEqual(foo['foo'], 0)
    1.44 +        self.assertEqual(foo['bar'], 0)
    1.45 +        self.assertEqual(foo['qux'], 0)
    1.46 +        self.assertFalse('length' in foo)
    1.47 +        self.assertFalse('length2' in foo)
    1.48 +        self.assertEqual(foo['string'], '')
    1.49 +        self.assertEqual(foo['string2'], '')
    1.50 +
    1.51 +        self.assertEqual(foo.size, 16)
    1.52 +
    1.53 +        foo['foo'] = 0x42434445
    1.54 +        foo['bar'] = 0xabcd
    1.55 +        foo['qux'] = 0xef01
    1.56 +        foo['string'] = 'abcde'
    1.57 +        foo['string2'] = 'Arbitrarily long string'
    1.58 +
    1.59 +        serialized = b'\x04\x03\x02\x01\x45\x44\x43\x42\xcd\xab\x01\xef' + \
    1.60 +                     b'\x05\x00\x17\x00abcdeArbitrarily long string'
    1.61 +        self.assertEqual(foo.size, len(serialized))
    1.62 +        foo_serialized = foo.serialize()
    1.63 +        self.assertEqual(foo_serialized, serialized)
    1.64 +
    1.65 +    def do_test_read_jar_struct(self, data):
    1.66 +        self.assertRaises(JarReaderError, TestJarStruct.Foo, data)
    1.67 +        self.assertRaises(JarReaderError, TestJarStruct.Foo, data[2:])
    1.68 +
    1.69 +        foo = TestJarStruct.Foo(data[1:])
    1.70 +        self.assertEqual(foo['foo'], 0x45444342)
    1.71 +        self.assertEqual(foo['bar'], 0xcdab)
    1.72 +        self.assertEqual(foo['qux'], 0x01ef)
    1.73 +        self.assertFalse('length' in foo)
    1.74 +        self.assertFalse('length2' in foo)
    1.75 +        self.assertEqual(foo['string'], '012345')
    1.76 +        self.assertEqual(foo['string2'], '67')
    1.77 +
    1.78 +    def test_read_jar_struct(self):
    1.79 +        data = b'\x00\x04\x03\x02\x01\x42\x43\x44\x45\xab\xcd\xef' + \
    1.80 +               b'\x01\x06\x00\x02\x0001234567890'
    1.81 +        self.do_test_read_jar_struct(data)
    1.82 +
    1.83 +    def test_read_jar_struct_memoryview(self):
    1.84 +        data = b'\x00\x04\x03\x02\x01\x42\x43\x44\x45\xab\xcd\xef' + \
    1.85 +               b'\x01\x06\x00\x02\x0001234567890'
    1.86 +        self.do_test_read_jar_struct(memoryview(data))
    1.87 +
    1.88 +
    1.89 +class TestDeflater(unittest.TestCase):
    1.90 +    def wrap(self, data):
    1.91 +        return data
    1.92 +
    1.93 +    def test_deflater_no_compress(self):
    1.94 +        deflater = Deflater(False)
    1.95 +        deflater.write(self.wrap('abc'))
    1.96 +        self.assertFalse(deflater.compressed)
    1.97 +        self.assertEqual(deflater.uncompressed_size, 3)
    1.98 +        self.assertEqual(deflater.compressed_size, deflater.uncompressed_size)
    1.99 +        self.assertEqual(deflater.compressed_data, 'abc')
   1.100 +        self.assertEqual(deflater.crc32, 0x352441c2)
   1.101 +
   1.102 +    def test_deflater_compress_no_gain(self):
   1.103 +        deflater = Deflater(True)
   1.104 +        deflater.write(self.wrap('abc'))
   1.105 +        self.assertFalse(deflater.compressed)
   1.106 +        self.assertEqual(deflater.uncompressed_size, 3)
   1.107 +        self.assertEqual(deflater.compressed_size, deflater.uncompressed_size)
   1.108 +        self.assertEqual(deflater.compressed_data, 'abc')
   1.109 +        self.assertEqual(deflater.crc32, 0x352441c2)
   1.110 +
   1.111 +    def test_deflater_compress(self):
   1.112 +        deflater = Deflater(True)
   1.113 +        deflater.write(self.wrap('aaaaaaaaaaaaanopqrstuvwxyz'))
   1.114 +        self.assertTrue(deflater.compressed)
   1.115 +        self.assertEqual(deflater.uncompressed_size, 26)
   1.116 +        self.assertNotEqual(deflater.compressed_size,
   1.117 +                            deflater.uncompressed_size)
   1.118 +        self.assertEqual(deflater.crc32, 0xd46b97ed)
   1.119 +        # The CRC is the same as when not compressed
   1.120 +        deflater = Deflater(False)
   1.121 +        self.assertFalse(deflater.compressed)
   1.122 +        deflater.write(self.wrap('aaaaaaaaaaaaanopqrstuvwxyz'))
   1.123 +        self.assertEqual(deflater.crc32, 0xd46b97ed)
   1.124 +
   1.125 +
   1.126 +class TestDeflaterMemoryView(TestDeflater):
   1.127 +    def wrap(self, data):
   1.128 +        return memoryview(data)
   1.129 +
   1.130 +
   1.131 +class TestJar(unittest.TestCase):
   1.132 +    optimize = False
   1.133 +
   1.134 +    def test_jar(self):
   1.135 +        s = MockDest()
   1.136 +        with JarWriter(fileobj=s, optimize=self.optimize) as jar:
   1.137 +            jar.add('foo', 'foo')
   1.138 +            self.assertRaises(JarWriterError, jar.add, 'foo', 'bar')
   1.139 +            jar.add('bar', 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.140 +            jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz', False)
   1.141 +
   1.142 +        files = [j for j in JarReader(fileobj=s)]
   1.143 +
   1.144 +        self.assertEqual(files[0].filename, 'foo')
   1.145 +        self.assertFalse(files[0].compressed)
   1.146 +        self.assertEqual(files[0].read(), 'foo')
   1.147 +
   1.148 +        self.assertEqual(files[1].filename, 'bar')
   1.149 +        self.assertTrue(files[1].compressed)
   1.150 +        self.assertEqual(files[1].read(), 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.151 +
   1.152 +        self.assertEqual(files[2].filename, 'baz/qux')
   1.153 +        self.assertFalse(files[2].compressed)
   1.154 +        self.assertEqual(files[2].read(), 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.155 +
   1.156 +        s = MockDest()
   1.157 +        with JarWriter(fileobj=s, compress=False,
   1.158 +                       optimize=self.optimize) as jar:
   1.159 +            jar.add('bar', 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.160 +            jar.add('foo', 'foo')
   1.161 +            jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz', True)
   1.162 +
   1.163 +        jar = JarReader(fileobj=s)
   1.164 +        files = [j for j in jar]
   1.165 +
   1.166 +        self.assertEqual(files[0].filename, 'bar')
   1.167 +        self.assertFalse(files[0].compressed)
   1.168 +        self.assertEqual(files[0].read(), 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.169 +
   1.170 +        self.assertEqual(files[1].filename, 'foo')
   1.171 +        self.assertFalse(files[1].compressed)
   1.172 +        self.assertEqual(files[1].read(), 'foo')
   1.173 +
   1.174 +        self.assertEqual(files[2].filename, 'baz/qux')
   1.175 +        self.assertTrue(files[2].compressed)
   1.176 +        self.assertEqual(files[2].read(), 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.177 +
   1.178 +        self.assertTrue('bar' in jar)
   1.179 +        self.assertTrue('foo' in jar)
   1.180 +        self.assertFalse('baz' in jar)
   1.181 +        self.assertTrue('baz/qux' in jar)
   1.182 +        self.assertTrue(jar['bar'], files[1])
   1.183 +        self.assertTrue(jar['foo'], files[0])
   1.184 +        self.assertTrue(jar['baz/qux'], files[2])
   1.185 +
   1.186 +        s.seek(0)
   1.187 +        jar = JarReader(fileobj=s)
   1.188 +        self.assertTrue('bar' in jar)
   1.189 +        self.assertTrue('foo' in jar)
   1.190 +        self.assertFalse('baz' in jar)
   1.191 +        self.assertTrue('baz/qux' in jar)
   1.192 +
   1.193 +        files[0].seek(0)
   1.194 +        self.assertEqual(jar['bar'].filename, files[0].filename)
   1.195 +        self.assertEqual(jar['bar'].compressed, files[0].compressed)
   1.196 +        self.assertEqual(jar['bar'].read(), files[0].read())
   1.197 +
   1.198 +        files[1].seek(0)
   1.199 +        self.assertEqual(jar['foo'].filename, files[1].filename)
   1.200 +        self.assertEqual(jar['foo'].compressed, files[1].compressed)
   1.201 +        self.assertEqual(jar['foo'].read(), files[1].read())
   1.202 +
   1.203 +        files[2].seek(0)
   1.204 +        self.assertEqual(jar['baz/qux'].filename, files[2].filename)
   1.205 +        self.assertEqual(jar['baz/qux'].compressed, files[2].compressed)
   1.206 +        self.assertEqual(jar['baz/qux'].read(), files[2].read())
   1.207 +
   1.208 +    def test_rejar(self):
   1.209 +        s = MockDest()
   1.210 +        with JarWriter(fileobj=s, optimize=self.optimize) as jar:
   1.211 +            jar.add('foo', 'foo')
   1.212 +            jar.add('bar', 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.213 +            jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz', False)
   1.214 +
   1.215 +        new = MockDest()
   1.216 +        with JarWriter(fileobj=new, optimize=self.optimize) as jar:
   1.217 +            for j in JarReader(fileobj=s):
   1.218 +                jar.add(j.filename, j)
   1.219 +
   1.220 +        jar = JarReader(fileobj=new)
   1.221 +        files = [j for j in jar]
   1.222 +
   1.223 +        self.assertEqual(files[0].filename, 'foo')
   1.224 +        self.assertFalse(files[0].compressed)
   1.225 +        self.assertEqual(files[0].read(), 'foo')
   1.226 +
   1.227 +        self.assertEqual(files[1].filename, 'bar')
   1.228 +        self.assertTrue(files[1].compressed)
   1.229 +        self.assertEqual(files[1].read(), 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.230 +
   1.231 +        self.assertEqual(files[2].filename, 'baz/qux')
   1.232 +        self.assertTrue(files[2].compressed)
   1.233 +        self.assertEqual(files[2].read(), 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.234 +
   1.235 +
   1.236 +class TestOptimizeJar(TestJar):
   1.237 +    optimize = True
   1.238 +
   1.239 +
   1.240 +class TestPreload(unittest.TestCase):
   1.241 +    def test_preload(self):
   1.242 +        s = MockDest()
   1.243 +        with JarWriter(fileobj=s) as jar:
   1.244 +            jar.add('foo', 'foo')
   1.245 +            jar.add('bar', 'abcdefghijklmnopqrstuvwxyz')
   1.246 +            jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.247 +
   1.248 +        jar = JarReader(fileobj=s)
   1.249 +        self.assertEqual(jar.last_preloaded, None)
   1.250 +
   1.251 +        with JarWriter(fileobj=s) as jar:
   1.252 +            jar.add('foo', 'foo')
   1.253 +            jar.add('bar', 'abcdefghijklmnopqrstuvwxyz')
   1.254 +            jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz')
   1.255 +            jar.preload(['baz/qux', 'bar'])
   1.256 +
   1.257 +        jar = JarReader(fileobj=s)
   1.258 +        self.assertEqual(jar.last_preloaded, 'bar')
   1.259 +        files = [j for j in jar]
   1.260 +
   1.261 +        self.assertEqual(files[0].filename, 'baz/qux')
   1.262 +        self.assertEqual(files[1].filename, 'bar')
   1.263 +        self.assertEqual(files[2].filename, 'foo')
   1.264 +
   1.265 +
   1.266 +class TestJarLog(unittest.TestCase):
   1.267 +    def test_jarlog(self):
   1.268 +        base = 'file:' + pathname2url(os.path.abspath(os.curdir))
   1.269 +        s = StringIO('\n'.join([
   1.270 +            base + '/bar/baz.jar first',
   1.271 +            base + '/bar/baz.jar second',
   1.272 +            base + '/bar/baz.jar third',
   1.273 +            base + '/bar/baz.jar second',
   1.274 +            base + '/bar/baz.jar second',
   1.275 +            'jar:' + base + '/qux.zip!/omni.ja stuff',
   1.276 +            base + '/bar/baz.jar first',
   1.277 +            'jar:' + base + '/qux.zip!/omni.ja other/stuff',
   1.278 +            'jar:' + base + '/qux.zip!/omni.ja stuff',
   1.279 +            base + '/bar/baz.jar third',
   1.280 +            'jar:jar:' + base + '/qux.zip!/baz/baz.jar!/omni.ja nested/stuff',
   1.281 +            'jar:jar:jar:' + base + '/qux.zip!/baz/baz.jar!/foo.zip!/omni.ja' +
   1.282 +            ' deeply/nested/stuff',
   1.283 +        ]))
   1.284 +        log = JarLog(fileobj=s)
   1.285 +        canonicalize = lambda p: \
   1.286 +            mozpack.path.normsep(os.path.normcase(os.path.realpath(p)))
   1.287 +        baz_jar = canonicalize('bar/baz.jar')
   1.288 +        qux_zip = canonicalize('qux.zip')
   1.289 +        self.assertEqual(set(log.keys()), set([
   1.290 +            baz_jar,
   1.291 +            (qux_zip, 'omni.ja'),
   1.292 +            (qux_zip, 'baz/baz.jar', 'omni.ja'),
   1.293 +            (qux_zip, 'baz/baz.jar', 'foo.zip', 'omni.ja'),
   1.294 +        ]))
   1.295 +        self.assertEqual(log[baz_jar], [
   1.296 +            'first',
   1.297 +            'second',
   1.298 +            'third',
   1.299 +        ])
   1.300 +        self.assertEqual(log[(qux_zip, 'omni.ja')], [
   1.301 +            'stuff',
   1.302 +            'other/stuff',
   1.303 +        ])
   1.304 +        self.assertEqual(log[(qux_zip, 'baz/baz.jar', 'omni.ja')],
   1.305 +                         ['nested/stuff'])
   1.306 +        self.assertEqual(log[(qux_zip, 'baz/baz.jar', 'foo.zip',
   1.307 +                              'omni.ja')], ['deeply/nested/stuff'])
   1.308 +
   1.309 +        # The above tests also indirectly check the value returned by
   1.310 +        # JarLog.canonicalize for various jar: and file: urls, but
   1.311 +        # JarLog.canonicalize also supports plain paths.
   1.312 +        self.assertEqual(JarLog.canonicalize(os.path.abspath('bar/baz.jar')),
   1.313 +                         baz_jar)
   1.314 +        self.assertEqual(JarLog.canonicalize('bar/baz.jar'), baz_jar)
   1.315 +
   1.316 +
   1.317 +if __name__ == '__main__':
   1.318 +    mozunit.main()

mercurial