blob: cc5e505af89b8f2ed75b9aa0559620be3b90f700 [file] [log] [blame]
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00001import sys
2import os
3import shutil
Brett Cannon455ea532003-06-12 08:01:06 +00004import tempfile
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +00005
6import unittest
7import tarfile
8
9from test import test_support
10
11# Check for our compression modules.
12try:
13 import gzip
Neal Norwitzae323192003-04-14 01:18:32 +000014 gzip.GzipFile
15except (ImportError, AttributeError):
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000016 gzip = None
17try:
18 import bz2
19except ImportError:
20 bz2 = None
21
22def path(path):
23 return test_support.findfile(path)
24
Brett Cannon455ea532003-06-12 08:01:06 +000025testtar = path("testtar.tar")
26tempdir = os.path.join(tempfile.gettempdir(), "testtar" + os.extsep + "dir")
27tempname = test_support.TESTFN
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000028membercount = 10
29
30def tarname(comp=""):
31 if not comp:
32 return testtar
Brett Cannon43e559a2003-06-12 19:16:58 +000033 return os.path.join(tempdir, "%s%s%s" % (testtar, os.extsep, comp))
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000034
35def dirname():
36 if not os.path.exists(tempdir):
37 os.mkdir(tempdir)
38 return tempdir
39
40def tmpname():
41 return tempname
42
43
44class BaseTest(unittest.TestCase):
45 comp = ''
46 mode = 'r'
47 sep = ':'
48
49 def setUp(self):
50 mode = self.mode + self.sep + self.comp
51 self.tar = tarfile.open(tarname(self.comp), mode)
52
53 def tearDown(self):
54 self.tar.close()
55
56class ReadTest(BaseTest):
57
58 def test(self):
59 """Test member extraction.
60 """
61 members = 0
62 for tarinfo in self.tar:
63 members += 1
64 if not tarinfo.isreg():
65 continue
66 f = self.tar.extractfile(tarinfo)
67 self.assert_(len(f.read()) == tarinfo.size,
68 "size read does not match expected size")
69 f.close()
70
71 self.assert_(members == membercount,
72 "could not find all members")
73
74 def test_sparse(self):
75 """Test sparse member extraction.
76 """
77 if self.sep != "|":
78 f1 = self.tar.extractfile("S-SPARSE")
Jack Jansen149a8992003-03-07 13:27:53 +000079 f2 = self.tar.extractfile("S-SPARSE-WITH-NULLS")
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000080 self.assert_(f1.read() == f2.read(),
81 "_FileObject failed on sparse file member")
82
83 def test_readlines(self):
84 """Test readlines() method of _FileObject.
85 """
86 if self.sep != "|":
Jack Jansen149a8992003-03-07 13:27:53 +000087 filename = "0-REGTYPE-TEXT"
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000088 self.tar.extract(filename, dirname())
Jack Jansenc7fcc2d2003-03-07 12:50:45 +000089 lines1 = file(os.path.join(dirname(), filename), "rU").readlines()
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000090 lines2 = self.tar.extractfile(filename).readlines()
91 self.assert_(lines1 == lines2,
92 "_FileObject.readline() does not work correctly")
93
Martin v. Löwisdf241532005-03-03 08:17:42 +000094 def test_iter(self):
95 # Test iteration over ExFileObject.
96 if self.sep != "|":
97 filename = "0-REGTYPE-TEXT"
98 self.tar.extract(filename, dirname())
99 lines1 = file(os.path.join(dirname(), filename), "rU").readlines()
100 lines2 = [line for line in self.tar.extractfile(filename)]
101 self.assert_(lines1 == lines2,
102 "ExFileObject iteration does not work correctly")
103
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000104 def test_seek(self):
105 """Test seek() method of _FileObject, incl. random reading.
106 """
107 if self.sep != "|":
Jack Jansen149a8992003-03-07 13:27:53 +0000108 filename = "0-REGTYPE"
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000109 self.tar.extract(filename, dirname())
110 data = file(os.path.join(dirname(), filename), "rb").read()
111
112 tarinfo = self.tar.getmember(filename)
113 fobj = self.tar.extractfile(tarinfo)
114
115 text = fobj.read()
116 fobj.seek(0)
117 self.assert_(0 == fobj.tell(),
118 "seek() to file's start failed")
119 fobj.seek(2048, 0)
120 self.assert_(2048 == fobj.tell(),
121 "seek() to absolute position failed")
122 fobj.seek(-1024, 1)
123 self.assert_(1024 == fobj.tell(),
124 "seek() to negative relative position failed")
125 fobj.seek(1024, 1)
126 self.assert_(2048 == fobj.tell(),
127 "seek() to positive relative position failed")
128 s = fobj.read(10)
129 self.assert_(s == data[2048:2058],
130 "read() after seek failed")
131 fobj.seek(0, 2)
132 self.assert_(tarinfo.size == fobj.tell(),
133 "seek() to file's end failed")
134 self.assert_(fobj.read() == "",
135 "read() at file's end did not return empty string")
136 fobj.seek(-tarinfo.size, 2)
137 self.assert_(0 == fobj.tell(),
138 "relative seek() to file's start failed")
139 fobj.seek(512)
140 s1 = fobj.readlines()
141 fobj.seek(512)
142 s2 = fobj.readlines()
143 self.assert_(s1 == s2,
144 "readlines() after seek failed")
145 fobj.close()
146
147class ReadStreamTest(ReadTest):
148 sep = "|"
149
150 def test(self):
151 """Test member extraction, and for StreamError when
152 seeking backwards.
153 """
154 ReadTest.test(self)
155 tarinfo = self.tar.getmembers()[0]
156 f = self.tar.extractfile(tarinfo)
157 self.assertRaises(tarfile.StreamError, f.read)
158
159 def test_stream(self):
160 """Compare the normal tar and the stream tar.
161 """
162 stream = self.tar
163 tar = tarfile.open(tarname(), 'r')
164
165 while 1:
166 t1 = tar.next()
167 t2 = stream.next()
168 if t1 is None:
169 break
170 self.assert_(t2 is not None, "stream.next() failed.")
171
172 if t2.islnk() or t2.issym():
173 self.assertRaises(tarfile.StreamError, stream.extractfile, t2)
174 continue
175 v1 = tar.extractfile(t1)
176 v2 = stream.extractfile(t2)
177 if v1 is None:
178 continue
179 self.assert_(v2 is not None, "stream.extractfile() failed")
180 self.assert_(v1.read() == v2.read(), "stream extraction failed")
181
182 stream.close()
183
Martin v. Löwis78be7df2005-03-05 12:47:42 +0000184class ReadAsteriskTest(ReadTest):
185
186 def setUp(self):
187 mode = self.mode + self.sep + "*"
188 self.tar = tarfile.open(tarname(self.comp), mode)
189
190class ReadStreamAsteriskTest(ReadStreamTest):
191
192 def setUp(self):
193 mode = self.mode + self.sep + "*"
194 self.tar = tarfile.open(tarname(self.comp), mode)
195
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000196class WriteTest(BaseTest):
197 mode = 'w'
198
199 def setUp(self):
200 mode = self.mode + self.sep + self.comp
201 self.src = tarfile.open(tarname(self.comp), 'r')
Martin v. Löwisc234a522004-08-22 21:28:33 +0000202 self.dstname = tmpname()
203 self.dst = tarfile.open(self.dstname, mode)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000204
205 def tearDown(self):
206 self.src.close()
207 self.dst.close()
208
209 def test_posix(self):
210 self.dst.posix = 1
211 self._test()
212
213 def test_nonposix(self):
214 self.dst.posix = 0
215 self._test()
216
Martin v. Löwisc234a522004-08-22 21:28:33 +0000217 def test_small(self):
218 self.dst.add(os.path.join(os.path.dirname(__file__),"cfgparser.1"))
219 self.dst.close()
220 self.assertNotEqual(os.stat(self.dstname).st_size, 0)
221
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000222 def _test(self):
223 for tarinfo in self.src:
224 if not tarinfo.isreg():
225 continue
226 f = self.src.extractfile(tarinfo)
227 if self.dst.posix and len(tarinfo.name) > tarfile.LENGTH_NAME:
228 self.assertRaises(ValueError, self.dst.addfile,
229 tarinfo, f)
230 else:
231 self.dst.addfile(tarinfo, f)
232
233class WriteStreamTest(WriteTest):
234 sep = '|'
235
Neal Norwitz0662f8a2004-07-20 21:54:18 +0000236class WriteGNULongTest(unittest.TestCase):
237 """This testcase checks for correct creation of GNU Longname
238 and Longlink extensions.
239
240 It creates a tarfile and adds empty members with either
241 long names, long linknames or both and compares the size
242 of the tarfile with the expected size.
243
244 It checks for SF bug #812325 in TarFile._create_gnulong().
245
246 While I was writing this testcase, I noticed a second bug
247 in the same method:
248 Long{names,links} weren't null-terminated which lead to
249 bad tarfiles when their length was a multiple of 512. This
250 is tested as well.
251 """
252
253 def setUp(self):
254 self.tar = tarfile.open(tmpname(), "w")
255 self.tar.posix = False
256
257 def tearDown(self):
258 self.tar.close()
259
260 def _length(self, s):
261 blocks, remainder = divmod(len(s) + 1, 512)
262 if remainder:
263 blocks += 1
264 return blocks * 512
265
266 def _calc_size(self, name, link=None):
267 # initial tar header
268 count = 512
269
270 if len(name) > tarfile.LENGTH_NAME:
271 # gnu longname extended header + longname
272 count += 512
273 count += self._length(name)
274
275 if link is not None and len(link) > tarfile.LENGTH_LINK:
276 # gnu longlink extended header + longlink
277 count += 512
278 count += self._length(link)
279
280 return count
281
282 def _test(self, name, link=None):
283 tarinfo = tarfile.TarInfo(name)
284 if link:
285 tarinfo.linkname = link
286 tarinfo.type = tarfile.LNKTYPE
287
288 self.tar.addfile(tarinfo)
289
290 v1 = self._calc_size(name, link)
291 v2 = self.tar.offset
292 self.assertEqual(v1, v2, "GNU longname/longlink creation failed")
293
294 def test_longname_1023(self):
295 self._test(("longnam/" * 127) + "longnam")
296
297 def test_longname_1024(self):
298 self._test(("longnam/" * 127) + "longname")
299
300 def test_longname_1025(self):
301 self._test(("longnam/" * 127) + "longname_")
302
303 def test_longlink_1023(self):
304 self._test("name", ("longlnk/" * 127) + "longlnk")
305
306 def test_longlink_1024(self):
307 self._test("name", ("longlnk/" * 127) + "longlink")
308
309 def test_longlink_1025(self):
310 self._test("name", ("longlnk/" * 127) + "longlink_")
311
312 def test_longnamelink_1023(self):
313 self._test(("longnam/" * 127) + "longnam",
314 ("longlnk/" * 127) + "longlnk")
315
316 def test_longnamelink_1024(self):
317 self._test(("longnam/" * 127) + "longname",
318 ("longlnk/" * 127) + "longlink")
319
320 def test_longnamelink_1025(self):
321 self._test(("longnam/" * 127) + "longname_",
322 ("longlnk/" * 127) + "longlink_")
323
Neal Norwitza4f651a2004-07-20 22:07:44 +0000324class ExtractHardlinkTest(BaseTest):
325
326 def test_hardlink(self):
327 """Test hardlink extraction (bug #857297)
328 """
329 # Prevent errors from being caught
330 self.tar.errorlevel = 1
331
332 self.tar.extract("0-REGTYPE", dirname())
333 try:
334 # Extract 1-LNKTYPE which is a hardlink to 0-REGTYPE
335 self.tar.extract("1-LNKTYPE", dirname())
336 except EnvironmentError, e:
337 import errno
338 if e.errno == errno.ENOENT:
339 self.fail("hardlink not extracted properly")
340
341
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000342# Gzip TestCases
343class ReadTestGzip(ReadTest):
344 comp = "gz"
345class ReadStreamTestGzip(ReadStreamTest):
346 comp = "gz"
347class WriteTestGzip(WriteTest):
348 comp = "gz"
349class WriteStreamTestGzip(WriteStreamTest):
350 comp = "gz"
Martin v. Löwis78be7df2005-03-05 12:47:42 +0000351class ReadAsteriskTestGzip(ReadAsteriskTest):
352 comp = "gz"
353class ReadStreamAsteriskTestGzip(ReadStreamAsteriskTest):
354 comp = "gz"
355
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000356
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +0000357# Filemode test cases
358
359class FileModeTest(unittest.TestCase):
360 def test_modes(self):
361 self.assertEqual(tarfile.filemode(0755), '-rwxr-xr-x')
362 self.assertEqual(tarfile.filemode(07111), '---s--s--t')
363
Tim Peters8ceefc52004-10-25 03:19:41 +0000364
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000365if bz2:
366 # Bzip2 TestCases
367 class ReadTestBzip2(ReadTestGzip):
368 comp = "bz2"
369 class ReadStreamTestBzip2(ReadStreamTestGzip):
370 comp = "bz2"
371 class WriteTestBzip2(WriteTest):
372 comp = "bz2"
373 class WriteStreamTestBzip2(WriteStreamTestGzip):
374 comp = "bz2"
Martin v. Löwis78be7df2005-03-05 12:47:42 +0000375 class ReadAsteriskTestBzip2(ReadAsteriskTest):
376 comp = "bz2"
377 class ReadStreamAsteriskTestBzip2(ReadStreamAsteriskTest):
378 comp = "bz2"
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000379
380# If importing gzip failed, discard the Gzip TestCases.
381if not gzip:
382 del ReadTestGzip
383 del ReadStreamTestGzip
384 del WriteTestGzip
385 del WriteStreamTestGzip
386
Neal Norwitz996acf12003-02-17 14:51:41 +0000387def test_main():
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000388 if gzip:
389 # create testtar.tar.gz
390 gzip.open(tarname("gz"), "wb").write(file(tarname(), "rb").read())
391 if bz2:
392 # create testtar.tar.bz2
393 bz2.BZ2File(tarname("bz2"), "wb").write(file(tarname(), "rb").read())
394
Walter Dörwald21d3a322003-05-01 17:45:56 +0000395 tests = [
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +0000396 FileModeTest,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000397 ReadTest,
398 ReadStreamTest,
Martin v. Löwis78be7df2005-03-05 12:47:42 +0000399 ReadAsteriskTest,
400 ReadStreamAsteriskTest,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000401 WriteTest,
Neal Norwitz0662f8a2004-07-20 21:54:18 +0000402 WriteStreamTest,
403 WriteGNULongTest,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000404 ]
405
Neal Norwitza4f651a2004-07-20 22:07:44 +0000406 if hasattr(os, "link"):
407 tests.append(ExtractHardlinkTest)
408
Walter Dörwald21d3a322003-05-01 17:45:56 +0000409 if gzip:
410 tests.extend([
411 ReadTestGzip, ReadStreamTestGzip,
Martin v. Löwis78be7df2005-03-05 12:47:42 +0000412 WriteTestGzip, WriteStreamTestGzip,
413 ReadAsteriskTestGzip, ReadStreamAsteriskTestGzip
Walter Dörwald21d3a322003-05-01 17:45:56 +0000414 ])
415
416 if bz2:
417 tests.extend([
418 ReadTestBzip2, ReadStreamTestBzip2,
Martin v. Löwis78be7df2005-03-05 12:47:42 +0000419 WriteTestBzip2, WriteStreamTestBzip2,
420 ReadAsteriskTestBzip2, ReadStreamAsteriskTestBzip2
Walter Dörwald21d3a322003-05-01 17:45:56 +0000421 ])
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000422 try:
Walter Dörwald21d3a322003-05-01 17:45:56 +0000423 test_support.run_unittest(*tests)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000424 finally:
425 if gzip:
426 os.remove(tarname("gz"))
427 if bz2:
428 os.remove(tarname("bz2"))
Brett Cannon455ea532003-06-12 08:01:06 +0000429 if os.path.exists(dirname()):
430 shutil.rmtree(dirname())
431 if os.path.exists(tmpname()):
432 os.remove(tmpname())
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000433
Neal Norwitz996acf12003-02-17 14:51:41 +0000434if __name__ == "__main__":
435 test_main()