Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: client/libs/arfile/tests.py

Issue 2049523004: luci-py: Tools for working with BSD style ar archives. (Closed) Base URL: https://github.com/luci/luci-py.git@master
Patch Set: Adding missing unicode tests. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« client/libs/arfile/cli.py ('K') | « client/libs/arfile/cli.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
M-A Ruel 2016/06/22 14:21:32 please rename it to ar_test.py
mithro 2016/06/23 07:10:55 Done.
2 # Copyright 2016 The LUCI Authors. All rights reserved.
3 # Use of this source code is governed under the Apache License, Version 2.0
4 # that can be found in the LICENSE file.
5
6 # pylint: disable=relative-import
7
8 import io
9 import os
10 import shutil
11 import subprocess
12 import sys
13 import tempfile
14 import unittest
15
16 import arfile
17 import cli
18
19
20 ARFILE_DIR = os.path.dirname(os.path.abspath(__file__))
21 sys.path.insert(0, ARFILE_DIR)
22
23
24 if not hasattr(subprocess, 'DEVNULL'):
25 subprocess.DEVNULL = file(os.devnull, 'wb')
26
27
28 class ClosesSaveIOBytes(io.BytesIO):
29
30 def close(self):
31 _value = self.getvalue()
32 self.getvalue = lambda: _value
33 io.BytesIO.close(self)
34
35
36 AR_TEST_SIMPLE1 = (
37 # ar file header
38 '!<arch>\n'
39 # File 1
40 # ----------------------
41 # (16 bytes) simple file
42 'filename1 '
43 # (12 bytes) modification time
44 '123 '
45 # (6 bytes) user id
46 '1000 '
47 # (6 bytes) group id
48 '1000 '
49 # (8 bytes) file mode
50 '100640 '
51 # (10 bytes) data size
52 '6 '
53 # (2 bytes) file magic
54 '\x60\n'
55 # File data
56 'abc123'
57 # Finished
58 '')
59
60 AR_TEST_SIMPLE_UTF = (
61 # ar file header
62 '!<arch>\n'
63 # File 1
64 # ----------------------
65 # (16 bytes) simple file
66 '\xe2\x98\x83 '
67 # (12 bytes) modification time
68 '123 '
69 # (6 bytes) user id
70 '1000 '
71 # (6 bytes) group id
72 '1000 '
73 # (8 bytes) file mode
74 '100640 '
75 # (10 bytes) data size
76 '4 '
77 # (2 bytes) file magic
78 '\x60\n'
79 # (4 bytes) File data
80 '\xf0\x9f\x92\xa9'
81 # Finished
82 '')
83
84 AR_TEST_BSD1 = (
85 # ar file header
86 '!<arch>\n'
87 # File 1
88 # ----------------------
89 # (16 bytes) BSD style filename length
90 '#1/9 '
91 # (12 bytes) modification time
92 '1234 '
93 # (6 bytes) user id
94 '1001 '
95 # (6 bytes) group id
96 '1001 '
97 # (8 bytes) file mode
98 '100644 '
99 # (10 bytes) data size
100 '15 '
101 # (2 bytes) file magic
102 '\x60\n'
103 # BSD style filename
104 'filename1'
105 # File data
106 'abc123'
107 # Padding
108 '\n'
109 # Finished
110 '')
111
112 AR_TEST_BSD2 = (
113 # ar file header
114 '!<arch>\n'
115
116 # File 1
117 # ----------------------
118 # (16 bytes) filename len
119 '#1/5 '
120 # (12 bytes) mtime
121 '1447140471 '
122 # (6 bytes) owner id
123 '1000 '
124 # (6 bytes) group id
125 '1000 '
126 # (8 bytes) file mode
127 '100640 '
128 # (10 bytes) Data size
129 '13 '
130 # (2 bytes) File magic
131 '\x60\n'
132 # (9 bytes) File name
133 'file1'
134 # (6 bytes) File data
135 'contents'
136 # (1 byte) Padding
137 '\n'
138
139 # File 2
140 # ----------------------
141 # (16 bytes) filename len
142 '#1/7 '
143 # (12 bytes) mtime
144 '1447140471 '
145 # (6 bytes) owner id
146 '1000 '
147 # (6 bytes) group id
148 '1000 '
149 # (8 bytes) file mode
150 '100640 '
151 # (10 bytes) Data size
152 '10 '
153 # (2 bytes) File magic
154 '\x60\n'
155 # (9 bytes) File name
156 'fileabc'
157 # (6 bytes) File data
158 '123'
159 # (0 byte) No padding
160 ''
161
162 # File 3
163 # ----------------------
164 # (16 bytes) filename len
165 '#1/10 '
166 # (12 bytes) mtime
167 '1447140471 '
168 # (6 bytes) owner id
169 '1000 '
170 # (6 bytes) group id
171 '1000 '
172 # (8 bytes) file mode
173 '100640 '
174 # (10 bytes) Data size
175 '16 '
176 # (2 bytes) File magic
177 '\x60\n'
178 # (9 bytes) File name
179 'dir1/file1'
180 # (6 bytes) File data
181 '123abc'
182 # (0 byte) No padding
183 ''
184
185 # Finished
186 '')
187
188 AR_TEST_BSD_UTF = (
189 # ar file header
190 '!<arch>\n'
191 # File 1
192 # ----------------------
193 # (16 bytes) BSD style filename length
194 '#1/3 '
195 # (12 bytes) modification time
196 '1234 '
197 # (6 bytes) user id
198 '1001 '
199 # (6 bytes) group id
200 '1001 '
201 # (8 bytes) file mode
202 '100644 '
203 # (10 bytes) data size
204 '7 '
205 # (2 bytes) file magic
206 '\x60\n'
207 # (3 bytes) BSD style filename
208 '\xe2\x98\x83'
209 # (4 bytes) File data
210 '\xf0\x9f\x92\xa9'
211 # Padding
212 '\n'
213 # Finished
214 '')
215
216
217 class TestArFileReader(unittest.TestCase):
218
219 def testSimple1(self):
220 fileobj = io.BytesIO(AR_TEST_SIMPLE1)
221
222 afri = iter(arfile.ArFileReader(fileobj))
223 ai, af = afri.next()
224 self.assertIs(arfile.AR_FORMAT_SIMPLE, ai.format)
225 self.assertEqual('filename1', ai.name)
226 self.assertEqual(6, ai.size)
227 self.assertEqual(123, ai.mtime)
228 self.assertEqual(1000, ai.uid)
229 self.assertEqual(1000, ai.gid)
230 self.assertEqual('0100640', oct(ai.mode))
231 self.assertEqual('abc123', af.read(ai.size))
232
233 def testSimpleUTF(self):
234 fileobj = io.BytesIO(AR_TEST_SIMPLE_UTF)
235
236 afri = iter(arfile.ArFileReader(fileobj))
237 ai, af = afri.next()
238 self.assertIs(arfile.AR_FORMAT_SIMPLE, ai.format)
239 self.assertEqual(u'\u2603', ai.name)
240 self.assertEqual(4, ai.size)
241 self.assertEqual(123, ai.mtime)
242 self.assertEqual(1000, ai.uid)
243 self.assertEqual(1000, ai.gid)
244 self.assertEqual('0100640', oct(ai.mode))
245 self.assertEqual(u'\U0001f4a9', af.read(ai.size).decode('utf-8'))
246
247 def testBSD1(self):
248 fileobj = io.BytesIO(AR_TEST_BSD1)
249
250 afri = iter(arfile.ArFileReader(fileobj))
251 ai, af = afri.next()
252 self.assertIs(arfile.AR_FORMAT_BSD, ai.format)
253 self.assertEqual('filename1', ai.name)
254 self.assertEqual(6, ai.size)
255 self.assertEqual(1234, ai.mtime)
256 self.assertEqual(1001, ai.uid)
257 self.assertEqual(1001, ai.gid)
258 self.assertEqual('0100644', oct(ai.mode))
259 self.assertEqual('abc123', af.read(ai.size))
260
261 def testBSD2(self):
262 fileobj = io.BytesIO(AR_TEST_BSD2)
263
264 afri = iter(arfile.ArFileReader(fileobj))
265 ai, af = afri.next()
266 self.assertIs(arfile.AR_FORMAT_BSD, ai.format)
267 self.assertEqual('file1', ai.name)
268 self.assertEqual(8, ai.size)
269 self.assertEqual(1447140471, ai.mtime)
270 self.assertEqual(1000, ai.uid)
271 self.assertEqual(1000, ai.gid)
272 self.assertEqual('0100640', oct(ai.mode))
273 self.assertEqual('contents', af.read(ai.size))
274
275 ai, af = afri.next()
276 self.assertIs(arfile.AR_FORMAT_BSD, ai.format)
277 self.assertEqual('fileabc', ai.name)
278 self.assertEqual(3, ai.size)
279 self.assertEqual(1447140471, ai.mtime)
280 self.assertEqual(1000, ai.uid)
281 self.assertEqual(1000, ai.gid)
282 self.assertEqual('0100640', oct(ai.mode))
283 self.assertEqual('123', af.read(ai.size))
284
285 ai, af = afri.next()
286 self.assertIs(arfile.AR_FORMAT_BSD, ai.format)
287 self.assertEqual('dir1/file1', ai.name)
288 self.assertEqual(6, ai.size)
289 self.assertEqual(1447140471, ai.mtime)
290 self.assertEqual(1000, ai.uid)
291 self.assertEqual(1000, ai.gid)
292 self.assertEqual('0100640', oct(ai.mode))
293 self.assertEqual('123abc', af.read(ai.size))
294
295 def testBSDUTF(self):
296 fileobj = io.BytesIO(AR_TEST_BSD_UTF)
297
298 afri = iter(arfile.ArFileReader(fileobj))
299 ai, af = afri.next()
300 self.assertIs(arfile.AR_FORMAT_BSD, ai.format)
301 self.assertEqual(u'\u2603', ai.name)
302 self.assertEqual(4, ai.size)
303 self.assertEqual(1234, ai.mtime)
304 self.assertEqual(1001, ai.uid)
305 self.assertEqual(1001, ai.gid)
306 self.assertEqual('0100644', oct(ai.mode))
307 self.assertEqual(u'\U0001f4a9', af.read(ai.size).decode('utf-8'))
308
309
310 class TestArFileWriter(unittest.TestCase):
311
312 def testSimple1(self):
313 fileobj = ClosesSaveIOBytes()
314
315 afw = arfile.ArFileWriter(fileobj)
316 ai = arfile.ArInfo(
317 arfile.AR_FORMAT_SIMPLE, 'filename1', 6, 123, 1000, 1000, 0100640)
318 afw.addfile(ai, io.BytesIO('abc123'))
319 afw.close()
320
321 self.assertMultiLineEqual(AR_TEST_SIMPLE1, fileobj.getvalue())
322
323 def testSimpleUTF(self):
324 fileobj = ClosesSaveIOBytes()
325
326 afw = arfile.ArFileWriter(fileobj)
327 ai = arfile.ArInfo(
328 arfile.AR_FORMAT_SIMPLE, u'\u2603', 4, 123, 1000, 1000, 0100640)
329 afw.addfile(ai, io.BytesIO(u'\U0001f4a9'.encode('utf-8')))
330 afw.close()
331
332 self.assertMultiLineEqual(AR_TEST_SIMPLE_UTF, fileobj.getvalue())
333
334 def testBSD1(self):
335 fileobj = ClosesSaveIOBytes()
336
337 afw = arfile.ArFileWriter(fileobj)
338 ai = arfile.ArInfo(
339 arfile.AR_FORMAT_BSD, 'filename1', 6, 1234, 1001, 1001, 0100644)
340 afw.addfile(ai, io.BytesIO('abc123'))
341 afw.close()
342
343 self.assertMultiLineEqual(AR_TEST_BSD1, fileobj.getvalue())
344
345 def testBSD2(self):
346 fileobj = ClosesSaveIOBytes()
347
348 afw = arfile.ArFileWriter(fileobj)
349 afw.addfile(
350 arfile.ArInfo.fromdefault(
351 'file1', 8, arformat=arfile.AR_FORMAT_BSD),
352 io.BytesIO('contents'))
353 afw.addfile(
354 arfile.ArInfo.fromdefault(
355 'fileabc', 3, arformat=arfile.AR_FORMAT_BSD),
356 io.BytesIO('123'))
357 afw.addfile(
358 arfile.ArInfo.fromdefault(
359 'dir1/file1', 6, arformat=arfile.AR_FORMAT_BSD),
360 io.BytesIO('123abc'))
361 afw.close()
362
363 self.assertMultiLineEqual(AR_TEST_BSD2, fileobj.getvalue())
364
365 def testBSDUTF(self):
366 fileobj = ClosesSaveIOBytes()
367
368 afw = arfile.ArFileWriter(fileobj)
369 ai = arfile.ArInfo(
370 arfile.AR_FORMAT_BSD, u'\u2603', 4, 1234, 1001, 1001, 0100644)
371 afw.addfile(ai, io.BytesIO(u'\U0001f4a9'.encode('utf-8')))
372 afw.close()
373
374 self.assertMultiLineEqual(AR_TEST_BSD_UTF, fileobj.getvalue())
375
376
377 class BaseTestSuite(object):
378
379 def testSimple1(self):
380 self.assertWorking(
381 (
382 arfile.ArInfo(
383 arfile.AR_FORMAT_SIMPLE, 'filename1',
384 6, 123, 1000, 1000, 0100640),
385 'abc123'))
386
387 def testSimpleUTF(self):
388 self.assertWorking(
389 (
390 arfile.ArInfo(
391 arfile.AR_FORMAT_SIMPLE, u'\u2603',
392 4, 123, 1000, 1000, 0100640),
393 u'\U0001f4a9'.encode('utf-8')))
394
395 def testBSD1(self):
396 self.assertWorking(
397 (
398 arfile.ArInfo(
399 arfile.AR_FORMAT_BSD, 'filename1',
400 6, 123, 1000, 1000, 0100640),
401 'abc123'))
402
403 def testBSD2(self):
404 self.assertWorking(
405 (
406 arfile.ArInfo.fromdefault(
407 'file1', 8, arformat=arfile.AR_FORMAT_BSD),
408 'contents'),
409 (
410 arfile.ArInfo.fromdefault(
411 'fileabc', 3, arformat=arfile.AR_FORMAT_BSD),
412 '123'),
413 (
414 arfile.ArInfo.fromdefault(
415 'dir1/file1', 6, arformat=arfile.AR_FORMAT_BSD),
416 '123abc'))
417
418 def testBSDUTF(self):
419 self.assertWorking(
420 (
421 arfile.ArInfo(
422 arfile.AR_FORMAT_BSD, u'\u2603',
423 4, 123, 1000, 1000, 0100640),
424 u'\U0001f4a9'.encode('utf-8')))
425
426 def testMixed(self):
427 self.assertWorking(
428 (arfile.ArInfo.fromdefault('file1', 0), ''),
429 (arfile.ArInfo.fromdefault('f f', 1), 'a'),
430 (arfile.ArInfo.fromdefault('123456789abcedefa', 1), 'a'))
431
432
433 class TestArRoundTrip(BaseTestSuite, unittest.TestCase):
434
435 def assertWorking(self, *initems):
436 outfile = ClosesSaveIOBytes()
437
438 afw = arfile.ArFileWriter(outfile)
439 for ai, data in initems:
440 assert ai.size == len(data)
441 afw.addfile(ai, io.BytesIO(data))
442 afw.close()
443
444 infile = io.BytesIO(outfile.getvalue())
445 afr = arfile.ArFileReader(infile)
446
447 outitems = []
448 for ai, fd in afr:
449 data = fd.read(ai.size)
450 outitems.append((ai, data))
451
452 self.assertSequenceEqual(initems, outitems)
453
454
455 def system_has_ar():
456 retcode = subprocess.call(
457 'ar', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
458 return retcode == 1
459
460
461 @unittest.skipIf(not system_has_ar(), 'no ar binary found.')
462 class TestArExternal(BaseTestSuite, unittest.TestCase):
463
464 def assertWorking(self, *initems):
465 tf = tempfile.NamedTemporaryFile(mode='wb')
466 afw = arfile.ArFileWriter(tf)
467
468 files = []
469 for ai, data in initems:
470 files.append(ai.name)
471 assert ai.size == len(data)
472 afw.addfile(ai, io.BytesIO(data))
473 afw.flush()
474
475 output = subprocess.check_output(['ar', 't', tf.name])
476 self.assertMultiLineEqual('\n'.join(files), output.decode('utf-8').strip())
477 tf.close()
478
479
480 class TestCLI(unittest.TestCase):
481
482 def runCLI(self, args):
483 orig_stdout = sys.stdout
484 orig_stderr = sys.stderr
485 try:
486 sys.stdout = io.StringIO()
487 sys.stderr = io.StringIO()
488 cli.main('artool', args)
489 return sys.stdout.getvalue(), sys.stderr.getvalue()
490 finally:
491 sys.stdout = orig_stdout
492 sys.stderr = orig_stderr
493
494 def assertCLI(self, *initems):
495 indir = None
496 ardir = None
497 outdir = None
498 try:
499 indir = tempfile.mkdtemp().decode(sys.getfilesystemencoding())
500 ardir = tempfile.mkdtemp().decode(sys.getfilesystemencoding())
501 outdir = tempfile.mkdtemp().decode(sys.getfilesystemencoding())
502
503 arp = os.path.join(ardir, 'out.ar')
504 assert not os.path.exists(arp)
505
506 # Write out a directory tree
507 files = []
508 for fp, contents in initems:
509 fn = os.path.join(indir, fp)
510 dn = os.path.dirname(fn)
511 if not os.path.exists(dn):
512 os.makedirs(dn)
513
514 with file(fn, 'wb') as f:
515 f.write(contents)
516
517 files.append(fp)
518
519 files.sort()
520 fileslist = '\n'.join(files)
521
522 # Create an archive from a directory
523 self.runCLI(['create', '--filename', arp, indir])
524 self.assertTrue(
525 os.path.exists(arp), '%s file should exists' % arp)
526
527 # List the archive contents
528 output, _ = self.runCLI(['list', '--filename', arp])
529 filesoutput = '\n'.join(sorted(output[:-1].split('\n')))
530 self.assertMultiLineEqual(fileslist, filesoutput)
531
532 # Extract the archive
533 os.chdir(outdir)
534 self.runCLI(['extract', '--filename', arp])
535
536 # Walk the directory tree and collect the extracted output
537 outitems = []
538 for root, _, files in os.walk(outdir):
539 for fn in files:
540 fp = os.path.join(root, fn)
541 outitems.append([fp[len(outdir)+1:], file(fp, 'rb').read()])
542
543 # Check the two are equal
544 self.assertSequenceEqual(sorted(initems), sorted(outitems))
545
546 finally:
547 if indir:
548 shutil.rmtree(indir, ignore_errors=True)
549 if ardir:
550 shutil.rmtree(ardir, ignore_errors=True)
551 if outdir:
552 shutil.rmtree(outdir, ignore_errors=True)
553
554 def testSimple1(self):
555 self.assertCLI(
M-A Ruel 2016/06/22 14:21:32 please move these that fits 80 cols as one line, n
mithro 2016/06/23 07:10:54 Done.
556 ['file1', 'contents1'],
557 )
558
559 def testMultiple(self):
560 self.assertCLI(
561 ['file1', 'contents1'],
562 ['dir1/file2', 'contents2'],
563 ['dir2/dir3/file3', 'contents3'],
564 ['file4', 'contents4'],
565 )
566
567 def testUnicodeContents(self):
568 self.assertCLI(
569 ['file1', u'\u2603'.encode('utf-8')],
570 )
571
572 def testFilenameSpaces(self):
573 self.assertCLI(
574 ['f f1', 'contents1'],
575 ['d d1/file2', 'contents2'],
576 ['d d1/f f3', 'contents3'],
577 ['file4', 'contents4'],
578 )
579
580 def testBigFile(self):
581 self.assertCLI(
582 ['bigfile', 'data'*1024*1024*10],
583 )
584
585 def testUnicode(self):
586 self.assertCLI(
587 [u'\u2603', u'\U0001f4a9'.encode('utf-8')],
588 )
589
590 if __name__ == '__main__':
591 import doctest
M-A Ruel 2016/06/22 14:21:32 please import at file level at the top
mithro 2016/06/23 07:10:54 Done.
592 doctest.testmod(arfile)
593 unittest.main()
OLDNEW
« client/libs/arfile/cli.py ('K') | « client/libs/arfile/cli.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698