Skip to content

Commit f95c43c

Browse files
committed
Add more type hints to test suite
1 parent d6f2edb commit f95c43c

File tree

3 files changed

+80
-38
lines changed

3 files changed

+80
-38
lines changed

tests/test_module_imports.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
# Copyright 2025 Broadcom.
22
# SPDX-License-Identifier: Apache-2.0
33
#
4+
from __future__ import annotations
5+
46
import importlib
57
import pathlib
8+
from typing import List
69

710
import pytest
811

912

10-
def _top_level_modules():
13+
def _top_level_modules() -> List[pytest.ParameterSet]:
1114
relenv_dir = pathlib.Path(__file__).resolve().parents[1] / "relenv"
12-
params = []
15+
params: List[pytest.ParameterSet] = []
1316
for path in sorted(relenv_dir.iterdir()):
1417
if not path.is_file() or path.suffix != ".py":
1518
continue

tests/test_pyversions_runtime.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,60 @@
11
# Copyright 2025 Broadcom.
22
# SPDX-License-Identifier: Apache-2.0
33
#
4+
from __future__ import annotations
5+
46
import hashlib
7+
import pathlib
58
import subprocess
9+
from typing import Dict
10+
11+
import pytest
612

713
from relenv import pyversions
814

915

10-
def test_python_versions_returns_versions():
11-
versions = pyversions.python_versions()
16+
def test_python_versions_returns_versions() -> None:
17+
versions: Dict[pyversions.Version, str] = pyversions.python_versions()
1218
assert versions, "python_versions() should return known versions"
1319
first_version = next(iter(versions))
1420
assert isinstance(first_version, pyversions.Version)
1521
assert isinstance(versions[first_version], str)
1622

1723

18-
def test_python_versions_filters_minor():
24+
def test_python_versions_filters_minor() -> None:
1925
versions = pyversions.python_versions("3.11")
2026
assert versions
2127
assert all(version.major == 3 and version.minor == 11 for version in versions)
2228
sorted_versions = sorted(versions)
2329
assert sorted_versions[-1] in versions
2430

2531

26-
def test_release_urls_handles_old_versions():
32+
def test_release_urls_handles_old_versions() -> None:
2733
tarball, signature = pyversions._release_urls(pyversions.Version("3.1.3"))
2834
assert tarball.endswith(".tar.xz")
2935
assert signature is not None
3036

3137

32-
def test_release_urls_no_signature_before_23():
38+
def test_release_urls_no_signature_before_23() -> None:
3339
tarball, signature = pyversions._release_urls(pyversions.Version("2.2.3"))
3440
assert tarball.endswith(".tar.xz")
3541
assert signature is None
3642

3743

38-
def test_ref_version_and_path_helpers():
44+
def test_ref_version_and_path_helpers() -> None:
3945
html = '<a href="download/Python-3.11.9.tgz">Python 3.11.9</a>'
4046
version = pyversions._ref_version(html)
4147
assert str(version) == "3.11.9"
4248
assert pyversions._ref_path(html) == "download/Python-3.11.9.tgz"
4349

4450

45-
def test_digest(tmp_path):
51+
def test_digest(tmp_path: pathlib.Path) -> None:
4652
file = tmp_path / "data.bin"
4753
file.write_bytes(b"abc")
4854
assert pyversions.digest(file) == hashlib.sha1(b"abc").hexdigest()
4955

5056

