blob: 0fae5efcd4010bfa3be7a5a5030d0562d96fc22d [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
94 def test_seek(self):
95 """Test seek() method of _FileObject, incl. random reading.
96 """
97 if self.sep != "|":
Jack Jansen149a8992003-03-07 13:27:53 +000098 filename = "0-REGTYPE"
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +000099 self.tar.extract(filename, dirname())
100 data = file(os.path.join(dirname(), filename), "rb").read()
101
102 tarinfo = self.tar.getmember(filename)
103 fobj = self.tar.extractfile(tarinfo)
104
105 text = fobj.read()
106 fobj.seek(0)
107 self.assert_(0 == fobj.tell(),
108 "seek() to file's start failed")
109 fobj.seek(2048, 0)
110 self.assert_(2048 == fobj.tell(),
111 "seek() to absolute position failed")
112 fobj.seek(-1024, 1)
113 self.assert_(1024 == fobj.tell(),
114 "seek() to negative relative position failed")
115 fobj.seek(1024, 1)
116 self.assert_(2048 == fobj.tell(),
117 "seek() to positive relative position failed")
118 s = fobj.read(10)
119 self.assert_(s == data[2048:2058],
120 "read() after seek failed")
121 fobj.seek(0, 2)
122 self.assert_(tarinfo.size == fobj.tell(),
123 "seek() to file's end failed")
124 self.assert_(fobj.read() == "",
125 "read() at file's end did not return empty string")
126 fobj.seek(-tarinfo.size, 2)
127 self.assert_(0 == fobj.tell(),
128 "relative seek() to file's start failed")
129 fobj.seek(512)
130 s1 = fobj.readlines()
131 fobj.seek(512)
132 s2 = fobj.readlines()
133 self.assert_(s1 == s2,
134 "readlines() after seek failed")
135 fobj.close()
136
137class ReadStreamTest(ReadTest):
138 sep = "|"
139
140 def test(self):
141 """Test member extraction, and for StreamError when
142 seeking backwards.
143 """
144 ReadTest.test(self)
145 tarinfo = self.tar.getmembers()[0]
146 f = self.tar.extractfile(tarinfo)
147 self.assertRaises(tarfile.StreamError, f.read)
148
149 def test_stream(self):
150 """Compare the normal tar and the stream tar.
151 """
152 stream = self.tar
153 tar = tarfile.open(tarname(), 'r')
154
155 while 1:
156 t1 = tar.next()
157 t2 = stream.next()
158 if t1 is None:
159 break
160 self.assert_(t2 is not None, "stream.next() failed.")
161
162 if t2.islnk() or t2.issym():
163 self.assertRaises(tarfile.StreamError, stream.extractfile, t2)
164 continue
165 v1 = tar.extractfile(t1)
166 v2 = stream.extractfile(t2)
167 if v1 is None:
168 continue
169 self.assert_(v2 is not None, "stream.extractfile() failed")
170 self.assert_(v1.read() == v2.read(), "stream extraction failed")
171
172 stream.close()
173
174class WriteTest(BaseTest):
175 mode = 'w'
176
177 def setUp(self):
178 mode = self.mode + self.sep + self.comp
179 self.src = tarfile.open(tarname(self.comp), 'r')
Martin v. Löwisc234a522004-08-22 21:28:33 +0000180 self.dstname = tmpname()
181 self.dst = tarfile.open(self.dstname, mode)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000182
183 def tearDown(self):
184 self.src.close()
185 self.dst.close()
186
187 def test_posix(self):
188 self.dst.posix = 1
189 self._test()
190
191 def test_nonposix(self):
192 self.dst.posix = 0
193 self._test()
194
Martin v. Löwisc234a522004-08-22 21:28:33 +0000195 def test_small(self):
196 self.dst.add(os.path.join(os.path.dirname(__file__),"cfgparser.1"))
197 self.dst.close()
198 self.assertNotEqual(os.stat(self.dstname).st_size, 0)
199
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000200 def _test(self):
201 for tarinfo in self.src:
202 if not tarinfo.isreg():
203 continue
204 f = self.src.extractfile(tarinfo)
205 if self.dst.posix and len(tarinfo.name) > tarfile.LENGTH_NAME:
206 self.assertRaises(ValueError, self.dst.addfile,
207 tarinfo, f)
208 else:
209 self.dst.addfile(tarinfo, f)
210
211class WriteStreamTest(WriteTest):
212 sep = '|'
213
Neal Norwitz0662f8a2004-07-20 21:54:18 +0000214class WriteGNULongTest(unittest.TestCase):
215 """This testcase checks for correct creation of GNU Longname
216 and Longlink extensions.
217
218 It creates a tarfile and adds empty members with either
219 long names, long linknames or both and compares the size
220 of the tarfile with the expected size.
221
222 It checks for SF bug #812325 in TarFile._create_gnulong().
223
224 While I was writing this testcase, I noticed a second bug
225 in the same method:
226 Long{names,links} weren't null-terminated which lead to
227 bad tarfiles when their length was a multiple of 512. This
228 is tested as well.
229 """
230
231 def setUp(self):
232 self.tar = tarfile.open(tmpname(), "w")
233 self.tar.posix = False
234
235 def tearDown(self):
236 self.tar.close()
237
238 def _length(self, s):
239 blocks, remainder = divmod(len(s) + 1, 512)
240 if remainder:
241 blocks += 1
242 return blocks * 512
243
244 def _calc_size(self, name, link=None):
245 # initial tar header
246 count = 512
247
248 if len(name) > tarfile.LENGTH_NAME:
249 # gnu longname extended header + longname
250 count += 512
251 count += self._length(name)
252
253 if link is not None and len(link) > tarfile.LENGTH_LINK:
254 # gnu longlink extended header + longlink
255 count += 512
256 count += self._length(link)
257
258 return count
259
260 def _test(self, name, link=None):
261 tarinfo = tarfile.TarInfo(name)
262 if link:
263 tarinfo.linkname = link
264 tarinfo.type = tarfile.LNKTYPE
265
266 self.tar.addfile(tarinfo)
267
268 v1 = self._calc_size(name, link)
269 v2 = self.tar.offset
270 self.assertEqual(v1, v2, "GNU longname/longlink creation failed")
271
272 def test_longname_1023(self):
273 self._test(("longnam/" * 127) + "longnam")
274
275 def test_longname_1024(self):
276 self._test(("longnam/" * 127) + "longname")
277
278 def test_longname_1025(self):
279 self._test(("longnam/" * 127) + "longname_")
280
281 def test_longlink_1023(self):
282 self._test("name", ("longlnk/" * 127) + "longlnk")
283
284 def test_longlink_1024(self):
285 self._test("name", ("longlnk/" * 127) + "longlink")
286
287 def test_longlink_1025(self):
288 self._test("name", ("longlnk/" * 127) + "longlink_")
289
290 def test_longnamelink_1023(self):
291 self._test(("longnam/" * 127) + "longnam",
292 ("longlnk/" * 127) + "longlnk")
293
294 def test_longnamelink_1024(self):
295 self._test(("longnam/" * 127) + "longname",
296 ("longlnk/" * 127) + "longlink")
297
298 def test_longnamelink_1025(self):
299 self._test(("longnam/" * 127) + "longname_",
300 ("longlnk/" * 127) + "longlink_")
301
Neal Norwitza4f651a2004-07-20 22:07:44 +0000302class ExtractHardlinkTest(BaseTest):
303
304 def test_hardlink(self):
305 """Test hardlink extraction (bug #857297)
306 """
307 # Prevent errors from being caught
308 self.tar.errorlevel = 1
309
310 self.tar.extract("0-REGTYPE", dirname())
311 try:
312 # Extract 1-LNKTYPE which is a hardlink to 0-REGTYPE
313 self.tar.extract("1-LNKTYPE", dirname())
314 except EnvironmentError, e:
315 import errno
316 if e.errno == errno.ENOENT:
317 self.fail("hardlink not extracted properly")
318
319
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000320# Gzip TestCases
321class ReadTestGzip(ReadTest):
322 comp = "gz"
323class ReadStreamTestGzip(ReadStreamTest):
324 comp = "gz"
325class WriteTestGzip(WriteTest):
326 comp = "gz"
327class WriteStreamTestGzip(WriteStreamTest):
328 comp = "gz"
329
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +0000330# Filemode test cases
331
332class FileModeTest(unittest.TestCase):
333 def test_modes(self):
334 self.assertEqual(tarfile.filemode(0755), '-rwxr-xr-x')
335 self.assertEqual(tarfile.filemode(07111), '---s--s--t')
336
Tim Peters8ceefc52004-10-25 03:19:41 +0000337
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000338if bz2:
339 # Bzip2 TestCases
340 class ReadTestBzip2(ReadTestGzip):
341 comp = "bz2"
342 class ReadStreamTestBzip2(ReadStreamTestGzip):
343 comp = "bz2"
344 class WriteTestBzip2(WriteTest):
345 comp = "bz2"
346 class WriteStreamTestBzip2(WriteStreamTestGzip):
347 comp = "bz2"
348
349# If importing gzip failed, discard the Gzip TestCases.
350if not gzip:
351 del ReadTestGzip
352 del ReadStreamTestGzip
353 del WriteTestGzip
354 del WriteStreamTestGzip
355
Neal Norwitz996acf12003-02-17 14:51:41 +0000356def test_main():
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000357 if gzip:
358 # create testtar.tar.gz
359 gzip.open(tarname("gz"), "wb").write(file(tarname(), "rb").read())
360 if bz2:
361 # create testtar.tar.bz2
362 bz2.BZ2File(tarname("bz2"), "wb").write(file(tarname(), "rb").read())
363
Walter Dörwald21d3a322003-05-01 17:45:56 +0000364 tests = [
Andrew M. Kuchlingd4f25522004-10-20 11:47:01 +0000365 FileModeTest,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000366 ReadTest,
367 ReadStreamTest,
368 WriteTest,
Neal Norwitz0662f8a2004-07-20 21:54:18 +0000369 WriteStreamTest,
370 WriteGNULongTest,
Walter Dörwald21d3a322003-05-01 17:45:56 +0000371 ]
372
Neal Norwitza4f651a2004-07-20 22:07:44 +0000373 if hasattr(os, "link"):
374 tests.append(ExtractHardlinkTest)
375
Walter Dörwald21d3a322003-05-01 17:45:56 +0000376 if gzip:
377 tests.extend([
378 ReadTestGzip, ReadStreamTestGzip,
379 WriteTestGzip, WriteStreamTestGzip
380 ])
381
382 if bz2:
383 tests.extend([
384 ReadTestBzip2, ReadStreamTestBzip2,
385 WriteTestBzip2, WriteStreamTestBzip2
386 ])
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000387 try:
Walter Dörwald21d3a322003-05-01 17:45:56 +0000388 test_support.run_unittest(*tests)
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000389 finally:
390 if gzip:
391 os.remove(tarname("gz"))
392 if bz2:
393 os.remove(tarname("bz2"))
Brett Cannon455ea532003-06-12 08:01:06 +0000394 if os.path.exists(dirname()):
395 shutil.rmtree(dirname())
396 if os.path.exists(tmpname()):
397 os.remove(tmpname())
Neal Norwitzb9ef4ae2003-01-05 23:19:43 +0000398
Neal Norwitz996acf12003-02-17 14:51:41 +0000399if __name__ == "__main__":
400 test_main()