Coverage for tests/unit_tests/managers/test_package_manager.py: 100%
47 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-07 05:08 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-07 05:08 +0000
1# This file is part of the Apio project
2# (C) 2016-present FPGAwars
3# Project authors:
4# * Jesús Arroyo (Jesus89) (2016-2019)
5# * Juan Gonzalez (obijuan) (2019-2024)
6# * The Apio Team (2024-present)
7# License: GPLv2
9"""
10Tests of managers/package_manager.py
11"""
13import io
14import tarfile
15import pytest
16from tests.conftest import ApioRunner
17from apio.managers.package_manager import unpack_tgz
20def test_unpack_tgz(apio_runner: ApioRunner):
21 """Tests unpack_tgz()."""
23 with apio_runner.in_sandbox() as sb:
25 # -- Create the source files, one of them in a sub dir.
26 src_dir = sb.proj_dir / "src"
27 (src_dir / "bin").mkdir(parents=True)
28 (src_dir / "readme.txt").write_text("readme", encoding="utf-8")
29 (src_dir / "bin" / "tool").write_text("tool", encoding="utf-8")
31 # -- Archive them.
32 archive = sb.proj_dir / "package.tgz"
33 with tarfile.open(archive, "w:gz") as tar:
34 tar.add(src_dir / "readme.txt", arcname="readme.txt")
35 tar.add(src_dir / "bin" / "tool", arcname="bin/tool")
37 # -- Case 1: Unpack to a new dir. Should extract all the files.
38 dest_dir = sb.proj_dir / "dest1"
39 unpack_tgz(archive, dest_dir)
40 readme_text = (dest_dir / "readme.txt").read_text(encoding="utf-8")
41 assert readme_text == "readme"
42 tool_text = (dest_dir / "bin" / "tool").read_text(encoding="utf-8")
43 assert tool_text == "tool"
45 # -- Case 2: Unpack to an existing dir. Should extract all the files
46 # -- and keep the existing ones.
47 dest_dir = sb.proj_dir / "dest2"
48 dest_dir.mkdir()
49 (dest_dir / "existing.txt").write_text("existing", encoding="utf-8")
50 unpack_tgz(archive, dest_dir)
51 assert (dest_dir / "readme.txt").is_file()
52 assert (dest_dir / "bin" / "tool").is_file()
53 assert (dest_dir / "existing.txt").is_file()
55 # -- Case 3: An archive without the .tgz extension. Should fail.
56 archive_tar = sb.proj_dir / "package.tar"
57 archive_tar.write_bytes(archive.read_bytes())
58 with apio_runner.with_logger() as log:
59 with pytest.raises(SystemExit) as e:
60 unpack_tgz(archive_tar, sb.proj_dir / "dest3")
61 assert e.value.code == 1
62 assert "it's not a .tgz file" in log.out
63 assert not (sb.proj_dir / "dest3").exists()
66def test_unpack_tgz_unsafe_item(apio_runner: ApioRunner):
67 """Tests that unpack_tgz() rejects an item outside of the dest dir."""
69 with apio_runner.in_sandbox() as sb:
71 # -- Create an archive with a '../' item.
72 archive = sb.proj_dir / "package.tgz"
73 with tarfile.open(archive, "w:gz") as tar:
74 tar.addfile(tarfile.TarInfo("../escape.txt"), io.BytesIO())
76 # -- Unpack. Should fail and not write the file.
77 with apio_runner.with_logger() as log:
78 with pytest.raises(SystemExit) as e:
79 unpack_tgz(archive, sb.proj_dir / "dest")
80 assert e.value.code == 1
81 assert "Unsafe item '../escape.txt'" in log.out
82 assert not (sb.proj_dir / "escape.txt").exists()