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

1from hashlib import sha256 

2from typing import Final 

3from pathlib import Path 

4 

5from iso_freeze import iso_freeze 

6from iso_freeze.iso_freeze import PyPackage 

7 

8TEST_TOML: Final[Path] = Path(Path(__file__).parent.resolve(), "test_pyproject.toml") 

9 

10 

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 

28 

29 

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"] 

34 

35 

36def test_virtualenv_deps(): 

37 """Test whether the correct list of requirements with optional dependency is loaded. 

38 

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"] 

45 

46 

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"] 

53 

54 

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 

157 

158 

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 ) 

183 

184 

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 

212 

213 

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 ) 

237 

238 

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 

306 

307 

308 

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