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