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 mozbuild.util import ensureParentDir |
michael@0 | 6 | |
michael@0 | 7 | from mozpack.errors import ErrorMessage |
michael@0 | 8 | from mozpack.files import ( |
michael@0 | 9 | AbsoluteSymlinkFile, |
michael@0 | 10 | DeflatedFile, |
michael@0 | 11 | Dest, |
michael@0 | 12 | ExistingFile, |
michael@0 | 13 | FileFinder, |
michael@0 | 14 | File, |
michael@0 | 15 | GeneratedFile, |
michael@0 | 16 | JarFinder, |
michael@0 | 17 | ManifestFile, |
michael@0 | 18 | MinifiedJavaScript, |
michael@0 | 19 | MinifiedProperties, |
michael@0 | 20 | PreprocessedFile, |
michael@0 | 21 | XPTFile, |
michael@0 | 22 | ) |
michael@0 | 23 | from mozpack.mozjar import ( |
michael@0 | 24 | JarReader, |
michael@0 | 25 | JarWriter, |
michael@0 | 26 | ) |
michael@0 | 27 | from mozpack.chrome.manifest import ( |
michael@0 | 28 | ManifestContent, |
michael@0 | 29 | ManifestResource, |
michael@0 | 30 | ManifestLocale, |
michael@0 | 31 | ManifestOverride, |
michael@0 | 32 | ) |
michael@0 | 33 | import unittest |
michael@0 | 34 | import mozfile |
michael@0 | 35 | import mozunit |
michael@0 | 36 | import os |
michael@0 | 37 | import random |
michael@0 | 38 | import string |
michael@0 | 39 | import sys |
michael@0 | 40 | import mozpack.path |
michael@0 | 41 | from tempfile import mkdtemp |
michael@0 | 42 | from io import BytesIO |
michael@0 | 43 | from xpt import Typelib |
michael@0 | 44 | |
michael@0 | 45 | |
michael@0 | 46 | class TestWithTmpDir(unittest.TestCase): |
michael@0 | 47 | def setUp(self): |
michael@0 | 48 | self.tmpdir = mkdtemp() |
michael@0 | 49 | |
michael@0 | 50 | self.symlink_supported = False |
michael@0 | 51 | |
michael@0 | 52 | if not hasattr(os, 'symlink'): |
michael@0 | 53 | return |
michael@0 | 54 | |
michael@0 | 55 | dummy_path = self.tmppath('dummy_file') |
michael@0 | 56 | with open(dummy_path, 'a'): |
michael@0 | 57 | pass |
michael@0 | 58 | |
michael@0 | 59 | try: |
michael@0 | 60 | os.symlink(dummy_path, self.tmppath('dummy_symlink')) |
michael@0 | 61 | os.remove(self.tmppath('dummy_symlink')) |
michael@0 | 62 | except EnvironmentError: |
michael@0 | 63 | pass |
michael@0 | 64 | finally: |
michael@0 | 65 | os.remove(dummy_path) |
michael@0 | 66 | |
michael@0 | 67 | self.symlink_supported = True |
michael@0 | 68 | |
michael@0 | 69 | |
michael@0 | 70 | def tearDown(self): |
michael@0 | 71 | mozfile.rmtree(self.tmpdir) |
michael@0 | 72 | |
michael@0 | 73 | def tmppath(self, relpath): |
michael@0 | 74 | return os.path.normpath(os.path.join(self.tmpdir, relpath)) |
michael@0 | 75 | |
michael@0 | 76 | |
michael@0 | 77 | class MockDest(BytesIO, Dest): |
michael@0 | 78 | def __init__(self): |
michael@0 | 79 | BytesIO.__init__(self) |
michael@0 | 80 | self.mode = None |
michael@0 | 81 | |
michael@0 | 82 | def read(self, length=-1): |
michael@0 | 83 | if self.mode != 'r': |
michael@0 | 84 | self.seek(0) |
michael@0 | 85 | self.mode = 'r' |
michael@0 | 86 | return BytesIO.read(self, length) |
michael@0 | 87 | |
michael@0 | 88 | def write(self, data): |
michael@0 | 89 | if self.mode != 'w': |
michael@0 | 90 | self.seek(0) |
michael@0 | 91 | self.truncate(0) |
michael@0 | 92 | self.mode = 'w' |
michael@0 | 93 | return BytesIO.write(self, data) |
michael@0 | 94 | |
michael@0 | 95 | def exists(self): |
michael@0 | 96 | return True |
michael@0 | 97 | |
michael@0 | 98 | def close(self): |
michael@0 | 99 | if self.mode: |
michael@0 | 100 | self.mode = None |
michael@0 | 101 | |
michael@0 | 102 | |
michael@0 | 103 | class DestNoWrite(Dest): |
michael@0 | 104 | def write(self, data): |
michael@0 | 105 | raise RuntimeError |
michael@0 | 106 | |
michael@0 | 107 | |
michael@0 | 108 | class TestDest(TestWithTmpDir): |
michael@0 | 109 | def test_dest(self): |
michael@0 | 110 | dest = Dest(self.tmppath('dest')) |
michael@0 | 111 | self.assertFalse(dest.exists()) |
michael@0 | 112 | dest.write('foo') |
michael@0 | 113 | self.assertTrue(dest.exists()) |
michael@0 | 114 | dest.write('foo') |
michael@0 | 115 | self.assertEqual(dest.read(4), 'foof') |
michael@0 | 116 | self.assertEqual(dest.read(), 'oo') |
michael@0 | 117 | self.assertEqual(dest.read(), '') |
michael@0 | 118 | dest.write('bar') |
michael@0 | 119 | self.assertEqual(dest.read(4), 'bar') |
michael@0 | 120 | dest.close() |
michael@0 | 121 | self.assertEqual(dest.read(), 'bar') |
michael@0 | 122 | dest.write('foo') |
michael@0 | 123 | dest.close() |
michael@0 | 124 | dest.write('qux') |
michael@0 | 125 | self.assertEqual(dest.read(), 'qux') |
michael@0 | 126 | |
michael@0 | 127 | rand = ''.join(random.choice(string.letters) for i in xrange(131597)) |
michael@0 | 128 | samples = [ |
michael@0 | 129 | '', |
michael@0 | 130 | 'test', |
michael@0 | 131 | 'fooo', |
michael@0 | 132 | 'same', |
michael@0 | 133 | 'same', |
michael@0 | 134 | 'Different and longer', |
michael@0 | 135 | rand, |
michael@0 | 136 | rand, |
michael@0 | 137 | rand[:-1] + '_', |
michael@0 | 138 | 'test' |
michael@0 | 139 | ] |
michael@0 | 140 | |
michael@0 | 141 | |
michael@0 | 142 | class TestFile(TestWithTmpDir): |
michael@0 | 143 | def test_file(self): |
michael@0 | 144 | ''' |
michael@0 | 145 | Check that File.copy yields the proper content in the destination file |
michael@0 | 146 | in all situations that trigger different code paths: |
michael@0 | 147 | - different content |
michael@0 | 148 | - different content of the same size |
michael@0 | 149 | - same content |
michael@0 | 150 | - long content |
michael@0 | 151 | ''' |
michael@0 | 152 | src = self.tmppath('src') |
michael@0 | 153 | dest = self.tmppath('dest') |
michael@0 | 154 | |
michael@0 | 155 | for content in samples: |
michael@0 | 156 | with open(src, 'wb') as tmp: |
michael@0 | 157 | tmp.write(content) |
michael@0 | 158 | # Ensure the destination file, when it exists, is older than the |
michael@0 | 159 | # source |
michael@0 | 160 | if os.path.exists(dest): |
michael@0 | 161 | time = os.path.getmtime(src) - 1 |
michael@0 | 162 | os.utime(dest, (time, time)) |
michael@0 | 163 | f = File(src) |
michael@0 | 164 | f.copy(dest) |
michael@0 | 165 | self.assertEqual(content, open(dest, 'rb').read()) |
michael@0 | 166 | self.assertEqual(content, f.open().read()) |
michael@0 | 167 | self.assertEqual(content, f.open().read()) |
michael@0 | 168 | |
michael@0 | 169 | def test_file_dest(self): |
michael@0 | 170 | ''' |
michael@0 | 171 | Similar to test_file, but for a destination object instead of |
michael@0 | 172 | a destination file. This ensures the destination object is being |
michael@0 | 173 | used properly by File.copy, ensuring that other subclasses of Dest |
michael@0 | 174 | will work. |
michael@0 | 175 | ''' |
michael@0 | 176 | src = self.tmppath('src') |
michael@0 | 177 | dest = MockDest() |
michael@0 | 178 | |
michael@0 | 179 | for content in samples: |
michael@0 | 180 | with open(src, 'wb') as tmp: |
michael@0 | 181 | tmp.write(content) |
michael@0 | 182 | f = File(src) |
michael@0 | 183 | f.copy(dest) |
michael@0 | 184 | self.assertEqual(content, dest.getvalue()) |
michael@0 | 185 | |
michael@0 | 186 | def test_file_open(self): |
michael@0 | 187 | ''' |
michael@0 | 188 | Test whether File.open returns an appropriately reset file object. |
michael@0 | 189 | ''' |
michael@0 | 190 | src = self.tmppath('src') |
michael@0 | 191 | content = ''.join(samples) |
michael@0 | 192 | with open(src, 'wb') as tmp: |
michael@0 | 193 | tmp.write(content) |
michael@0 | 194 | |
michael@0 | 195 | f = File(src) |
michael@0 | 196 | self.assertEqual(content[:42], f.open().read(42)) |
michael@0 | 197 | self.assertEqual(content, f.open().read()) |
michael@0 | 198 | |
michael@0 | 199 | def test_file_no_write(self): |
michael@0 | 200 | ''' |
michael@0 | 201 | Test various conditions where File.copy is expected not to write |
michael@0 | 202 | in the destination file. |
michael@0 | 203 | ''' |
michael@0 | 204 | src = self.tmppath('src') |
michael@0 | 205 | dest = self.tmppath('dest') |
michael@0 | 206 | |
michael@0 | 207 | with open(src, 'wb') as tmp: |
michael@0 | 208 | tmp.write('test') |
michael@0 | 209 | |
michael@0 | 210 | # Initial copy |
michael@0 | 211 | f = File(src) |
michael@0 | 212 | f.copy(dest) |
michael@0 | 213 | |
michael@0 | 214 | # Ensure subsequent copies won't trigger writes |
michael@0 | 215 | f.copy(DestNoWrite(dest)) |
michael@0 | 216 | self.assertEqual('test', open(dest, 'rb').read()) |
michael@0 | 217 | |
michael@0 | 218 | # When the source file is newer, but with the same content, no copy |
michael@0 | 219 | # should occur |
michael@0 | 220 | time = os.path.getmtime(src) - 1 |
michael@0 | 221 | os.utime(dest, (time, time)) |
michael@0 | 222 | f.copy(DestNoWrite(dest)) |
michael@0 | 223 | self.assertEqual('test', open(dest, 'rb').read()) |
michael@0 | 224 | |
michael@0 | 225 | # When the source file is older than the destination file, even with |
michael@0 | 226 | # different content, no copy should occur. |
michael@0 | 227 | with open(src, 'wb') as tmp: |
michael@0 | 228 | tmp.write('fooo') |
michael@0 | 229 | time = os.path.getmtime(dest) - 1 |
michael@0 | 230 | os.utime(src, (time, time)) |
michael@0 | 231 | f.copy(DestNoWrite(dest)) |
michael@0 | 232 | self.assertEqual('test', open(dest, 'rb').read()) |
michael@0 | 233 | |
michael@0 | 234 | # Double check that under conditions where a copy occurs, we would get |
michael@0 | 235 | # an exception. |
michael@0 | 236 | time = os.path.getmtime(src) - 1 |
michael@0 | 237 | os.utime(dest, (time, time)) |
michael@0 | 238 | self.assertRaises(RuntimeError, f.copy, DestNoWrite(dest)) |
michael@0 | 239 | |
michael@0 | 240 | # skip_if_older=False is expected to force a copy in this situation. |
michael@0 | 241 | f.copy(dest, skip_if_older=False) |
michael@0 | 242 | self.assertEqual('fooo', open(dest, 'rb').read()) |
michael@0 | 243 | |
michael@0 | 244 | |
michael@0 | 245 | class TestAbsoluteSymlinkFile(TestWithTmpDir): |
michael@0 | 246 | def test_absolute_relative(self): |
michael@0 | 247 | AbsoluteSymlinkFile('/foo') |
michael@0 | 248 | |
michael@0 | 249 | with self.assertRaisesRegexp(ValueError, 'Symlink target not absolute'): |
michael@0 | 250 | AbsoluteSymlinkFile('./foo') |
michael@0 | 251 | |
michael@0 | 252 | def test_symlink_file(self): |
michael@0 | 253 | source = self.tmppath('test_path') |
michael@0 | 254 | with open(source, 'wt') as fh: |
michael@0 | 255 | fh.write('Hello world') |
michael@0 | 256 | |
michael@0 | 257 | s = AbsoluteSymlinkFile(source) |
michael@0 | 258 | dest = self.tmppath('symlink') |
michael@0 | 259 | self.assertTrue(s.copy(dest)) |
michael@0 | 260 | |
michael@0 | 261 | if self.symlink_supported: |
michael@0 | 262 | self.assertTrue(os.path.islink(dest)) |
michael@0 | 263 | link = os.readlink(dest) |
michael@0 | 264 | self.assertEqual(link, source) |
michael@0 | 265 | else: |
michael@0 | 266 | self.assertTrue(os.path.isfile(dest)) |
michael@0 | 267 | content = open(dest).read() |
michael@0 | 268 | self.assertEqual(content, 'Hello world') |
michael@0 | 269 | |
michael@0 | 270 | def test_replace_file_with_symlink(self): |
michael@0 | 271 | # If symlinks are supported, an existing file should be replaced by a |
michael@0 | 272 | # symlink. |
michael@0 | 273 | source = self.tmppath('test_path') |
michael@0 | 274 | with open(source, 'wt') as fh: |
michael@0 | 275 | fh.write('source') |
michael@0 | 276 | |
michael@0 | 277 | dest = self.tmppath('dest') |
michael@0 | 278 | with open(dest, 'a'): |
michael@0 | 279 | pass |
michael@0 | 280 | |
michael@0 | 281 | s = AbsoluteSymlinkFile(source) |
michael@0 | 282 | s.copy(dest, skip_if_older=False) |
michael@0 | 283 | |
michael@0 | 284 | if self.symlink_supported: |
michael@0 | 285 | self.assertTrue(os.path.islink(dest)) |
michael@0 | 286 | link = os.readlink(dest) |
michael@0 | 287 | self.assertEqual(link, source) |
michael@0 | 288 | else: |
michael@0 | 289 | self.assertTrue(os.path.isfile(dest)) |
michael@0 | 290 | content = open(dest).read() |
michael@0 | 291 | self.assertEqual(content, 'source') |
michael@0 | 292 | |
michael@0 | 293 | def test_replace_symlink(self): |
michael@0 | 294 | if not self.symlink_supported: |
michael@0 | 295 | return |
michael@0 | 296 | |
michael@0 | 297 | source = self.tmppath('source') |
michael@0 | 298 | with open(source, 'a'): |
michael@0 | 299 | pass |
michael@0 | 300 | |
michael@0 | 301 | dest = self.tmppath('dest') |
michael@0 | 302 | |
michael@0 | 303 | os.symlink(self.tmppath('bad'), dest) |
michael@0 | 304 | self.assertTrue(os.path.islink(dest)) |
michael@0 | 305 | |
michael@0 | 306 | s = AbsoluteSymlinkFile(source) |
michael@0 | 307 | self.assertTrue(s.copy(dest)) |
michael@0 | 308 | |
michael@0 | 309 | self.assertTrue(os.path.islink(dest)) |
michael@0 | 310 | link = os.readlink(dest) |
michael@0 | 311 | self.assertEqual(link, source) |
michael@0 | 312 | |
michael@0 | 313 | def test_noop(self): |
michael@0 | 314 | if not hasattr(os, 'symlink'): |
michael@0 | 315 | return |
michael@0 | 316 | |
michael@0 | 317 | source = self.tmppath('source') |
michael@0 | 318 | dest = self.tmppath('dest') |
michael@0 | 319 | |
michael@0 | 320 | with open(source, 'a'): |
michael@0 | 321 | pass |
michael@0 | 322 | |
michael@0 | 323 | os.symlink(source, dest) |
michael@0 | 324 | link = os.readlink(dest) |
michael@0 | 325 | self.assertEqual(link, source) |
michael@0 | 326 | |
michael@0 | 327 | s = AbsoluteSymlinkFile(source) |
michael@0 | 328 | self.assertFalse(s.copy(dest)) |
michael@0 | 329 | |
michael@0 | 330 | link = os.readlink(dest) |
michael@0 | 331 | self.assertEqual(link, source) |
michael@0 | 332 | |
michael@0 | 333 | class TestPreprocessedFile(TestWithTmpDir): |
michael@0 | 334 | def test_preprocess(self): |
michael@0 | 335 | ''' |
michael@0 | 336 | Test that copying the file invokes the preprocessor |
michael@0 | 337 | ''' |
michael@0 | 338 | src = self.tmppath('src') |
michael@0 | 339 | dest = self.tmppath('dest') |
michael@0 | 340 | |
michael@0 | 341 | with open(src, 'wb') as tmp: |
michael@0 | 342 | tmp.write('#ifdef FOO\ntest\n#endif') |
michael@0 | 343 | |
michael@0 | 344 | f = PreprocessedFile(src, depfile_path=None, marker='#', defines={'FOO': True}) |
michael@0 | 345 | self.assertTrue(f.copy(dest)) |
michael@0 | 346 | |
michael@0 | 347 | self.assertEqual('test\n', open(dest, 'rb').read()) |
michael@0 | 348 | |
michael@0 | 349 | def test_preprocess_file_no_write(self): |
michael@0 | 350 | ''' |
michael@0 | 351 | Test various conditions where PreprocessedFile.copy is expected not to |
michael@0 | 352 | write in the destination file. |
michael@0 | 353 | ''' |
michael@0 | 354 | src = self.tmppath('src') |
michael@0 | 355 | dest = self.tmppath('dest') |
michael@0 | 356 | depfile = self.tmppath('depfile') |
michael@0 | 357 | |
michael@0 | 358 | with open(src, 'wb') as tmp: |
michael@0 | 359 | tmp.write('#ifdef FOO\ntest\n#endif') |
michael@0 | 360 | |
michael@0 | 361 | # Initial copy |
michael@0 | 362 | f = PreprocessedFile(src, depfile_path=depfile, marker='#', defines={'FOO': True}) |
michael@0 | 363 | self.assertTrue(f.copy(dest)) |
michael@0 | 364 | |
michael@0 | 365 | # Ensure subsequent copies won't trigger writes |
michael@0 | 366 | self.assertFalse(f.copy(DestNoWrite(dest))) |
michael@0 | 367 | self.assertEqual('test\n', open(dest, 'rb').read()) |
michael@0 | 368 | |
michael@0 | 369 | # When the source file is older than the destination file, even with |
michael@0 | 370 | # different content, no copy should occur. |
michael@0 | 371 | with open(src, 'wb') as tmp: |
michael@0 | 372 | tmp.write('#ifdef FOO\nfooo\n#endif') |
michael@0 | 373 | time = os.path.getmtime(dest) - 1 |
michael@0 | 374 | os.utime(src, (time, time)) |
michael@0 | 375 | self.assertFalse(f.copy(DestNoWrite(dest))) |
michael@0 | 376 | self.assertEqual('test\n', open(dest, 'rb').read()) |
michael@0 | 377 | |
michael@0 | 378 | # skip_if_older=False is expected to force a copy in this situation. |
michael@0 | 379 | self.assertTrue(f.copy(dest, skip_if_older=False)) |
michael@0 | 380 | self.assertEqual('fooo\n', open(dest, 'rb').read()) |
michael@0 | 381 | |
michael@0 | 382 | def test_preprocess_file_dependencies(self): |
michael@0 | 383 | ''' |
michael@0 | 384 | Test that the preprocess runs if the dependencies of the source change |
michael@0 | 385 | ''' |
michael@0 | 386 | src = self.tmppath('src') |
michael@0 | 387 | dest = self.tmppath('dest') |
michael@0 | 388 | incl = self.tmppath('incl') |
michael@0 | 389 | deps = self.tmppath('src.pp') |
michael@0 | 390 | |
michael@0 | 391 | with open(src, 'wb') as tmp: |
michael@0 | 392 | tmp.write('#ifdef FOO\ntest\n#endif') |
michael@0 | 393 | |
michael@0 | 394 | with open(incl, 'wb') as tmp: |
michael@0 | 395 | tmp.write('foo bar') |
michael@0 | 396 | |
michael@0 | 397 | # Initial copy |
michael@0 | 398 | f = PreprocessedFile(src, depfile_path=deps, marker='#', defines={'FOO': True}) |
michael@0 | 399 | self.assertTrue(f.copy(dest)) |
michael@0 | 400 | |
michael@0 | 401 | # Update the source so it #includes the include file. |
michael@0 | 402 | with open(src, 'wb') as tmp: |
michael@0 | 403 | tmp.write('#include incl\n') |
michael@0 | 404 | time = os.path.getmtime(dest) + 1 |
michael@0 | 405 | os.utime(src, (time, time)) |
michael@0 | 406 | self.assertTrue(f.copy(dest)) |
michael@0 | 407 | self.assertEqual('foo bar', open(dest, 'rb').read()) |
michael@0 | 408 | |
michael@0 | 409 | # If one of the dependencies changes, the file should be updated. The |
michael@0 | 410 | # mtime of the dependency is set after the destination file, to avoid |
michael@0 | 411 | # both files having the same time. |
michael@0 | 412 | with open(incl, 'wb') as tmp: |
michael@0 | 413 | tmp.write('quux') |
michael@0 | 414 | time = os.path.getmtime(dest) + 1 |
michael@0 | 415 | os.utime(incl, (time, time)) |
michael@0 | 416 | self.assertTrue(f.copy(dest)) |
michael@0 | 417 | self.assertEqual('quux', open(dest, 'rb').read()) |
michael@0 | 418 | |
michael@0 | 419 | # Perform one final copy to confirm that we don't run the preprocessor |
michael@0 | 420 | # again. We update the mtime of the destination so it's newer than the |
michael@0 | 421 | # input files. This would "just work" if we weren't changing |
michael@0 | 422 | time = os.path.getmtime(incl) + 1 |
michael@0 | 423 | os.utime(dest, (time, time)) |
michael@0 | 424 | self.assertFalse(f.copy(DestNoWrite(dest))) |
michael@0 | 425 | |
michael@0 | 426 | def test_replace_symlink(self): |
michael@0 | 427 | ''' |
michael@0 | 428 | Test that if the destination exists, and is a symlink, the target of |
michael@0 | 429 | the symlink is not overwritten by the preprocessor output. |
michael@0 | 430 | ''' |
michael@0 | 431 | if not self.symlink_supported: |
michael@0 | 432 | return |
michael@0 | 433 | |
michael@0 | 434 | source = self.tmppath('source') |
michael@0 | 435 | dest = self.tmppath('dest') |
michael@0 | 436 | pp_source = self.tmppath('pp_in') |
michael@0 | 437 | deps = self.tmppath('deps') |
michael@0 | 438 | |
michael@0 | 439 | with open(source, 'a'): |
michael@0 | 440 | pass |
michael@0 | 441 | |
michael@0 | 442 | os.symlink(source, dest) |
michael@0 | 443 | self.assertTrue(os.path.islink(dest)) |
michael@0 | 444 | |
michael@0 | 445 | with open(pp_source, 'wb') as tmp: |
michael@0 | 446 | tmp.write('#define FOO\nPREPROCESSED') |
michael@0 | 447 | |
michael@0 | 448 | f = PreprocessedFile(pp_source, depfile_path=deps, marker='#', |
michael@0 | 449 | defines={'FOO': True}) |
michael@0 | 450 | self.assertTrue(f.copy(dest)) |
michael@0 | 451 | |
michael@0 | 452 | self.assertEqual('PREPROCESSED', open(dest, 'rb').read()) |
michael@0 | 453 | self.assertFalse(os.path.islink(dest)) |
michael@0 | 454 | self.assertEqual('', open(source, 'rb').read()) |
michael@0 | 455 | |
michael@0 | 456 | class TestExistingFile(TestWithTmpDir): |
michael@0 | 457 | def test_required_missing_dest(self): |
michael@0 | 458 | with self.assertRaisesRegexp(ErrorMessage, 'Required existing file'): |
michael@0 | 459 | f = ExistingFile(required=True) |
michael@0 | 460 | f.copy(self.tmppath('dest')) |
michael@0 | 461 | |
michael@0 | 462 | def test_required_existing_dest(self): |
michael@0 | 463 | p = self.tmppath('dest') |
michael@0 | 464 | with open(p, 'a'): |
michael@0 | 465 | pass |
michael@0 | 466 | |
michael@0 | 467 | f = ExistingFile(required=True) |
michael@0 | 468 | f.copy(p) |
michael@0 | 469 | |
michael@0 | 470 | def test_optional_missing_dest(self): |
michael@0 | 471 | f = ExistingFile(required=False) |
michael@0 | 472 | f.copy(self.tmppath('dest')) |
michael@0 | 473 | |
michael@0 | 474 | def test_optional_existing_dest(self): |
michael@0 | 475 | p = self.tmppath('dest') |
michael@0 | 476 | with open(p, 'a'): |
michael@0 | 477 | pass |
michael@0 | 478 | |
michael@0 | 479 | f = ExistingFile(required=False) |
michael@0 | 480 | f.copy(p) |
michael@0 | 481 | |
michael@0 | 482 | |
michael@0 | 483 | class TestGeneratedFile(TestWithTmpDir): |
michael@0 | 484 | def test_generated_file(self): |
michael@0 | 485 | ''' |
michael@0 | 486 | Check that GeneratedFile.copy yields the proper content in the |
michael@0 | 487 | destination file in all situations that trigger different code paths |
michael@0 | 488 | (see TestFile.test_file) |
michael@0 | 489 | ''' |
michael@0 | 490 | dest = self.tmppath('dest') |
michael@0 | 491 | |
michael@0 | 492 | for content in samples: |
michael@0 | 493 | f = GeneratedFile(content) |
michael@0 | 494 | f.copy(dest) |
michael@0 | 495 | self.assertEqual(content, open(dest, 'rb').read()) |
michael@0 | 496 | |
michael@0 | 497 | def test_generated_file_open(self): |
michael@0 | 498 | ''' |
michael@0 | 499 | Test whether GeneratedFile.open returns an appropriately reset file |
michael@0 | 500 | object. |
michael@0 | 501 | ''' |
michael@0 | 502 | content = ''.join(samples) |
michael@0 | 503 | f = GeneratedFile(content) |
michael@0 | 504 | self.assertEqual(content[:42], f.open().read(42)) |
michael@0 | 505 | self.assertEqual(content, f.open().read()) |
michael@0 | 506 | |
michael@0 | 507 | def test_generated_file_no_write(self): |
michael@0 | 508 | ''' |
michael@0 | 509 | Test various conditions where GeneratedFile.copy is expected not to |
michael@0 | 510 | write in the destination file. |
michael@0 | 511 | ''' |
michael@0 | 512 | dest = self.tmppath('dest') |
michael@0 | 513 | |
michael@0 | 514 | # Initial copy |
michael@0 | 515 | f = GeneratedFile('test') |
michael@0 | 516 | f.copy(dest) |
michael@0 | 517 | |
michael@0 | 518 | # Ensure subsequent copies won't trigger writes |
michael@0 | 519 | f.copy(DestNoWrite(dest)) |
michael@0 | 520 | self.assertEqual('test', open(dest, 'rb').read()) |
michael@0 | 521 | |
michael@0 | 522 | # When using a new instance with the same content, no copy should occur |
michael@0 | 523 | f = GeneratedFile('test') |
michael@0 | 524 | f.copy(DestNoWrite(dest)) |
michael@0 | 525 | self.assertEqual('test', open(dest, 'rb').read()) |
michael@0 | 526 | |
michael@0 | 527 | # Double check that under conditions where a copy occurs, we would get |
michael@0 | 528 | # an exception. |
michael@0 | 529 | f = GeneratedFile('fooo') |
michael@0 | 530 | self.assertRaises(RuntimeError, f.copy, DestNoWrite(dest)) |
michael@0 | 531 | |
michael@0 | 532 | |
michael@0 | 533 | class TestDeflatedFile(TestWithTmpDir): |
michael@0 | 534 | def test_deflated_file(self): |
michael@0 | 535 | ''' |
michael@0 | 536 | Check that DeflatedFile.copy yields the proper content in the |
michael@0 | 537 | destination file in all situations that trigger different code paths |
michael@0 | 538 | (see TestFile.test_file) |
michael@0 | 539 | ''' |
michael@0 | 540 | src = self.tmppath('src.jar') |
michael@0 | 541 | dest = self.tmppath('dest') |
michael@0 | 542 | |
michael@0 | 543 | contents = {} |
michael@0 | 544 | with JarWriter(src) as jar: |
michael@0 | 545 | for content in samples: |
michael@0 | 546 | name = ''.join(random.choice(string.letters) |
michael@0 | 547 | for i in xrange(8)) |
michael@0 | 548 | jar.add(name, content, compress=True) |
michael@0 | 549 | contents[name] = content |
michael@0 | 550 | |
michael@0 | 551 | for j in JarReader(src): |
michael@0 | 552 | f = DeflatedFile(j) |
michael@0 | 553 | f.copy(dest) |
michael@0 | 554 | self.assertEqual(contents[j.filename], open(dest, 'rb').read()) |
michael@0 | 555 | |
michael@0 | 556 | def test_deflated_file_open(self): |
michael@0 | 557 | ''' |
michael@0 | 558 | Test whether DeflatedFile.open returns an appropriately reset file |
michael@0 | 559 | object. |
michael@0 | 560 | ''' |
michael@0 | 561 | src = self.tmppath('src.jar') |
michael@0 | 562 | content = ''.join(samples) |
michael@0 | 563 | with JarWriter(src) as jar: |
michael@0 | 564 | jar.add('content', content) |
michael@0 | 565 | |
michael@0 | 566 | f = DeflatedFile(JarReader(src)['content']) |
michael@0 | 567 | self.assertEqual(content[:42], f.open().read(42)) |
michael@0 | 568 | self.assertEqual(content, f.open().read()) |
michael@0 | 569 | |
michael@0 | 570 | def test_deflated_file_no_write(self): |
michael@0 | 571 | ''' |
michael@0 | 572 | Test various conditions where DeflatedFile.copy is expected not to |
michael@0 | 573 | write in the destination file. |
michael@0 | 574 | ''' |
michael@0 | 575 | src = self.tmppath('src.jar') |
michael@0 | 576 | dest = self.tmppath('dest') |
michael@0 | 577 | |
michael@0 | 578 | with JarWriter(src) as jar: |
michael@0 | 579 | jar.add('test', 'test') |
michael@0 | 580 | jar.add('test2', 'test') |
michael@0 | 581 | jar.add('fooo', 'fooo') |
michael@0 | 582 | |
michael@0 | 583 | jar = JarReader(src) |
michael@0 | 584 | # Initial copy |
michael@0 | 585 | f = DeflatedFile(jar['test']) |
michael@0 | 586 | f.copy(dest) |
michael@0 | 587 | |
michael@0 | 588 | # Ensure subsequent copies won't trigger writes |
michael@0 | 589 | f.copy(DestNoWrite(dest)) |
michael@0 | 590 | self.assertEqual('test', open(dest, 'rb').read()) |
michael@0 | 591 | |
michael@0 | 592 | # When using a different file with the same content, no copy should |
michael@0 | 593 | # occur |
michael@0 | 594 | f = DeflatedFile(jar['test2']) |
michael@0 | 595 | f.copy(DestNoWrite(dest)) |
michael@0 | 596 | self.assertEqual('test', open(dest, 'rb').read()) |
michael@0 | 597 | |
michael@0 | 598 | # Double check that under conditions where a copy occurs, we would get |
michael@0 | 599 | # an exception. |
michael@0 | 600 | f = DeflatedFile(jar['fooo']) |
michael@0 | 601 | self.assertRaises(RuntimeError, f.copy, DestNoWrite(dest)) |
michael@0 | 602 | |
michael@0 | 603 | |
michael@0 | 604 | class TestManifestFile(TestWithTmpDir): |
michael@0 | 605 | def test_manifest_file(self): |
michael@0 | 606 | f = ManifestFile('chrome') |
michael@0 | 607 | f.add(ManifestContent('chrome', 'global', 'toolkit/content/global/')) |
michael@0 | 608 | f.add(ManifestResource('chrome', 'gre-resources', 'toolkit/res/')) |
michael@0 | 609 | f.add(ManifestResource('chrome/pdfjs', 'pdfjs', './')) |
michael@0 | 610 | f.add(ManifestContent('chrome/pdfjs', 'pdfjs', 'pdfjs')) |
michael@0 | 611 | f.add(ManifestLocale('chrome', 'browser', 'en-US', |
michael@0 | 612 | 'en-US/locale/browser/')) |
michael@0 | 613 | |
michael@0 | 614 | f.copy(self.tmppath('chrome.manifest')) |
michael@0 | 615 | self.assertEqual(open(self.tmppath('chrome.manifest')).readlines(), [ |
michael@0 | 616 | 'content global toolkit/content/global/\n', |
michael@0 | 617 | 'resource gre-resources toolkit/res/\n', |
michael@0 | 618 | 'resource pdfjs pdfjs/\n', |
michael@0 | 619 | 'content pdfjs pdfjs/pdfjs\n', |
michael@0 | 620 | 'locale browser en-US en-US/locale/browser/\n', |
michael@0 | 621 | ]) |
michael@0 | 622 | |
michael@0 | 623 | self.assertRaises( |
michael@0 | 624 | ValueError, |
michael@0 | 625 | f.remove, |
michael@0 | 626 | ManifestContent('', 'global', 'toolkit/content/global/') |
michael@0 | 627 | ) |
michael@0 | 628 | self.assertRaises( |
michael@0 | 629 | ValueError, |
michael@0 | 630 | f.remove, |
michael@0 | 631 | ManifestOverride('chrome', 'chrome://global/locale/netError.dtd', |
michael@0 | 632 | 'chrome://browser/locale/netError.dtd') |
michael@0 | 633 | ) |
michael@0 | 634 | |
michael@0 | 635 | f.remove(ManifestContent('chrome', 'global', |
michael@0 | 636 | 'toolkit/content/global/')) |
michael@0 | 637 | self.assertRaises( |
michael@0 | 638 | ValueError, |
michael@0 | 639 | f.remove, |
michael@0 | 640 | ManifestContent('chrome', 'global', 'toolkit/content/global/') |
michael@0 | 641 | ) |
michael@0 | 642 | |
michael@0 | 643 | f.copy(self.tmppath('chrome.manifest')) |
michael@0 | 644 | content = open(self.tmppath('chrome.manifest')).read() |
michael@0 | 645 | self.assertEqual(content[:42], f.open().read(42)) |
michael@0 | 646 | self.assertEqual(content, f.open().read()) |
michael@0 | 647 | |
michael@0 | 648 | # Compiled typelib for the following IDL: |
michael@0 | 649 | # interface foo; |
michael@0 | 650 | # [uuid(5f70da76-519c-4858-b71e-e3c92333e2d6)] |
michael@0 | 651 | # interface bar { |
michael@0 | 652 | # void bar(in foo f); |
michael@0 | 653 | # }; |
michael@0 | 654 | bar_xpt = GeneratedFile( |
michael@0 | 655 | b'\x58\x50\x43\x4F\x4D\x0A\x54\x79\x70\x65\x4C\x69\x62\x0D\x0A\x1A' + |
michael@0 | 656 | b'\x01\x02\x00\x02\x00\x00\x00\x7B\x00\x00\x00\x24\x00\x00\x00\x5C' + |
michael@0 | 657 | b'\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + |
michael@0 | 658 | b'\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x5F' + |
michael@0 | 659 | b'\x70\xDA\x76\x51\x9C\x48\x58\xB7\x1E\xE3\xC9\x23\x33\xE2\xD6\x00' + |
michael@0 | 660 | b'\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x0D\x00\x66\x6F\x6F\x00' + |
michael@0 | 661 | b'\x62\x61\x72\x00\x62\x61\x72\x00\x00\x00\x00\x01\x00\x00\x00\x00' + |
michael@0 | 662 | b'\x09\x01\x80\x92\x00\x01\x80\x06\x00\x00\x00' |
michael@0 | 663 | ) |
michael@0 | 664 | |
michael@0 | 665 | # Compiled typelib for the following IDL: |
michael@0 | 666 | # [uuid(3271bebc-927e-4bef-935e-44e0aaf3c1e5)] |
michael@0 | 667 | # interface foo { |
michael@0 | 668 | # void foo(); |
michael@0 | 669 | # }; |
michael@0 | 670 | foo_xpt = GeneratedFile( |
michael@0 | 671 | b'\x58\x50\x43\x4F\x4D\x0A\x54\x79\x70\x65\x4C\x69\x62\x0D\x0A\x1A' + |
michael@0 | 672 | b'\x01\x02\x00\x01\x00\x00\x00\x57\x00\x00\x00\x24\x00\x00\x00\x40' + |
michael@0 | 673 | b'\x80\x00\x00\x32\x71\xBE\xBC\x92\x7E\x4B\xEF\x93\x5E\x44\xE0\xAA' + |
michael@0 | 674 | b'\xF3\xC1\xE5\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x09\x00' + |
michael@0 | 675 | b'\x66\x6F\x6F\x00\x66\x6F\x6F\x00\x00\x00\x00\x01\x00\x00\x00\x00' + |
michael@0 | 676 | b'\x05\x00\x80\x06\x00\x00\x00' |
michael@0 | 677 | ) |
michael@0 | 678 | |
michael@0 | 679 | # Compiled typelib for the following IDL: |
michael@0 | 680 | # [uuid(7057f2aa-fdc2-4559-abde-08d939f7e80d)] |
michael@0 | 681 | # interface foo { |
michael@0 | 682 | # void foo(); |
michael@0 | 683 | # }; |
michael@0 | 684 | foo2_xpt = GeneratedFile( |
michael@0 | 685 | b'\x58\x50\x43\x4F\x4D\x0A\x54\x79\x70\x65\x4C\x69\x62\x0D\x0A\x1A' + |
michael@0 | 686 | b'\x01\x02\x00\x01\x00\x00\x00\x57\x00\x00\x00\x24\x00\x00\x00\x40' + |
michael@0 | 687 | b'\x80\x00\x00\x70\x57\xF2\xAA\xFD\xC2\x45\x59\xAB\xDE\x08\xD9\x39' + |
michael@0 | 688 | b'\xF7\xE8\x0D\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x09\x00' + |
michael@0 | 689 | b'\x66\x6F\x6F\x00\x66\x6F\x6F\x00\x00\x00\x00\x01\x00\x00\x00\x00' + |
michael@0 | 690 | b'\x05\x00\x80\x06\x00\x00\x00' |
michael@0 | 691 | ) |
michael@0 | 692 | |
michael@0 | 693 | |
michael@0 | 694 | def read_interfaces(file): |
michael@0 | 695 | return dict((i.name, i) for i in Typelib.read(file).interfaces) |
michael@0 | 696 | |
michael@0 | 697 | |
michael@0 | 698 | class TestXPTFile(TestWithTmpDir): |
michael@0 | 699 | def test_xpt_file(self): |
michael@0 | 700 | x = XPTFile() |
michael@0 | 701 | x.add(foo_xpt) |
michael@0 | 702 | x.add(bar_xpt) |
michael@0 | 703 | x.copy(self.tmppath('interfaces.xpt')) |
michael@0 | 704 | |
michael@0 | 705 | foo = read_interfaces(foo_xpt.open()) |
michael@0 | 706 | foo2 = read_interfaces(foo2_xpt.open()) |
michael@0 | 707 | bar = read_interfaces(bar_xpt.open()) |
michael@0 | 708 | linked = read_interfaces(self.tmppath('interfaces.xpt')) |
michael@0 | 709 | self.assertEqual(foo['foo'], linked['foo']) |
michael@0 | 710 | self.assertEqual(bar['bar'], linked['bar']) |
michael@0 | 711 | |
michael@0 | 712 | x.remove(foo_xpt) |
michael@0 | 713 | x.copy(self.tmppath('interfaces2.xpt')) |
michael@0 | 714 | linked = read_interfaces(self.tmppath('interfaces2.xpt')) |
michael@0 | 715 | self.assertEqual(bar['foo'], linked['foo']) |
michael@0 | 716 | self.assertEqual(bar['bar'], linked['bar']) |
michael@0 | 717 | |
michael@0 | 718 | x.add(foo_xpt) |
michael@0 | 719 | x.copy(DestNoWrite(self.tmppath('interfaces.xpt'))) |
michael@0 | 720 | linked = read_interfaces(self.tmppath('interfaces.xpt')) |
michael@0 | 721 | self.assertEqual(foo['foo'], linked['foo']) |
michael@0 | 722 | self.assertEqual(bar['bar'], linked['bar']) |
michael@0 | 723 | |
michael@0 | 724 | x = XPTFile() |
michael@0 | 725 | x.add(foo2_xpt) |
michael@0 | 726 | x.add(bar_xpt) |
michael@0 | 727 | x.copy(self.tmppath('interfaces.xpt')) |
michael@0 | 728 | linked = read_interfaces(self.tmppath('interfaces.xpt')) |
michael@0 | 729 | self.assertEqual(foo2['foo'], linked['foo']) |
michael@0 | 730 | self.assertEqual(bar['bar'], linked['bar']) |
michael@0 | 731 | |
michael@0 | 732 | x = XPTFile() |
michael@0 | 733 | x.add(foo_xpt) |
michael@0 | 734 | x.add(foo2_xpt) |
michael@0 | 735 | x.add(bar_xpt) |
michael@0 | 736 | from xpt import DataError |
michael@0 | 737 | self.assertRaises(DataError, x.copy, self.tmppath('interfaces.xpt')) |
michael@0 | 738 | |
michael@0 | 739 | |
michael@0 | 740 | class TestMinifiedProperties(TestWithTmpDir): |
michael@0 | 741 | def test_minified_properties(self): |
michael@0 | 742 | propLines = [ |
michael@0 | 743 | '# Comments are removed', |
michael@0 | 744 | 'foo = bar', |
michael@0 | 745 | '', |
michael@0 | 746 | '# Another comment', |
michael@0 | 747 | ] |
michael@0 | 748 | prop = GeneratedFile('\n'.join(propLines)) |
michael@0 | 749 | self.assertEqual(MinifiedProperties(prop).open().readlines(), |
michael@0 | 750 | ['foo = bar\n', '\n']) |
michael@0 | 751 | open(self.tmppath('prop'), 'wb').write('\n'.join(propLines)) |
michael@0 | 752 | MinifiedProperties(File(self.tmppath('prop'))) \ |
michael@0 | 753 | .copy(self.tmppath('prop2')) |
michael@0 | 754 | self.assertEqual(open(self.tmppath('prop2')).readlines(), |
michael@0 | 755 | ['foo = bar\n', '\n']) |
michael@0 | 756 | |
michael@0 | 757 | |
michael@0 | 758 | class TestMinifiedJavaScript(TestWithTmpDir): |
michael@0 | 759 | orig_lines = [ |
michael@0 | 760 | '// Comment line', |
michael@0 | 761 | 'let foo = "bar";', |
michael@0 | 762 | 'var bar = true;', |
michael@0 | 763 | '', |
michael@0 | 764 | '// Another comment', |
michael@0 | 765 | ] |
michael@0 | 766 | |
michael@0 | 767 | def test_minified_javascript(self): |
michael@0 | 768 | orig_f = GeneratedFile('\n'.join(self.orig_lines)) |
michael@0 | 769 | min_f = MinifiedJavaScript(orig_f) |
michael@0 | 770 | |
michael@0 | 771 | mini_lines = min_f.open().readlines() |
michael@0 | 772 | self.assertTrue(mini_lines) |
michael@0 | 773 | self.assertTrue(len(mini_lines) < len(self.orig_lines)) |
michael@0 | 774 | |
michael@0 | 775 | def _verify_command(self, code): |
michael@0 | 776 | our_dir = os.path.abspath(os.path.dirname(__file__)) |
michael@0 | 777 | return [ |
michael@0 | 778 | sys.executable, |
michael@0 | 779 | os.path.join(our_dir, 'support', 'minify_js_verify.py'), |
michael@0 | 780 | code, |
michael@0 | 781 | ] |
michael@0 | 782 | |
michael@0 | 783 | def test_minified_verify_success(self): |
michael@0 | 784 | orig_f = GeneratedFile('\n'.join(self.orig_lines)) |
michael@0 | 785 | min_f = MinifiedJavaScript(orig_f, |
michael@0 | 786 | verify_command=self._verify_command('0')) |
michael@0 | 787 | |
michael@0 | 788 | mini_lines = min_f.open().readlines() |
michael@0 | 789 | self.assertTrue(mini_lines) |
michael@0 | 790 | self.assertTrue(len(mini_lines) < len(self.orig_lines)) |
michael@0 | 791 | |
michael@0 | 792 | def test_minified_verify_failure(self): |
michael@0 | 793 | orig_f = GeneratedFile('\n'.join(self.orig_lines)) |
michael@0 | 794 | min_f = MinifiedJavaScript(orig_f, |
michael@0 | 795 | verify_command=self._verify_command('1')) |
michael@0 | 796 | |
michael@0 | 797 | mini_lines = min_f.open().readlines() |
michael@0 | 798 | self.assertEqual(mini_lines, orig_f.open().readlines()) |
michael@0 | 799 | |
michael@0 | 800 | |
michael@0 | 801 | class MatchTestTemplate(object): |
michael@0 | 802 | def prepare_match_test(self, with_dotfiles=False): |
michael@0 | 803 | self.add('bar') |
michael@0 | 804 | self.add('foo/bar') |
michael@0 | 805 | self.add('foo/baz') |
michael@0 | 806 | self.add('foo/qux/1') |
michael@0 | 807 | self.add('foo/qux/bar') |
michael@0 | 808 | self.add('foo/qux/2/test') |
michael@0 | 809 | self.add('foo/qux/2/test2') |
michael@0 | 810 | if with_dotfiles: |
michael@0 | 811 | self.add('foo/.foo') |
michael@0 | 812 | self.add('foo/.bar/foo') |
michael@0 | 813 | |
michael@0 | 814 | def do_match_test(self): |
michael@0 | 815 | self.do_check('', [ |
michael@0 | 816 | 'bar', 'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar', |
michael@0 | 817 | 'foo/qux/2/test', 'foo/qux/2/test2' |
michael@0 | 818 | ]) |
michael@0 | 819 | self.do_check('*', [ |
michael@0 | 820 | 'bar', 'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar', |
michael@0 | 821 | 'foo/qux/2/test', 'foo/qux/2/test2' |
michael@0 | 822 | ]) |
michael@0 | 823 | self.do_check('foo/qux', [ |
michael@0 | 824 | 'foo/qux/1', 'foo/qux/bar', 'foo/qux/2/test', 'foo/qux/2/test2' |
michael@0 | 825 | ]) |
michael@0 | 826 | self.do_check('foo/b*', ['foo/bar', 'foo/baz']) |
michael@0 | 827 | self.do_check('baz', []) |
michael@0 | 828 | self.do_check('foo/foo', []) |
michael@0 | 829 | self.do_check('foo/*ar', ['foo/bar']) |
michael@0 | 830 | self.do_check('*ar', ['bar']) |
michael@0 | 831 | self.do_check('*/bar', ['foo/bar']) |
michael@0 | 832 | self.do_check('foo/*ux', [ |
michael@0 | 833 | 'foo/qux/1', 'foo/qux/bar', 'foo/qux/2/test', 'foo/qux/2/test2' |
michael@0 | 834 | ]) |
michael@0 | 835 | self.do_check('foo/q*ux', [ |
michael@0 | 836 | 'foo/qux/1', 'foo/qux/bar', 'foo/qux/2/test', 'foo/qux/2/test2' |
michael@0 | 837 | ]) |
michael@0 | 838 | self.do_check('foo/*/2/test*', ['foo/qux/2/test', 'foo/qux/2/test2']) |
michael@0 | 839 | self.do_check('**/bar', ['bar', 'foo/bar', 'foo/qux/bar']) |
michael@0 | 840 | self.do_check('foo/**/test', ['foo/qux/2/test']) |
michael@0 | 841 | self.do_check('foo/**', [ |
michael@0 | 842 | 'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar', |
michael@0 | 843 | 'foo/qux/2/test', 'foo/qux/2/test2' |
michael@0 | 844 | ]) |
michael@0 | 845 | self.do_check('**/2/test*', ['foo/qux/2/test', 'foo/qux/2/test2']) |
michael@0 | 846 | self.do_check('**/foo', [ |
michael@0 | 847 | 'foo/bar', 'foo/baz', 'foo/qux/1', 'foo/qux/bar', |
michael@0 | 848 | 'foo/qux/2/test', 'foo/qux/2/test2' |
michael@0 | 849 | ]) |
michael@0 | 850 | self.do_check('**/barbaz', []) |
michael@0 | 851 | self.do_check('f**/bar', ['foo/bar']) |
michael@0 | 852 | |
michael@0 | 853 | def do_finder_test(self, finder): |
michael@0 | 854 | self.assertTrue(finder.contains('foo/.foo')) |
michael@0 | 855 | self.assertTrue(finder.contains('foo/.bar')) |
michael@0 | 856 | self.assertTrue('foo/.foo' in [f for f, c in |
michael@0 | 857 | finder.find('foo/.foo')]) |
michael@0 | 858 | self.assertTrue('foo/.bar/foo' in [f for f, c in |
michael@0 | 859 | finder.find('foo/.bar')]) |
michael@0 | 860 | self.assertEqual(sorted([f for f, c in finder.find('foo/.*')]), |
michael@0 | 861 | ['foo/.bar/foo', 'foo/.foo']) |
michael@0 | 862 | for pattern in ['foo', '**', '**/*', '**/foo', 'foo/*']: |
michael@0 | 863 | self.assertFalse('foo/.foo' in [f for f, c in |
michael@0 | 864 | finder.find(pattern)]) |
michael@0 | 865 | self.assertFalse('foo/.bar/foo' in [f for f, c in |
michael@0 | 866 | finder.find(pattern)]) |
michael@0 | 867 | self.assertEqual(sorted([f for f, c in finder.find(pattern)]), |
michael@0 | 868 | sorted([f for f, c in finder |
michael@0 | 869 | if mozpack.path.match(f, pattern)])) |
michael@0 | 870 | |
michael@0 | 871 | |
michael@0 | 872 | def do_check(test, finder, pattern, result): |
michael@0 | 873 | if result: |
michael@0 | 874 | test.assertTrue(finder.contains(pattern)) |
michael@0 | 875 | else: |
michael@0 | 876 | test.assertFalse(finder.contains(pattern)) |
michael@0 | 877 | test.assertEqual(sorted(list(f for f, c in finder.find(pattern))), |
michael@0 | 878 | sorted(result)) |
michael@0 | 879 | |
michael@0 | 880 | |
michael@0 | 881 | class TestFileFinder(MatchTestTemplate, TestWithTmpDir): |
michael@0 | 882 | def add(self, path): |
michael@0 | 883 | ensureParentDir(self.tmppath(path)) |
michael@0 | 884 | open(self.tmppath(path), 'wb').write(path) |
michael@0 | 885 | |
michael@0 | 886 | def do_check(self, pattern, result): |
michael@0 | 887 | do_check(self, self.finder, pattern, result) |
michael@0 | 888 | |
michael@0 | 889 | def test_file_finder(self): |
michael@0 | 890 | self.prepare_match_test(with_dotfiles=True) |
michael@0 | 891 | self.finder = FileFinder(self.tmpdir) |
michael@0 | 892 | self.do_match_test() |
michael@0 | 893 | self.do_finder_test(self.finder) |
michael@0 | 894 | |
michael@0 | 895 | def test_ignored_dirs(self): |
michael@0 | 896 | """Ignored directories should not have results returned.""" |
michael@0 | 897 | self.prepare_match_test() |
michael@0 | 898 | self.add('fooz') |
michael@0 | 899 | |
michael@0 | 900 | # Present to ensure prefix matching doesn't exclude. |
michael@0 | 901 | self.add('foo/quxz') |
michael@0 | 902 | |
michael@0 | 903 | self.finder = FileFinder(self.tmpdir, ignore=['foo/qux']) |
michael@0 | 904 | |
michael@0 | 905 | self.do_check('**', ['bar', 'foo/bar', 'foo/baz', 'foo/quxz', 'fooz']) |
michael@0 | 906 | self.do_check('foo/*', ['foo/bar', 'foo/baz', 'foo/quxz']) |
michael@0 | 907 | self.do_check('foo/**', ['foo/bar', 'foo/baz', 'foo/quxz']) |
michael@0 | 908 | self.do_check('foo/qux/**', []) |
michael@0 | 909 | self.do_check('foo/qux/*', []) |
michael@0 | 910 | self.do_check('foo/qux/bar', []) |
michael@0 | 911 | self.do_check('foo/quxz', ['foo/quxz']) |
michael@0 | 912 | self.do_check('fooz', ['fooz']) |
michael@0 | 913 | |
michael@0 | 914 | def test_ignored_files(self): |
michael@0 | 915 | """Ignored files should not have results returned.""" |
michael@0 | 916 | self.prepare_match_test() |
michael@0 | 917 | |
michael@0 | 918 | # Be sure prefix match doesn't get ignored. |
michael@0 | 919 | self.add('barz') |
michael@0 | 920 | |
michael@0 | 921 | self.finder = FileFinder(self.tmpdir, ignore=['foo/bar', 'bar']) |
michael@0 | 922 | self.do_check('**', ['barz', 'foo/baz', 'foo/qux/1', 'foo/qux/2/test', |
michael@0 | 923 | 'foo/qux/2/test2', 'foo/qux/bar']) |
michael@0 | 924 | self.do_check('foo/**', ['foo/baz', 'foo/qux/1', 'foo/qux/2/test', |
michael@0 | 925 | 'foo/qux/2/test2', 'foo/qux/bar']) |
michael@0 | 926 | |
michael@0 | 927 | def test_ignored_patterns(self): |
michael@0 | 928 | """Ignore entries with patterns should be honored.""" |
michael@0 | 929 | self.prepare_match_test() |
michael@0 | 930 | |
michael@0 | 931 | self.add('foo/quxz') |
michael@0 | 932 | |
michael@0 | 933 | self.finder = FileFinder(self.tmpdir, ignore=['foo/qux/*']) |
michael@0 | 934 | self.do_check('**', ['foo/bar', 'foo/baz', 'foo/quxz', 'bar']) |
michael@0 | 935 | self.do_check('foo/**', ['foo/bar', 'foo/baz', 'foo/quxz']) |
michael@0 | 936 | |
michael@0 | 937 | |
michael@0 | 938 | class TestJarFinder(MatchTestTemplate, TestWithTmpDir): |
michael@0 | 939 | def add(self, path): |
michael@0 | 940 | self.jar.add(path, path, compress=True) |
michael@0 | 941 | |
michael@0 | 942 | def do_check(self, pattern, result): |
michael@0 | 943 | do_check(self, self.finder, pattern, result) |
michael@0 | 944 | |
michael@0 | 945 | def test_jar_finder(self): |
michael@0 | 946 | self.jar = JarWriter(file=self.tmppath('test.jar')) |
michael@0 | 947 | self.prepare_match_test() |
michael@0 | 948 | self.jar.finish() |
michael@0 | 949 | reader = JarReader(file=self.tmppath('test.jar')) |
michael@0 | 950 | self.finder = JarFinder(self.tmppath('test.jar'), reader) |
michael@0 | 951 | self.do_match_test() |
michael@0 | 952 | |
michael@0 | 953 | |
michael@0 | 954 | if __name__ == '__main__': |
michael@0 | 955 | mozunit.main() |