Coverage for tests/test_iso_freeze.py: 100%
84 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-25 23:13 +0200
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-25 23:13 +0200
1from hashlib import sha256
2from typing import Final
3from pathlib import Path
5from iso_freeze import iso_freeze
6from iso_freeze.iso_freeze import PyPackage
8TEST_TOML: Final[Path] = Path(Path(__file__).parent.resolve(), "test_pyproject.toml")
11def test_validate_pip_version(mocker):
12 """Test whether pip version is validated correctly."""
13 mocked_pip_version_output_1 = "pip 22.2 from /funny/path/pip (python 3.9)"
14 mocker.patch("subprocess.check_output", return_value=mocked_pip_version_output_1)
15 assert iso_freeze.validate_pip_version(Path("python3")) == True
16 mocked_pip_version_output_2 = "pip 22.1 from /funny/path/pip (python 3.9)"
17 mocker.patch("subprocess.check_output", return_value=mocked_pip_version_output_2)
18 assert iso_freeze.validate_pip_version(Path("python3")) == False
19 mocked_pip_version_output_3 = "pip 23.1 from /funny/path/pip (python 3.10)"
20 mocker.patch("subprocess.check_output", return_value=mocked_pip_version_output_3)
21 assert iso_freeze.validate_pip_version(Path("python3")) == True
22 mocked_pip_version_output_4 = "pip 20.1.3 from /funny/path/pip (python 3.8)"
23 mocker.patch("subprocess.check_output", return_value=mocked_pip_version_output_4)
24 assert iso_freeze.validate_pip_version(Path("python3")) == False
25 mocked_pip_version_output_5 = "pip 34.2.9 from /funny/path/pip (python 3.15)"
26 mocker.patch("subprocess.check_output", return_value=mocked_pip_version_output_5)
27 assert iso_freeze.validate_pip_version(Path("python3")) == True
30def test_dev_deps():
31 """Test whether the correct list of requirements with optional dependency is loaded."""
32 dev_deps = iso_freeze.read_toml(toml_file=TEST_TOML, optional_dependency="dev")
33 assert dev_deps == ["tomli", "pytest", "pytest-mock"]
36def test_virtualenv_deps():
37 """Test whether the correct list of requirements with optional dependency is loaded.
39 Using a different optional dependency.
40 """
41 virtualenv_deps = iso_freeze.read_toml(
42 toml_file=TEST_TOML, optional_dependency="virtualenv"
43 )
44 assert virtualenv_deps == ["tomli", "virtualenv"]
47def test_base_requirements():
48 """Test whether the correct list of base requirements is loaded."""
49 base_requirements = iso_freeze.read_toml(
50 toml_file=TEST_TOML, optional_dependency=None
51 )
52 assert base_requirements == ["tomli"]
55def test_build_pip_report_command(mocker):
56 """Test whether pip command is build correctly."""
57 # We don't want to make a subprocess call for this test
58 mocker.patch("iso_freeze.iso_freeze.run_pip")
59 # First test: requirements file
60 pip_report_command_1 = iso_freeze.build_pip_report_command(
61 python_exec=Path("python3"),
62 toml_dependencies=None,
63 requirements_in=Path("requirements.in"),
64 pip_args=None,
65 )
66 expected_pip_report_command_1 = [
67 "env",
68 "PIP_REQUIRE_VIRTUALENV=false",
69 Path("python3"),
70 "-m",
71 "pip",
72 "install",
73 "-q",
74 "--dry-run",
75 "--ignore-installed",
76 "--report",
77 "-",
78 "-r",
79 Path("requirements.in"),
80 ]
81 assert pip_report_command_1 == expected_pip_report_command_1
82 # Second test: TOML dependencies
83 pip_report_command_2 = iso_freeze.build_pip_report_command(
84 python_exec=Path("python3"),
85 toml_dependencies=["pytest", "pytest-mock"],
86 requirements_in=None,
87 pip_args=None,
88 )
89 expected_pip_report_command_2 = [
90 "env",
91 "PIP_REQUIRE_VIRTUALENV=false",
92 Path("python3"),
93 "-m",
94 "pip",
95 "install",
96 "-q",
97 "--dry-run",
98 "--ignore-installed",
99 "--report",
100 "-",
101 "pytest",
102 "pytest-mock",
103 ]
104 assert pip_report_command_2 == expected_pip_report_command_2
105 # Third test: TOML dependencies with pip-args
106 pip_report_command_3 = iso_freeze.build_pip_report_command(
107 python_exec=Path("python3"),
108 toml_dependencies=["pytest", "pytest-mock"],
109 requirements_in=None,
110 pip_args=["--upgrade-strategy", "eager", "--require-hashes"],
111 )
112 expected_pip_report_command_3 = [
113 "env",
114 "PIP_REQUIRE_VIRTUALENV=false",
115 Path("python3"),
116 "-m",
117 "pip",
118 "install",
119 "--upgrade-strategy",
120 "eager",
121 "--require-hashes",
122 "-q",
123 "--dry-run",
124 "--ignore-installed",
125 "--report",
126 "-",
127 "pytest",
128 "pytest-mock",
129 ]
130 assert pip_report_command_3 == expected_pip_report_command_3
131 # Fourth test: requirements file with pip-args
132 pip_report_command_4 = iso_freeze.build_pip_report_command(
133 python_exec=Path("python3"),
134 toml_dependencies=None,
135 requirements_in=Path("requirements.in"),
136 pip_args=["--upgrade-strategy", "eager", "--require-hashes"],
137 )
138 expected_pip_report_command_4 = [
139 "env",
140 "PIP_REQUIRE_VIRTUALENV=false",
141 Path("python3"),
142 "-m",
143 "pip",
144 "install",
145 "--upgrade-strategy",
146 "eager",
147 "--require-hashes",
148 "-q",
149 "--dry-run",
150 "--ignore-installed",
151 "--report",
152 "-",
153 "-r",
154 Path("requirements.in"),
155 ]
156 assert pip_report_command_4 == expected_pip_report_command_4
159def test_remove_additional_packages(mocker):
160 """Test if additional packages are properly detected and removed."""
161 mocker.patch("iso_freeze.iso_freeze.run_pip")
162 mocked_pip_list_output = [
163 PyPackage(name="tomli", version="2.0.1", requested=False),
164 # Two packages not in mocked pip report output
165 PyPackage(name="pip", version="22.2", requested=False),
166 PyPackage(name="cowsay", version="5.0", requested=False),
167 ]
168 mocked_pip_report_output = [
169 PyPackage(name="tomli", version="2.0.1", requested=True),
170 # One package not in mocked pip list output
171 PyPackage(name="pyjokes", version="0.6.0", requested=True),
172 ]
173 iso_freeze.remove_additional_packages(
174 installed_packages=mocked_pip_list_output,
175 to_install=mocked_pip_report_output,
176 python_exec=Path("python3"),
177 )
178 # pip should not be removed, cowsay should
179 iso_freeze.run_pip.assert_called_with(
180 command=[Path("python3"), "-m", "pip", "uninstall", "-y", "cowsay"],
181 check_output=False,
182 )
185def test_get_installed_packages(mocker):
186 """Test if pip list output correctly parsed."""
187 mocker.patch("iso_freeze.iso_freeze.run_pip")
188 mocked_pip_list_output = [
189 {"name": "attrs", "version": "21.4.0"},
190 {"name": "iniconfig", "version": "1.1.1"},
191 {
192 "name": "iso-freeze",
193 "version": "0.0.10",
194 "editable_project_location": "/Users/user/python_projects/iso-freeze",
195 },
196 {"name": "packaging", "version": "21.3"},
197 {"name": "pip", "version": "22.2"},
198 {"name": "pluggy", "version": "1.0.0"},
199 ]
200 # TODO: Hashes?
201 expected_output = [
202 PyPackage(name="attrs", version="21.4.0", requested=False),
203 PyPackage(name="iniconfig", version="1.1.1", requested=False),
204 PyPackage(name="iso-freeze", version="0.0.10", requested=False),
205 PyPackage(name="packaging", version="21.3", requested=False),
206 PyPackage(name="pip", version="22.2", requested=False),
207 PyPackage(name="pluggy", version="1.0.0", requested=False),
208 ]
209 mocker.patch("json.loads", return_value=mocked_pip_list_output)
210 actual_output = iso_freeze.get_installed_packages(python_exec=Path("python3"))
211 assert actual_output == expected_output
214def test_install_pip_report_output(mocker):
215 """Test if pip report --install output is properly passed to pip install."""
216 mocker.patch("iso_freeze.iso_freeze.run_pip")
217 mocked_pip_report_output = [
218 PyPackage(name="tomli", version="2.0.1", requested=True),
219 PyPackage(name="pyjokes", version="0.6.0", requested=True),
220 ]
221 iso_freeze.install_pip_report_output(
222 to_install=mocked_pip_report_output,
223 python_exec=Path("python3"),
224 )
225 iso_freeze.run_pip.assert_called_with(
226 command=[
227 Path("python3"),
228 "-m",
229 "pip",
230 "install",
231 "--upgrade",
232 "tomli==2.0.1",
233 "pyjokes==0.6.0",
234 ],
235 check_output=False,
236 )
239def test_get_dependencies(mocker):
240 """Test if pip install --report is correctly captured."""
241 mocker.patch("iso_freeze.iso_freeze.run_pip")
242 mocked_pip_report_output = {
243 "environment": {},
244 "install": [
245 {
246 "download_info": {
247 "archive_info": {"hash": "sha256=some_hash"},
248 "url": "some_url",
249 },
250 "is_direct": False,
251 "metadata": {
252 "author_email": "Someone" "<someone@email.com>",
253 "classifier": ["License :: OSI Approved :: MIT "],
254 "description": "",
255 "keywords": ["something"],
256 "metadata_version": "2.1",
257 "name": "cool_package",
258 "project_url": [
259 "Homepage, " "https://github.com/",
260 ],
261 "requires_python": ">=3.7",
262 "summary": "A cool package",
263 "version": "2.0.1",
264 },
265 "requested": True,
266 }
267 ],
268 "pip_version": "22.2",
269 "version": "0",
270 }
271 expected_result = [
272 PyPackage(
273 name="cool_package",
274 version="2.0.1",
275 requested=True,
276 hash="sha256:some_hash",
277 )
278 ]
279 mocker.patch("json.loads", return_value=mocked_pip_report_output)
280 mocked_pip_report_command = [
281 "env",
282 "PIP_REQUIRE_VIRTUALENV=false",
283 Path("python3"),
284 "-m",
285 "pip",
286 "install",
287 "-q",
288 "--dry-run",
289 "--ignore-installed",
290 "--report",
291 "-",
292 "cowsay",
293 ]
294 actual_result = iso_freeze.get_dependencies(mocked_pip_report_command)
295 assert actual_result == expected_result
296 mocked_pip_report_output_no_install = {
297 "environment": {},
298 "install": [],
299 "pip_version": "22.2",
300 "version": "0",
301 }
302 mocker.patch("json.loads", return_value=mocked_pip_report_output_no_install)
303 expected_result = None
304 actual_result = iso_freeze.get_dependencies(mocked_pip_report_command)
305 assert actual_result == expected_result
309def test_build_reqirements_file_contents():
310 """Test if requirements file contents are correctly build."""
311 mocked_dependencies = [
312 PyPackage(name="tomli", version="2.0.1", requested=True, hash="sha256:1234"),
313 PyPackage(name="pyjokes", version="0.6.0", requested=False, hash="sha256:5678"),
314 ]
315 expected_output_no_hashes = [
316 "# Top level requirements",
317 "tomli==2.0.1",
318 "# Dependencies of top level requirements",
319 "pyjokes==0.6.0",
320 ]
321 actual_output_no_hashes = iso_freeze.build_reqirements_file_contents(dependencies=mocked_dependencies, hashes=False)
322 assert expected_output_no_hashes == actual_output_no_hashes
323 expected_output_hashes = [
324 "# Top level requirements",
325 "tomli==2.0.1 \\\n"
326 " --hash=sha256:1234",
327 "# Dependencies of top level requirements",
328 "pyjokes==0.6.0 \\\n"
329 " --hash=sha256:5678"
330 ]
331 actual_output_hashes = iso_freeze.build_reqirements_file_contents(dependencies=mocked_dependencies, hashes=True)
332 assert expected_output_hashes == actual_output_hashes