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