51-
def test_get_keyid_parses_second_line():
57+
def test_get_keyid_parses_second_line() -> None:
5258
proc = subprocess.CompletedProcess(
5359
["gpg"],
5460
1,
@@ -58,20 +64,24 @@ def test_get_keyid_parses_second_line():
5864
assert pyversions._get_keyid(proc) == "CB1234"
5965

6066

61-
def test_verify_signature_success(monkeypatch, tmp_path):
62-
called = {}
67+
def test_verify_signature_success(
68+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
69+
) -> None:
70+
called: Dict[str, list[str]] = {}
6371

6472
def fake_run(cmd, **kwargs):
65-
called["cmd"] = cmd
73+
called.setdefault("cmd", []).extend(cmd)
6674
return subprocess.CompletedProcess(cmd, 0, stdout=b"", stderr=b"")
6775

6876
monkeypatch.setattr(pyversions.subprocess, "run", fake_run)
6977
assert pyversions.verify_signature("archive.tgz", "archive.tgz.asc") is True
7078
assert called["cmd"][0] == "gpg"
7179

7280

73-
def test_verify_signature_failure_with_missing_key(monkeypatch):
74-
responses = []
81+
def test_verify_signature_failure_with_missing_key(
82+
monkeypatch: pytest.MonkeyPatch,
83+
) -> None:
84+
responses: list[str] = []
7585

7686
def fake_run(cmd, **kwargs):
7787
if len(responses) == 0:

tests/test_relocate_module.py

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
# Copyright 2025 Broadcom.
22
# SPDX-License-Identifier: Apache-2.0
33
#
4+
from __future__ import annotations
5+
46
import os
57
import pathlib
68
import shutil
79
import subprocess
10+
from typing import Dict, List
11+
12+
import pytest
813

914
from relenv import relocate
1015

1116

12-
def test_is_elf_on_text_file(tmp_path):
17+
def test_is_elf_on_text_file(tmp_path: pathlib.Path) -> None:
1318
sample = tmp_path / "sample.txt"
1419
sample.write_text("not an ELF binary\n")
1520
assert relocate.is_elf(sample) is False
1621

1722

18-
def test_is_macho_on_text_file(tmp_path):
23+
def test_is_macho_on_text_file(tmp_path: pathlib.Path) -> None:
1924
sample = tmp_path / "sample.txt"
2025
sample.write_text("plain text\n")
2126
assert relocate.is_macho(sample) is False
2227

2328

24-
def test_parse_readelf_output():
29+
def test_parse_readelf_output() -> None:
2530
output = """
2631
0x000000000000000f (NEEDED) Shared library: [libc.so.6]
2732
0x000000000000001d (RUNPATH) Library runpath: [/usr/lib:/opt/lib]
@@ -30,7 +35,7 @@ def test_parse_readelf_output():
3035
assert result == ["/usr/lib", "/opt/lib"]
3136

3237

33-
def test_parse_otool_output_extracts_rpaths():
38+
def test_parse_otool_output_extracts_rpaths() -> None:
3439
sample_output = """
3540
Load command 0
3641
cmd LC_LOAD_DYLIB
@@ -46,7 +51,9 @@ def test_parse_otool_output_extracts_rpaths():
4651
assert parsed[relocate.LC_RPATH] == ["@loader_path/../lib"]
4752

4853

49-
def test_patch_rpath_adds_new_entry(monkeypatch, tmp_path):
54+
def test_patch_rpath_adds_new_entry(
55+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
56+
) -> None:
5057
binary = tmp_path / "prog"
5158
binary.write_text("dummy")
5259

@@ -56,10 +63,12 @@ def test_patch_rpath_adds_new_entry(monkeypatch, tmp_path):
5663
lambda path: ["$ORIGIN/lib", "/abs/lib"],
5764
)
5865

59-
recorded = {}
66+
recorded: Dict[str, List[str]] = {}
6067

61-
def fake_run(cmd, **kwargs):
62-
recorded["cmd"] = cmd
68+
def fake_run(
69+
cmd: List[str], **kwargs: object
70+
) -> subprocess.CompletedProcess[bytes]:
71+
recorded.setdefault("cmd", []).extend(cmd)
6372
return subprocess.CompletedProcess(cmd, 0, stdout=b"", stderr=b"")
6473

6574
monkeypatch.setattr(relocate.subprocess, "run", fake_run)
@@ -69,13 +78,15 @@ def fake_run(cmd, **kwargs):
6978
assert pathlib.Path(recorded["cmd"][-1]) == binary
7079

7180

72-
def test_patch_rpath_skips_when_present(monkeypatch, tmp_path):
81+
def test_patch_rpath_skips_when_present(
82+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
83+
) -> None:
7384
binary = tmp_path / "prog"
7485
binary.write_text("dummy")
7586

7687
monkeypatch.setattr(relocate, "parse_rpath", lambda path: ["$ORIGIN/lib"])
7788

78-
def fail_run(*_args, **_kwargs):
89+
def fail_run(*_args: object, **_kwargs: object) -> None:
7990
raise AssertionError("patchelf should not be invoked")
8091

8192
monkeypatch.setattr(relocate.subprocess, "run", fail_run)
@@ -84,7 +95,9 @@ def fail_run(*_args, **_kwargs):
8495
assert result == "$ORIGIN/lib"
8596

8697

87-
def test_handle_elf_sets_rpath(monkeypatch, tmp_path):
98+
def test_handle_elf_sets_rpath(
99+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
100+
) -> None:
88101
bin_dir = tmp_path / "bin"
89102
lib_dir = tmp_path / "lib"
90103
bin_dir.mkdir()
@@ -95,7 +108,9 @@ def test_handle_elf_sets_rpath(monkeypatch, tmp_path):
95108
resident = lib_dir / "libfoo.so"
96109
resident.write_text("library")
97110

