doc: add readthedocs config
[rarfile.git] / test / test_api.py
blobe4cd5707e897cd7a7135616f78e4484899648196
1 """API tests.
2 """
4 import io
5 import os
6 from pathlib import Path
8 import pytest
10 import rarfile
13 # test start
16 def test_not_rar():
17 with pytest.raises(rarfile.NotRarFile):
18 rarfile.RarFile("rarfile.py", "r")
19 with pytest.raises(rarfile.NotRarFile):
20 with open("rarfile.py", "rb") as f:
21 rarfile.RarFile(f, "r")
24 def test_bad_arc_mode_w():
25 with pytest.raises(NotImplementedError):
26 rarfile.RarFile("test/files/rar3-comment-plain.rar", "w")
29 def test_bad_arc_mode_rb():
30 with pytest.raises(NotImplementedError):
31 rarfile.RarFile("test/files/rar3-comment-plain.rar", "rb")
34 def test_bad_errs():
35 with pytest.raises(ValueError):
36 rarfile.RarFile("test/files/rar3-comment-plain.rar", "r", errors="foo")
39 def test_errors_param():
40 with open("test/files/rar3-comment-plain.rar", "rb") as f:
41 data = f.read()
42 buf = io.BytesIO(data[:17])
43 with rarfile.RarFile(buf, "r", errors="stop") as rf:
44 assert rf.namelist() == []
45 with pytest.raises(rarfile.BadRarFile):
46 rarfile.RarFile(buf, "r", errors="strict")
49 def test_bad_open_mode_w():
50 rf = rarfile.RarFile("test/files/rar3-comment-plain.rar")
51 with pytest.raises(NotImplementedError):
52 rf.open("qwe", "w")
55 def test_bad_open_psw():
56 rf = rarfile.RarFile("test/files/rar3-comment-psw.rar")
57 with pytest.raises(rarfile.PasswordRequired):
58 rf.open("file1.txt")
61 def test_bad_filelike():
62 with pytest.raises(ValueError):
63 rarfile.is_rarfile(bytearray(10))
66 def test_open_psw_late_rar3():
67 rf = rarfile.RarFile("test/files/rar3-comment-psw.rar")
68 d1 = rf.open("file1.txt", "r", "password").read()
69 d2 = rf.open("file1.txt", "r", b"password").read()
70 assert d1 == d2
73 def test_open_psw_late_rar5():
74 rf = rarfile.RarFile("test/files/rar5-psw.rar")
75 rf.open("stest1.txt", "r", "password").read()
76 rf.open("stest1.txt", "r", b"password").read()
79 def test_open_pathlib_path():
80 rf = rarfile.RarFile("test/files/rar5-psw.rar")
81 rf.open(Path("stest1.txt"), "r", "password").read()
84 def test_read_psw_late_rar3():
85 rf = rarfile.RarFile("test/files/rar3-comment-psw.rar")
86 rf.read("file1.txt", "password")
87 rf.read("file1.txt", b"password")
90 def test_read_psw_late_rar5():
91 rf = rarfile.RarFile("test/files/rar5-psw.rar")
92 rf.read("stest1.txt", "password")
93 rf.read("stest1.txt", b"password")
96 def test_open_psw_late():
97 rf = rarfile.RarFile("test/files/rar5-psw.rar")
98 with pytest.raises(rarfile.BadRarFile):
99 rf.read("stest1.txt", "password222")
102 def test_create_from_pathlib_path():
103 # Make sure we can open both relative and absolute Paths
104 rarfile.RarFile(Path("test/files/rar5-psw.rar"))
105 rarfile.RarFile(Path("test/files/rar5-psw.rar").resolve())
108 def test_detection():
109 assert rarfile.is_rarfile("test/files/ctime4.rar.exp") is False
110 assert rarfile.is_rarfile("test/files/ctime4.rar") is True
111 assert rarfile.is_rarfile("test/files/rar5-crc.rar") is True
113 assert rarfile.is_rarfile(Path("test/files/rar5-crc.rar")) is True
115 assert rarfile.is_rarfile("test/files/_missing_.rar") is False
118 def test_getinfo():
119 with rarfile.RarFile("test/files/rar5-crc.rar") as rf:
120 inf = rf.getinfo("stest1.txt")
121 assert isinstance(inf, rarfile.RarInfo)
122 assert rf.getinfo(inf) is inf
123 with pytest.raises(rarfile.NoRarEntry):
124 rf.getinfo("missing.txt")
126 def test_signature_error():
127 with pytest.raises(rarfile.NotRarFile):
128 rarfile.RarFile("test/files/ctime4.rar.exp")
131 def test_signature_error_mem():
132 data = io.BytesIO(b"x" * 40)
133 with pytest.raises(rarfile.NotRarFile):
134 rarfile.RarFile(data)
137 def test_with():
138 with rarfile.RarFile("test/files/rar5-crc.rar") as rf:
139 data = rf.read("stest1.txt")
140 with rf.open("stest1.txt") as f:
141 dst = io.BytesIO()
142 while True:
143 buf = f.read(7)
144 if not buf:
145 break
146 dst.write(buf)
147 assert dst.getvalue() == data
150 def test_readline():
151 def load_readline(rf, fn):
152 with rf.open(fn) as f:
153 tr = io.TextIOWrapper(io.BufferedReader(f))
154 res = []
155 while True:
156 ln = tr.readline()
157 if not ln:
158 break
159 res.append(ln)
160 return res
162 rf = rarfile.RarFile("test/files/seektest.rar")
163 v1 = load_readline(rf, "stest1.txt")
164 v2 = load_readline(rf, "stest2.txt")
165 assert len(v1) == 512
166 assert v1 == v2
169 def run_parallel(rfile, entry):
170 buf1, buf2 = [], []
171 rf = rarfile.RarFile(rfile)
172 count = 0
173 with rf.open(entry) as f1:
174 with rf.open(entry) as f2:
175 for _ in range(10000):
176 res1 = f1.read(10)
177 res2 = f2.read(10)
178 if res1:
179 buf1.append(res1)
180 count += len(res1)
181 if res2:
182 buf2.append(res2)
183 count += len(res2)
184 if not res1 and not res2:
185 break
187 assert buf1
188 assert buf1 == buf2
191 def test_parallel_file_compressed():
192 run_parallel("test/files/seektest.rar", "stest1.txt")
195 def test_parallel_file_direct():
196 run_parallel("test/files/seektest.rar", "stest2.txt")
199 def test_parallel_fd_compressed():
200 with open("test/files/seektest.rar", "rb") as f:
201 memfile = io.BytesIO(f.read())
202 run_parallel(memfile, "stest1.txt")
205 def test_parallel_fd_direct():
206 with open("test/files/seektest.rar", "rb") as f:
207 memfile = io.BytesIO(f.read())
208 run_parallel(memfile, "stest2.txt")
211 def test_printdir(capsys):
212 rf = rarfile.RarFile("test/files/seektest.rar")
213 rf.printdir()
214 res = capsys.readouterr()
215 assert res.out == "stest1.txt\nstest2.txt\n"
218 def test_testrar():
219 rf = rarfile.RarFile("test/files/seektest.rar")
220 rf.testrar()
223 def test_iter():
224 rf = rarfile.RarFile("test/files/seektest.rar")
225 n1 = rf.namelist()
226 n2 = [m.filename for m in rf]
227 assert n1 == n2
230 def test_testrar_mem():
231 with open("test/files/seektest.rar", "rb") as f:
232 arc = f.read()
233 rf = rarfile.RarFile(io.BytesIO(arc))
234 rf.testrar()
237 def test_extract(tmp_path):
238 ex1 = tmp_path / "extract1"
239 ex2 = tmp_path / "extract2"
240 ex3 = tmp_path / "extract3"
241 os.makedirs(str(ex1))
242 os.makedirs(str(ex2))
243 os.makedirs(str(ex3))
244 rf = rarfile.RarFile("test/files/seektest.rar")
246 rf.extractall(str(ex1))
247 assert os.path.isfile(str(ex1 / "stest1.txt")) is True
248 assert os.path.isfile(str(ex1 / "stest2.txt")) is True
250 rf.extract("stest1.txt", str(ex2))
251 assert os.path.isfile(str(ex2 / "stest1.txt")) is True
252 assert os.path.isfile(str(ex2 / "stest2.txt")) is False
254 inf = rf.getinfo("stest2.txt")
255 rf.extract(inf, str(ex3))
256 assert os.path.isfile(str(ex3 / "stest1.txt")) is False
257 assert os.path.isfile(str(ex3 / "stest2.txt")) is True
259 rf.extractall(str(ex2), ["stest1.txt"])
260 assert os.path.isfile(str(ex2 / "stest1.txt")) is True
262 rf.extractall(str(ex3), [rf.getinfo("stest2.txt")])
263 assert os.path.isfile(str(ex3 / "stest2.txt")) is True
265 ex4 = tmp_path / "extract4"
266 os.makedirs(str(ex4))
267 rf.extractall(ex4)
268 assert os.path.isfile(str(ex4 / "stest1.txt")) is True
269 assert os.path.isfile(str(ex4 / "stest2.txt")) is True
272 def test_extract_mem(tmp_path):
273 ex1 = tmp_path / "extract11"
274 ex2 = tmp_path / "extract22"
275 ex3 = tmp_path / "extract33"
276 os.makedirs(str(ex1))
277 os.makedirs(str(ex2))
278 os.makedirs(str(ex3))
280 with open("test/files/seektest.rar", "rb") as f:
281 arc = f.read()
282 rf = rarfile.RarFile(io.BytesIO(arc))
284 rf.extractall(str(ex1))
285 assert os.path.isfile(str(ex1 / "stest1.txt")) is True
286 assert os.path.isfile(str(ex1 / "stest2.txt")) is True
288 rf.extract("stest1.txt", str(ex2))
289 assert os.path.isfile(str(ex2 / "stest1.txt")) is True
290 assert os.path.isfile(str(ex2 / "stest2.txt")) is False
292 inf = rf.getinfo("stest2.txt")
293 rf.extract(inf, str(ex3))
294 assert os.path.isfile(str(ex3 / "stest1.txt")) is False
295 assert os.path.isfile(str(ex3 / "stest2.txt")) is True
298 def get_rftype(h):
299 assert h.is_dir() == h.isdir()
300 return "".join([
301 h.is_file() and "F" or "-",
302 h.is_dir() and "D" or "-",
303 h.is_symlink() and "L" or "-",
307 def test_infocb():
308 infos = []
310 def info_cb(info):
311 infos.append((info.type, info.needs_password(), get_rftype(info), info._must_disable_hack()))
313 rf = rarfile.RarFile("test/files/seektest.rar", info_callback=info_cb)
314 assert infos == [
315 (rarfile.RAR_BLOCK_MAIN, False, "---", False),
316 (rarfile.RAR_BLOCK_FILE, False, "F--", False),
317 (rarfile.RAR_BLOCK_FILE, False, "F--", False),
318 (rarfile.RAR_BLOCK_ENDARC, False, "---", False)]
319 rf.close()
321 infos = []
322 rf = rarfile.RarFile("test/files/rar5-solid-qo.rar", info_callback=info_cb)
323 assert infos == [
324 (rarfile.RAR_BLOCK_MAIN, False, "---", True),
325 (rarfile.RAR_BLOCK_FILE, False, "F--", False),
326 (rarfile.RAR_BLOCK_FILE, False, "F--", True),
327 (rarfile.RAR_BLOCK_FILE, False, "F--", True),
328 (rarfile.RAR_BLOCK_FILE, False, "F--", True),
329 (rarfile.RAR_BLOCK_SUB, False, "---", False),
330 (rarfile.RAR_BLOCK_ENDARC, False, "---", False)]
331 rf.close()
334 # pylint: disable=singleton-comparison
335 def test_rarextfile():
336 with rarfile.RarFile("test/files/seektest.rar") as rf:
337 for fn in ("stest1.txt", "stest2.txt"):
338 with rf.open(fn) as f:
339 assert f.tell() == 0
340 assert f.writable() == False
341 assert f.seekable() == True
342 assert f.readable() == True
343 assert f.readall() == rf.read(fn)
346 def test_is_rarfile():
347 with rarfile.RarFile("test/files/seektest.rar") as rf:
348 for fn in ("stest1.txt", "stest2.txt"):
349 with rf.open(fn) as f:
350 assert f.tell() == 0
351 assert f.writable() == False
352 assert f.seekable() == True
353 assert f.readable() == True
354 assert f.readall() == rf.read(fn)
357 def test_part_only():
358 info_list = []
359 def info_cb(info):
360 info_list.append(info)
362 with pytest.raises(rarfile.NeedFirstVolume):
363 with rarfile.RarFile("test/files/rar3-vols.part2.rar") as rf:
364 pass
365 with rarfile.RarFile("test/files/rar3-vols.part2.rar", part_only=True, info_callback=info_cb) as rf:
366 assert len(info_list) == 3
368 with pytest.raises(rarfile.NeedFirstVolume):
369 with rarfile.RarFile("test/files/rar5-vols.part2.rar") as rf:
370 pass
371 info_list = []
372 with rarfile.RarFile("test/files/rar5-vols.part2.rar", part_only=True, info_callback=info_cb) as rf:
373 assert len(info_list) == 5
376 def test_volume_info():
377 info_list = []
378 def info_cb(info):
379 info_list.append(info)
380 with rarfile.RarFile("test/files/rar3-vols.part1.rar", info_callback=info_cb) as rf:
381 assert len(info_list) == 10
382 info_list = []
383 with rarfile.RarFile("test/files/rar5-vols.part1.rar", info_callback=info_cb) as rf:
384 assert len(info_list) == 16
387 def test_is_solid():
388 with rarfile.RarFile("test/files/rar3-comment-plain.rar") as rf:
389 assert not rf.is_solid()
390 with rarfile.RarFile("test/files/rar3-solid.rar") as rf:
391 assert rf.is_solid()
392 with rarfile.RarFile("test/files/rar5-crc.rar") as rf:
393 assert not rf.is_solid()
394 with rarfile.RarFile("test/files/rar5-solid.rar") as rf:
395 assert rf.is_solid()