Cleanup check-psw, change api
[rarfile.git] / test / test_api.py
blobc7dca3568866655da473cd0f0ebd636403ec89f7
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 test_printdir(capsys):
170 rf = rarfile.RarFile("test/files/seektest.rar")
171 rf.printdir()
172 res = capsys.readouterr()
173 assert res.out == "stest1.txt\nstest2.txt\n"
176 def test_testrar():
177 rf = rarfile.RarFile("test/files/seektest.rar")
178 rf.testrar()
181 def test_iter():
182 rf = rarfile.RarFile("test/files/seektest.rar")
183 n1 = rf.namelist()
184 n2 = [m.filename for m in rf]
185 assert n1 == n2
188 def test_testrar_mem():
189 with open("test/files/seektest.rar", "rb") as f:
190 arc = f.read()
191 rf = rarfile.RarFile(io.BytesIO(arc))
192 rf.testrar()
195 def test_extract(tmp_path):
196 ex1 = tmp_path / "extract1"
197 ex2 = tmp_path / "extract2"
198 ex3 = tmp_path / "extract3"
199 os.makedirs(str(ex1))
200 os.makedirs(str(ex2))
201 os.makedirs(str(ex3))
202 rf = rarfile.RarFile("test/files/seektest.rar")
204 rf.extractall(str(ex1))
205 assert os.path.isfile(str(ex1 / "stest1.txt")) is True
206 assert os.path.isfile(str(ex1 / "stest2.txt")) is True
208 rf.extract("stest1.txt", str(ex2))
209 assert os.path.isfile(str(ex2 / "stest1.txt")) is True
210 assert os.path.isfile(str(ex2 / "stest2.txt")) is False
212 inf = rf.getinfo("stest2.txt")
213 rf.extract(inf, str(ex3))
214 assert os.path.isfile(str(ex3 / "stest1.txt")) is False
215 assert os.path.isfile(str(ex3 / "stest2.txt")) is True
217 rf.extractall(str(ex2), ["stest1.txt"])
218 assert os.path.isfile(str(ex2 / "stest1.txt")) is True
220 rf.extractall(str(ex3), [rf.getinfo("stest2.txt")])
221 assert os.path.isfile(str(ex3 / "stest2.txt")) is True
223 ex4 = tmp_path / "extract4"
224 os.makedirs(str(ex4))
225 rf.extractall(ex4)
226 assert os.path.isfile(str(ex4 / "stest1.txt")) is True
227 assert os.path.isfile(str(ex4 / "stest2.txt")) is True
230 def test_extract_mem(tmp_path):
231 ex1 = tmp_path / "extract11"
232 ex2 = tmp_path / "extract22"
233 ex3 = tmp_path / "extract33"
234 os.makedirs(str(ex1))
235 os.makedirs(str(ex2))
236 os.makedirs(str(ex3))
238 with open("test/files/seektest.rar", "rb") as f:
239 arc = f.read()
240 rf = rarfile.RarFile(io.BytesIO(arc))
242 rf.extractall(str(ex1))
243 assert os.path.isfile(str(ex1 / "stest1.txt")) is True
244 assert os.path.isfile(str(ex1 / "stest2.txt")) is True
246 rf.extract("stest1.txt", str(ex2))
247 assert os.path.isfile(str(ex2 / "stest1.txt")) is True
248 assert os.path.isfile(str(ex2 / "stest2.txt")) is False
250 inf = rf.getinfo("stest2.txt")
251 rf.extract(inf, str(ex3))
252 assert os.path.isfile(str(ex3 / "stest1.txt")) is False
253 assert os.path.isfile(str(ex3 / "stest2.txt")) is True
256 def get_rftype(h):
257 assert h.is_dir() == h.isdir()
258 return "".join([
259 h.is_file() and "F" or "-",
260 h.is_dir() and "D" or "-",
261 h.is_symlink() and "L" or "-",
265 def test_infocb():
266 infos = []
268 def info_cb(info):
269 infos.append((info.type, info.needs_password(), get_rftype(info), info._must_disable_hack()))
271 rf = rarfile.RarFile("test/files/seektest.rar", info_callback=info_cb)
272 assert infos == [
273 (rarfile.RAR_BLOCK_MAIN, False, "---", False),
274 (rarfile.RAR_BLOCK_FILE, False, "F--", False),
275 (rarfile.RAR_BLOCK_FILE, False, "F--", False),
276 (rarfile.RAR_BLOCK_ENDARC, False, "---", False)]
277 rf.close()
279 infos = []
280 rf = rarfile.RarFile("test/files/rar5-solid-qo.rar", info_callback=info_cb)
281 assert infos == [
282 (rarfile.RAR_BLOCK_MAIN, False, "---", True),
283 (rarfile.RAR_BLOCK_FILE, False, "F--", False),
284 (rarfile.RAR_BLOCK_FILE, False, "F--", True),
285 (rarfile.RAR_BLOCK_FILE, False, "F--", True),
286 (rarfile.RAR_BLOCK_FILE, False, "F--", True),
287 (rarfile.RAR_BLOCK_SUB, False, "---", False),
288 (rarfile.RAR_BLOCK_ENDARC, False, "---", False)]
289 rf.close()
292 # pylint: disable=singleton-comparison
293 def test_rarextfile():
294 with rarfile.RarFile("test/files/seektest.rar") as rf:
295 for fn in ("stest1.txt", "stest2.txt"):
296 with rf.open(fn) as f:
297 assert f.tell() == 0
298 assert f.writable() == False
299 assert f.seekable() == True
300 assert f.readable() == True
301 assert f.readall() == rf.read(fn)
304 def test_is_rarfile():
305 with rarfile.RarFile("test/files/seektest.rar") as rf:
306 for fn in ("stest1.txt", "stest2.txt"):
307 with rf.open(fn) as f:
308 assert f.tell() == 0
309 assert f.writable() == False
310 assert f.seekable() == True
311 assert f.readable() == True
312 assert f.readall() == rf.read(fn)
315 def test_part_only():
316 info_list = []
317 def info_cb(info):
318 info_list.append(info)
320 with pytest.raises(rarfile.NeedFirstVolume):
321 with rarfile.RarFile("test/files/rar3-vols.part2.rar") as rf:
322 pass
323 with rarfile.RarFile("test/files/rar3-vols.part2.rar", part_only=True, info_callback=info_cb) as rf:
324 assert len(info_list) == 3
326 with pytest.raises(rarfile.NeedFirstVolume):
327 with rarfile.RarFile("test/files/rar5-vols.part2.rar") as rf:
328 pass
329 info_list = []
330 with rarfile.RarFile("test/files/rar5-vols.part2.rar", part_only=True, info_callback=info_cb) as rf:
331 assert len(info_list) == 5
334 def test_volume_info():
335 info_list = []
336 def info_cb(info):
337 info_list.append(info)
338 with rarfile.RarFile("test/files/rar3-vols.part1.rar", info_callback=info_cb) as rf:
339 assert len(info_list) == 10
340 info_list = []
341 with rarfile.RarFile("test/files/rar5-vols.part1.rar", info_callback=info_cb) as rf:
342 assert len(info_list) == 16