98-
def fake_run(cmd, **kwargs):
111+
def fake_run(
112+
cmd: List[str], **kwargs: object
113+
) -> subprocess.CompletedProcess[bytes]:
99114
if cmd[0] == "ldd":
100115
stdout = f"libfoo.so => {resident} (0x00007)\nlibc.so.6 => /lib/libc.so.6 (0x00007)\n"
101116
return subprocess.CompletedProcess(
@@ -105,9 +120,9 @@ def fake_run(cmd, **kwargs):
105120

106121
monkeypatch.setattr(relocate.subprocess, "run", fake_run)
107122

108-
captured = {}
123+
captured: Dict[str, str] = {}
109124

110-
def fake_patch_rpath(path, relpath):
125+
def fake_patch_rpath(path: str, relpath: str) -> str:
111126
captured["path"] = path
112127
captured["relpath"] = relpath
113128
return relpath
@@ -125,21 +140,27 @@ def fake_patch_rpath(path, relpath):
125140
assert captured["relpath"] == expected_rpath
126141

127142

128-
def test_patch_rpath_failure(monkeypatch, tmp_path):
143+
def test_patch_rpath_failure(
144+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
145+
) -> None:
129146
binary = tmp_path / "prog"
130147
binary.write_text("dummy")
131148

132149
monkeypatch.setattr(relocate, "parse_rpath", lambda path: [])
133150

134-
def fake_run(cmd, **kwargs):
151+
def fake_run(
152+
cmd: List[str], **kwargs: object
153+
) -> subprocess.CompletedProcess[bytes]:
135154
return subprocess.CompletedProcess(cmd, 1, stdout=b"", stderr=b"err")
136155

137156
monkeypatch.setattr(relocate.subprocess, "run", fake_run)
138157

139158
assert relocate.patch_rpath(binary, "$ORIGIN/lib") is False
140159

141160

142-
def test_parse_macho_non_object(monkeypatch, tmp_path):
161+
def test_parse_macho_non_object(
162+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
163+
) -> None:
143164
output = "foo: is not an object file\n"
144165
monkeypatch.setattr(
145166
relocate.subprocess,
@@ -151,7 +172,9 @@ def test_parse_macho_non_object(monkeypatch, tmp_path):
151172
assert relocate.parse_macho(tmp_path / "lib.dylib") is None
152173

153174

154-
def test_handle_macho_copies_when_needed(monkeypatch, tmp_path):
175+
def test_handle_macho_copies_when_needed(
176+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
177+
) -> None:
155178
binary = tmp_path / "bin" / "prog"
156179
binary.parent.mkdir()
157180
binary.write_text("exe")
@@ -178,10 +201,12 @@ def test_handle_macho_copies_when_needed(monkeypatch, tmp_path):
178201
shutil, "copymode", lambda src, dst: copied.setdefault("copymode", (src, dst))
179202
)
180203

181-
recorded = {}
204+
recorded: Dict[str, List[str]] = {}
182205

183-
def fake_run(cmd, **kwargs):
184-
recorded["cmd"] = cmd
206+
def fake_run(
207+
cmd: List[str], **kwargs: object
208+
) -> subprocess.CompletedProcess[bytes]:
209+
recorded.setdefault("cmd", []).extend(cmd)
185210
return subprocess.CompletedProcess(cmd, 0, stdout=b"", stderr=b"")
186211

187212
monkeypatch.setattr(relocate.subprocess, "run", fake_run)
@@ -193,7 +218,9 @@ def fake_run(cmd, **kwargs):
193218
assert recorded["cmd"][0] == "install_name_tool"
194219

195220

196-
def test_handle_macho_rpath_only(monkeypatch, tmp_path):
221+
def test_handle_macho_rpath_only(
222+
monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
223+
) -> None:
197224
binary = tmp_path / "bin" / "prog"
198225
binary.parent.mkdir()
199226
binary.write_text("exe")
@@ -218,7 +245,9 @@ def test_handle_macho_rpath_only(monkeypatch, tmp_path):
218245
monkeypatch.setattr(shutil, "copy", lambda *_args, **_kw: (_args, _kw))
219246
monkeypatch.setattr(shutil, "copymode", lambda *_args, **_kw: (_args, _kw))
220247

221-
def fake_run(cmd, **kwargs):
248+
def fake_run(
249+
cmd: List[str], **kwargs: object
250+
) -> subprocess.CompletedProcess[bytes]:
222251
if cmd[0] == "install_name_tool":
223252
raise AssertionError("install_name_tool should not run in rpath_only mode")
224253
return subprocess.CompletedProcess(cmd, 0, stdout=b"", stderr=b"")

0 commit comments

Comments
 (0)