blob: a6c4c4a4f958ea9df0bb4570db7bc55256a96066 [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
184class WriteTest(BaseTest):
185 mode = 'w'
186
187 def setUp(self):
188 mode = self.mode + self.sep + self.comp
189 self.src = tarfile.open(tarname(self.comp), 'r')
Martin v. Löwisc234a522004-08-22 21:28:33 +0000190 self.dstname = tmpname()
191 self.dst = tarfile.open(self.dstname, mode)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000192
193 def tearDown(self):
194 self.src.close()
195 self.dst.close()
196
197 def test_posix(self):
198 self.dst.posix = 1
199 self._test()
200
201 def test_nonposix(self):
202 self.dst.posix = 0
203 self._test()
204
Martin v. Löwisc234a522004-08-22 21:28:33 +0000205 def test_small(self):
206 self.dst.add(os.path.join(os.path.dirname(__file__),"cfgparser.1"))
207 self.dst.close()
208 self.assertNotEqual(os.stat(self.dstname).st_size, 0)
209
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000210 def _test(self):
211 for tarinfo in self.src:
212 if not tarinfo.isreg():
213 continue
214 f = self.src.extractfile(tarinfo)
215 if self.dst.posix and len(tarinfo.name) > tarfile.LENGTH_NAME:
216 self.assertRaises(ValueError, self.dst.addfile,
217 tarinfo, f)
218 else:
219 self.dst.addfile(tarinfo, f)
220
221class WriteStreamTest(WriteTest):
222 sep = '|'
223
Neal Norwitz0662f8a2004-07-20 21:54:18 +0000224class WriteGNULongTest(unittest.TestCase):
225 """This testcase checks for correct creation of GNU Longname
226 and Longlink extensions.
227
228 It creates a tarfile and adds empty members with either
229 long names, long linknames or both and compares the size
230 of the tarfile with the expected size.
231
232 It checks for SF bug #812325 in TarFile._create_gnulong().
233
234 While I was writing this testcase, I noticed a second bug
235 in the same method:
236 Long{names,links} weren't null-terminated which lead to
237 bad tarfiles when their length was a multiple of 512. This
238 is tested as well.
239 """
240
241 def setUp(self):
242 self.tar = tarfile.open(tmpname(), "w")
243 self.tar.posix = False
244
245 def tearDown(self):
246 self.tar.close()
247
248 def _length(self, s):
249 blocks, remainder = divmod(len(s) + 1, 512)
250 if remainder:
251 blocks += 1
252 return blocks * 512
253
254 def _calc_size(self, name, link=None):
255 # initial tar header
256 count = 512
257
258 if len(name) > tarfile.LENGTH_NAME:
259 # gnu longname extended header + longname
260 count += 512
261 count += self._length(name)
262
263 if link is not None and len(link) > tarfile.LENGTH_LINK:
264 # gnu longlink extended header + longlink
265 count += 512
266 count += self._length(link)
267
268 return count
269
270 def _test(self, name, link=None):
271 tarinfo = tarfile.TarInfo(name)
272 if link:
273 tarinfo.linkname = link
274 tarinfo.type = tarfile.LNKTYPE
275
276 self.tar.addfile(tarinfo)
277
278 v1 = self._calc_size(name, link)
279 v2 = self.tar.offset
280 self.assertEqual(v1, v2, "GNU longname/longlink creation failed")
281
282 def test_longname_1023(self):
283 self._test(("longnam/" * 127) + "longnam")
284
285 def test_longname_1024(self):
286 self._test(("longnam/" * 127) + "longname")
287
288 def test_longname_1025(self):
289 self._test(("longnam/" * 127) + "longname_")
290
291 def test_longlink_1023(self):
292 self._test("name", ("longlnk/" * 127) + "longlnk")
293
294 def test_longlink_1024(self):
295 self._test("name", ("longlnk/" * 127) + "longlink")
296
297 def test_longlink_1025(self):
298 self._test("name", ("longlnk/" * 127) + "longlink_")
299
300 def test_longnamelink_1023(self):
301 self._test(("longnam/" * 127) + "longnam",
302 ("longlnk/" * 127) + "longlnk")
303
304 def test_longnamelink_1024(self):
305 self._test(("longnam/" * 127) + "longname",
306 ("longlnk/" * 127) + "longlink")
307
308 def test_longnamelink_1025(self):
309 self._test(("longnam/" * 127) + "longname_",
310 ("longlnk/" * 127) + "longlink_")
311
Neal Norwitza4f651a2004-07-20 22:07:44 +0000312class ExtractHardlinkTest(BaseTest):
313
314 def test_hardlink(self):
315 """Test hardlink extraction (bug #857297)
316 """
317 # Prevent errors from being caught
318 self.tar.errorlevel = 1
319
320 self.tar.extract("0-REGTYPE", dirname())
321 try:
322 # Extract 1-LNKTYPE which is a hardlink to 0-REGTYPE
323 self.tar.extract("1-LNKTYPE", dirname())
324 except EnvironmentError, e:
325 import errno
326 if e.errno == errno.ENOENT:
327 self.fail("hardlink not extracted properly")
328
329
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000330# Gzip TestCases
331class ReadTestGzip(ReadTest):
332 comp = "gz"
333class ReadStreamTestGzip(ReadStreamTest):
334 comp = "gz"
335class WriteTestGzip(WriteTest):
336 comp = "gz"
337class WriteStreamTestGzip(WriteStreamTest):
338 comp = "gz"
339
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +0000340# Filemode test cases
341
342class FileModeTest(unittest.TestCase):
343 def test_modes(self):
344 self.assertEqual(tarfile.filemode(0755), '-rwxr-xr-x')
345 self.assertEqual(tarfile.filemode(07111), '---s--s--t')
346
Tim Peters8ceefc52004-10-25 03:19:41 +0000347
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000348if bz2:
349 # Bzip2 TestCases
350 class ReadTestBzip2(ReadTestGzip):
351 comp = "bz2"
352 class ReadStreamTestBzip2(ReadStreamTestGzip):
353 comp = "bz2"
354 class WriteTestBzip2(WriteTest):
355 comp = "bz2"
356 class WriteStreamTestBzip2(WriteStreamTestGzip):
357 comp = "bz2"
358
359# If importing gzip failed, discard the Gzip TestCases.
360if not gzip:
361 del ReadTestGzip
362 del ReadStreamTestGzip
363 del WriteTestGzip
364 del WriteStreamTestGzip
365
Neal Norwitz996acf12003-02-17 14:51:41 +0000366def test_main():
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000367 if gzip:
368 # create testtar.tar.gz
369 gzip.open(tarname("gz"), "wb").write(file(tarname(), "rb").read())
370 if bz2:
371 # create testtar.tar.bz2
372 bz2.BZ2File(tarname("bz2"), "wb").write(file(tarname(), "rb").read())
373
Walter Dörwald21d3a322003-05-01 17:45:56 +0000374 tests = [
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +0000375 FileModeTest,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000376 ReadTest,
377 ReadStreamTest,
378 WriteTest,
Neal Norwitz0662f8a2004-07-20 21:54:18 +0000379 WriteStreamTest,
380 WriteGNULongTest,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000381 ]
382
Neal Norwitza4f651a2004-07-20 22:07:44 +0000383 if hasattr(os, "link"):
384 tests.append(ExtractHardlinkTest)
385
Walter Dörwald21d3a322003-05-01 17:45:56 +0000386 if gzip:
387 tests.extend([
388 ReadTestGzip, ReadStreamTestGzip,
389 WriteTestGzip, WriteStreamTestGzip
390 ])
391
392 if bz2:
393 tests.extend([
394 ReadTestBzip2, ReadStreamTestBzip2,
395 WriteTestBzip2, WriteStreamTestBzip2
396 ])
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000397 try:
Walter Dörwald21d3a322003-05-01 17:45:56 +0000398 test_support.run_unittest(*tests)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000399 finally:
400 if gzip:
401 os.remove(tarname("gz"))
402 if bz2:
403 os.remove(tarname("bz2"))
Brett Cannon455ea532003-06-12 08:01:06 +0000404 if os.path.exists(dirname()):
405 shutil.rmtree(dirname())
406 if os.path.exists(tmpname()):
407 os.remove(tmpname())
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000408
Neal Norwitz996acf12003-02-17 14:51:41 +0000409if __name__ == "__main__":
410 test_main()