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