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 | from mozpack.mozjar import ( |
michael@0 | 6 | JarReaderError, |
michael@0 | 7 | JarWriterError, |
michael@0 | 8 | JarStruct, |
michael@0 | 9 | JarReader, |
michael@0 | 10 | JarWriter, |
michael@0 | 11 | Deflater, |
michael@0 | 12 | JarLog, |
michael@0 | 13 | ) |
michael@0 | 14 | from collections import OrderedDict |
michael@0 | 15 | from mozpack.test.test_files import MockDest |
michael@0 | 16 | import unittest |
michael@0 | 17 | import mozunit |
michael@0 | 18 | from cStringIO import StringIO |
michael@0 | 19 | from urllib import pathname2url |
michael@0 | 20 | import mozpack.path |
michael@0 | 21 | import os |
michael@0 | 22 | |
michael@0 | 23 | |
michael@0 | 24 | class TestJarStruct(unittest.TestCase): |
michael@0 | 25 | class Foo(JarStruct): |
michael@0 | 26 | MAGIC = 0x01020304 |
michael@0 | 27 | STRUCT = OrderedDict([ |
michael@0 | 28 | ('foo', 'uint32'), |
michael@0 | 29 | ('bar', 'uint16'), |
michael@0 | 30 | ('qux', 'uint16'), |
michael@0 | 31 | ('length', 'uint16'), |
michael@0 | 32 | ('length2', 'uint16'), |
michael@0 | 33 | ('string', 'length'), |
michael@0 | 34 | ('string2', 'length2'), |
michael@0 | 35 | ]) |
michael@0 | 36 | |
michael@0 | 37 | def test_jar_struct(self): |
michael@0 | 38 | foo = TestJarStruct.Foo() |
michael@0 | 39 | self.assertEqual(foo.signature, TestJarStruct.Foo.MAGIC) |
michael@0 | 40 | self.assertEqual(foo['foo'], 0) |
michael@0 | 41 | self.assertEqual(foo['bar'], 0) |
michael@0 | 42 | self.assertEqual(foo['qux'], 0) |
michael@0 | 43 | self.assertFalse('length' in foo) |
michael@0 | 44 | self.assertFalse('length2' in foo) |
michael@0 | 45 | self.assertEqual(foo['string'], '') |
michael@0 | 46 | self.assertEqual(foo['string2'], '') |
michael@0 | 47 | |
michael@0 | 48 | self.assertEqual(foo.size, 16) |
michael@0 | 49 | |
michael@0 | 50 | foo['foo'] = 0x42434445 |
michael@0 | 51 | foo['bar'] = 0xabcd |
michael@0 | 52 | foo['qux'] = 0xef01 |
michael@0 | 53 | foo['string'] = 'abcde' |
michael@0 | 54 | foo['string2'] = 'Arbitrarily long string' |
michael@0 | 55 | |
michael@0 | 56 | serialized = b'\x04\x03\x02\x01\x45\x44\x43\x42\xcd\xab\x01\xef' + \ |
michael@0 | 57 | b'\x05\x00\x17\x00abcdeArbitrarily long string' |
michael@0 | 58 | self.assertEqual(foo.size, len(serialized)) |
michael@0 | 59 | foo_serialized = foo.serialize() |
michael@0 | 60 | self.assertEqual(foo_serialized, serialized) |
michael@0 | 61 | |
michael@0 | 62 | def do_test_read_jar_struct(self, data): |
michael@0 | 63 | self.assertRaises(JarReaderError, TestJarStruct.Foo, data) |
michael@0 | 64 | self.assertRaises(JarReaderError, TestJarStruct.Foo, data[2:]) |
michael@0 | 65 | |
michael@0 | 66 | foo = TestJarStruct.Foo(data[1:]) |
michael@0 | 67 | self.assertEqual(foo['foo'], 0x45444342) |
michael@0 | 68 | self.assertEqual(foo['bar'], 0xcdab) |
michael@0 | 69 | self.assertEqual(foo['qux'], 0x01ef) |
michael@0 | 70 | self.assertFalse('length' in foo) |
michael@0 | 71 | self.assertFalse('length2' in foo) |
michael@0 | 72 | self.assertEqual(foo['string'], '012345') |
michael@0 | 73 | self.assertEqual(foo['string2'], '67') |
michael@0 | 74 | |
michael@0 | 75 | def test_read_jar_struct(self): |
michael@0 | 76 | data = b'\x00\x04\x03\x02\x01\x42\x43\x44\x45\xab\xcd\xef' + \ |
michael@0 | 77 | b'\x01\x06\x00\x02\x0001234567890' |
michael@0 | 78 | self.do_test_read_jar_struct(data) |
michael@0 | 79 | |
michael@0 | 80 | def test_read_jar_struct_memoryview(self): |
michael@0 | 81 | data = b'\x00\x04\x03\x02\x01\x42\x43\x44\x45\xab\xcd\xef' + \ |
michael@0 | 82 | b'\x01\x06\x00\x02\x0001234567890' |
michael@0 | 83 | self.do_test_read_jar_struct(memoryview(data)) |
michael@0 | 84 | |
michael@0 | 85 | |
michael@0 | 86 | class TestDeflater(unittest.TestCase): |
michael@0 | 87 | def wrap(self, data): |
michael@0 | 88 | return data |
michael@0 | 89 | |
michael@0 | 90 | def test_deflater_no_compress(self): |
michael@0 | 91 | deflater = Deflater(False) |
michael@0 | 92 | deflater.write(self.wrap('abc')) |
michael@0 | 93 | self.assertFalse(deflater.compressed) |
michael@0 | 94 | self.assertEqual(deflater.uncompressed_size, 3) |
michael@0 | 95 | self.assertEqual(deflater.compressed_size, deflater.uncompressed_size) |
michael@0 | 96 | self.assertEqual(deflater.compressed_data, 'abc') |
michael@0 | 97 | self.assertEqual(deflater.crc32, 0x352441c2) |
michael@0 | 98 | |
michael@0 | 99 | def test_deflater_compress_no_gain(self): |
michael@0 | 100 | deflater = Deflater(True) |
michael@0 | 101 | deflater.write(self.wrap('abc')) |
michael@0 | 102 | self.assertFalse(deflater.compressed) |
michael@0 | 103 | self.assertEqual(deflater.uncompressed_size, 3) |
michael@0 | 104 | self.assertEqual(deflater.compressed_size, deflater.uncompressed_size) |
michael@0 | 105 | self.assertEqual(deflater.compressed_data, 'abc') |
michael@0 | 106 | self.assertEqual(deflater.crc32, 0x352441c2) |
michael@0 | 107 | |
michael@0 | 108 | def test_deflater_compress(self): |
michael@0 | 109 | deflater = Deflater(True) |
michael@0 | 110 | deflater.write(self.wrap('aaaaaaaaaaaaanopqrstuvwxyz')) |
michael@0 | 111 | self.assertTrue(deflater.compressed) |
michael@0 | 112 | self.assertEqual(deflater.uncompressed_size, 26) |
michael@0 | 113 | self.assertNotEqual(deflater.compressed_size, |
michael@0 | 114 | deflater.uncompressed_size) |
michael@0 | 115 | self.assertEqual(deflater.crc32, 0xd46b97ed) |
michael@0 | 116 | # The CRC is the same as when not compressed |
michael@0 | 117 | deflater = Deflater(False) |
michael@0 | 118 | self.assertFalse(deflater.compressed) |
michael@0 | 119 | deflater.write(self.wrap('aaaaaaaaaaaaanopqrstuvwxyz')) |
michael@0 | 120 | self.assertEqual(deflater.crc32, 0xd46b97ed) |
michael@0 | 121 | |
michael@0 | 122 | |
michael@0 | 123 | class TestDeflaterMemoryView(TestDeflater): |
michael@0 | 124 | def wrap(self, data): |
michael@0 | 125 | return memoryview(data) |
michael@0 | 126 | |
michael@0 | 127 | |
michael@0 | 128 | class TestJar(unittest.TestCase): |
michael@0 | 129 | optimize = False |
michael@0 | 130 | |
michael@0 | 131 | def test_jar(self): |
michael@0 | 132 | s = MockDest() |
michael@0 | 133 | with JarWriter(fileobj=s, optimize=self.optimize) as jar: |
michael@0 | 134 | jar.add('foo', 'foo') |
michael@0 | 135 | self.assertRaises(JarWriterError, jar.add, 'foo', 'bar') |
michael@0 | 136 | jar.add('bar', 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 137 | jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz', False) |
michael@0 | 138 | |
michael@0 | 139 | files = [j for j in JarReader(fileobj=s)] |
michael@0 | 140 | |
michael@0 | 141 | self.assertEqual(files[0].filename, 'foo') |
michael@0 | 142 | self.assertFalse(files[0].compressed) |
michael@0 | 143 | self.assertEqual(files[0].read(), 'foo') |
michael@0 | 144 | |
michael@0 | 145 | self.assertEqual(files[1].filename, 'bar') |
michael@0 | 146 | self.assertTrue(files[1].compressed) |
michael@0 | 147 | self.assertEqual(files[1].read(), 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 148 | |
michael@0 | 149 | self.assertEqual(files[2].filename, 'baz/qux') |
michael@0 | 150 | self.assertFalse(files[2].compressed) |
michael@0 | 151 | self.assertEqual(files[2].read(), 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 152 | |
michael@0 | 153 | s = MockDest() |
michael@0 | 154 | with JarWriter(fileobj=s, compress=False, |
michael@0 | 155 | optimize=self.optimize) as jar: |
michael@0 | 156 | jar.add('bar', 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 157 | jar.add('foo', 'foo') |
michael@0 | 158 | jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz', True) |
michael@0 | 159 | |
michael@0 | 160 | jar = JarReader(fileobj=s) |
michael@0 | 161 | files = [j for j in jar] |
michael@0 | 162 | |
michael@0 | 163 | self.assertEqual(files[0].filename, 'bar') |
michael@0 | 164 | self.assertFalse(files[0].compressed) |
michael@0 | 165 | self.assertEqual(files[0].read(), 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 166 | |
michael@0 | 167 | self.assertEqual(files[1].filename, 'foo') |
michael@0 | 168 | self.assertFalse(files[1].compressed) |
michael@0 | 169 | self.assertEqual(files[1].read(), 'foo') |
michael@0 | 170 | |
michael@0 | 171 | self.assertEqual(files[2].filename, 'baz/qux') |
michael@0 | 172 | self.assertTrue(files[2].compressed) |
michael@0 | 173 | self.assertEqual(files[2].read(), 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 174 | |
michael@0 | 175 | self.assertTrue('bar' in jar) |
michael@0 | 176 | self.assertTrue('foo' in jar) |
michael@0 | 177 | self.assertFalse('baz' in jar) |
michael@0 | 178 | self.assertTrue('baz/qux' in jar) |
michael@0 | 179 | self.assertTrue(jar['bar'], files[1]) |
michael@0 | 180 | self.assertTrue(jar['foo'], files[0]) |
michael@0 | 181 | self.assertTrue(jar['baz/qux'], files[2]) |
michael@0 | 182 | |
michael@0 | 183 | s.seek(0) |
michael@0 | 184 | jar = JarReader(fileobj=s) |
michael@0 | 185 | self.assertTrue('bar' in jar) |
michael@0 | 186 | self.assertTrue('foo' in jar) |
michael@0 | 187 | self.assertFalse('baz' in jar) |
michael@0 | 188 | self.assertTrue('baz/qux' in jar) |
michael@0 | 189 | |
michael@0 | 190 | files[0].seek(0) |
michael@0 | 191 | self.assertEqual(jar['bar'].filename, files[0].filename) |
michael@0 | 192 | self.assertEqual(jar['bar'].compressed, files[0].compressed) |
michael@0 | 193 | self.assertEqual(jar['bar'].read(), files[0].read()) |
michael@0 | 194 | |
michael@0 | 195 | files[1].seek(0) |
michael@0 | 196 | self.assertEqual(jar['foo'].filename, files[1].filename) |
michael@0 | 197 | self.assertEqual(jar['foo'].compressed, files[1].compressed) |
michael@0 | 198 | self.assertEqual(jar['foo'].read(), files[1].read()) |
michael@0 | 199 | |
michael@0 | 200 | files[2].seek(0) |
michael@0 | 201 | self.assertEqual(jar['baz/qux'].filename, files[2].filename) |
michael@0 | 202 | self.assertEqual(jar['baz/qux'].compressed, files[2].compressed) |
michael@0 | 203 | self.assertEqual(jar['baz/qux'].read(), files[2].read()) |
michael@0 | 204 | |
michael@0 | 205 | def test_rejar(self): |
michael@0 | 206 | s = MockDest() |
michael@0 | 207 | with JarWriter(fileobj=s, optimize=self.optimize) as jar: |
michael@0 | 208 | jar.add('foo', 'foo') |
michael@0 | 209 | jar.add('bar', 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 210 | jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz', False) |
michael@0 | 211 | |
michael@0 | 212 | new = MockDest() |
michael@0 | 213 | with JarWriter(fileobj=new, optimize=self.optimize) as jar: |
michael@0 | 214 | for j in JarReader(fileobj=s): |
michael@0 | 215 | jar.add(j.filename, j) |
michael@0 | 216 | |
michael@0 | 217 | jar = JarReader(fileobj=new) |
michael@0 | 218 | files = [j for j in jar] |
michael@0 | 219 | |
michael@0 | 220 | self.assertEqual(files[0].filename, 'foo') |
michael@0 | 221 | self.assertFalse(files[0].compressed) |
michael@0 | 222 | self.assertEqual(files[0].read(), 'foo') |
michael@0 | 223 | |
michael@0 | 224 | self.assertEqual(files[1].filename, 'bar') |
michael@0 | 225 | self.assertTrue(files[1].compressed) |
michael@0 | 226 | self.assertEqual(files[1].read(), 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 227 | |
michael@0 | 228 | self.assertEqual(files[2].filename, 'baz/qux') |
michael@0 | 229 | self.assertTrue(files[2].compressed) |
michael@0 | 230 | self.assertEqual(files[2].read(), 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 231 | |
michael@0 | 232 | |
michael@0 | 233 | class TestOptimizeJar(TestJar): |
michael@0 | 234 | optimize = True |
michael@0 | 235 | |
michael@0 | 236 | |
michael@0 | 237 | class TestPreload(unittest.TestCase): |
michael@0 | 238 | def test_preload(self): |
michael@0 | 239 | s = MockDest() |
michael@0 | 240 | with JarWriter(fileobj=s) as jar: |
michael@0 | 241 | jar.add('foo', 'foo') |
michael@0 | 242 | jar.add('bar', 'abcdefghijklmnopqrstuvwxyz') |
michael@0 | 243 | jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 244 | |
michael@0 | 245 | jar = JarReader(fileobj=s) |
michael@0 | 246 | self.assertEqual(jar.last_preloaded, None) |
michael@0 | 247 | |
michael@0 | 248 | with JarWriter(fileobj=s) as jar: |
michael@0 | 249 | jar.add('foo', 'foo') |
michael@0 | 250 | jar.add('bar', 'abcdefghijklmnopqrstuvwxyz') |
michael@0 | 251 | jar.add('baz/qux', 'aaaaaaaaaaaaanopqrstuvwxyz') |
michael@0 | 252 | jar.preload(['baz/qux', 'bar']) |
michael@0 | 253 | |
michael@0 | 254 | jar = JarReader(fileobj=s) |
michael@0 | 255 | self.assertEqual(jar.last_preloaded, 'bar') |
michael@0 | 256 | files = [j for j in jar] |
michael@0 | 257 | |
michael@0 | 258 | self.assertEqual(files[0].filename, 'baz/qux') |
michael@0 | 259 | self.assertEqual(files[1].filename, 'bar') |
michael@0 | 260 | self.assertEqual(files[2].filename, 'foo') |
michael@0 | 261 | |
michael@0 | 262 | |
michael@0 | 263 | class TestJarLog(unittest.TestCase): |
michael@0 | 264 | def test_jarlog(self): |
michael@0 | 265 | base = 'file:' + pathname2url(os.path.abspath(os.curdir)) |
michael@0 | 266 | s = StringIO('\n'.join([ |
michael@0 | 267 | base + '/bar/baz.jar first', |
michael@0 | 268 | base + '/bar/baz.jar second', |
michael@0 | 269 | base + '/bar/baz.jar third', |
michael@0 | 270 | base + '/bar/baz.jar second', |
michael@0 | 271 | base + '/bar/baz.jar second', |
michael@0 | 272 | 'jar:' + base + '/qux.zip!/omni.ja stuff', |
michael@0 | 273 | base + '/bar/baz.jar first', |
michael@0 | 274 | 'jar:' + base + '/qux.zip!/omni.ja other/stuff', |
michael@0 | 275 | 'jar:' + base + '/qux.zip!/omni.ja stuff', |
michael@0 | 276 | base + '/bar/baz.jar third', |
michael@0 | 277 | 'jar:jar:' + base + '/qux.zip!/baz/baz.jar!/omni.ja nested/stuff', |
michael@0 | 278 | 'jar:jar:jar:' + base + '/qux.zip!/baz/baz.jar!/foo.zip!/omni.ja' + |
michael@0 | 279 | ' deeply/nested/stuff', |
michael@0 | 280 | ])) |
michael@0 | 281 | log = JarLog(fileobj=s) |
michael@0 | 282 | canonicalize = lambda p: \ |
michael@0 | 283 | mozpack.path.normsep(os.path.normcase(os.path.realpath(p))) |
michael@0 | 284 | baz_jar = canonicalize('bar/baz.jar') |
michael@0 | 285 | qux_zip = canonicalize('qux.zip') |
michael@0 | 286 | self.assertEqual(set(log.keys()), set([ |
michael@0 | 287 | baz_jar, |
michael@0 | 288 | (qux_zip, 'omni.ja'), |
michael@0 | 289 | (qux_zip, 'baz/baz.jar', 'omni.ja'), |
michael@0 | 290 | (qux_zip, 'baz/baz.jar', 'foo.zip', 'omni.ja'), |
michael@0 | 291 | ])) |
michael@0 | 292 | self.assertEqual(log[baz_jar], [ |
michael@0 | 293 | 'first', |
michael@0 | 294 | 'second', |
michael@0 | 295 | 'third', |
michael@0 | 296 | ]) |
michael@0 | 297 | self.assertEqual(log[(qux_zip, 'omni.ja')], [ |
michael@0 | 298 | 'stuff', |
michael@0 | 299 | 'other/stuff', |
michael@0 | 300 | ]) |
michael@0 | 301 | self.assertEqual(log[(qux_zip, 'baz/baz.jar', 'omni.ja')], |
michael@0 | 302 | ['nested/stuff']) |
michael@0 | 303 | self.assertEqual(log[(qux_zip, 'baz/baz.jar', 'foo.zip', |
michael@0 | 304 | 'omni.ja')], ['deeply/nested/stuff']) |
michael@0 | 305 | |
michael@0 | 306 | # The above tests also indirectly check the value returned by |
michael@0 | 307 | # JarLog.canonicalize for various jar: and file: urls, but |
michael@0 | 308 | # JarLog.canonicalize also supports plain paths. |
michael@0 | 309 | self.assertEqual(JarLog.canonicalize(os.path.abspath('bar/baz.jar')), |
michael@0 | 310 | baz_jar) |
michael@0 | 311 | self.assertEqual(JarLog.canonicalize('bar/baz.jar'), baz_jar) |
michael@0 | 312 | |
michael@0 | 313 | |
michael@0 | 314 | if __name__ == '__main__': |
michael@0 | 315 | mozunit.main() |