|
1 | 1 | """Tests for flexaidds.__main__ – CLI entry point. |
2 | 2 |
|
3 | | -Covers build_parser() and the two output branches of main(): |
| 3 | +Covers build_parser() and the output branches of main(): |
4 | 4 | - human-readable summary (default) |
5 | 5 | - machine-readable JSON (--json flag) |
| 6 | + - CSV export (--csv flag) |
| 7 | + - top-N filtering (--top flag) |
| 8 | + - version display (--version flag) |
6 | 9 | """ |
7 | 10 |
|
8 | 11 | from __future__ import annotations |
@@ -196,3 +199,110 @@ def test_json_source_dir_is_string(self, tmp_path, monkeypatch, capsys): |
196 | 199 | main() |
197 | 200 | parsed = json.loads(capsys.readouterr().out) |
198 | 201 | assert isinstance(parsed["source_dir"], str) |
| 202 | + |
| 203 | + |
| 204 | +# =========================================================================== |
| 205 | +# --version flag |
| 206 | +# =========================================================================== |
| 207 | + |
| 208 | +class TestMainVersionOutput: |
| 209 | + def test_version_flag_prints_version(self, capsys): |
| 210 | + from flexaidds.__version__ import __version__ |
| 211 | + parser = build_parser() |
| 212 | + with pytest.raises(SystemExit) as exc_info: |
| 213 | + parser.parse_args(["--version"]) |
| 214 | + assert exc_info.value.code == 0 |
| 215 | + out = capsys.readouterr().out |
| 216 | + assert __version__ in out |
| 217 | + |
| 218 | + def test_short_version_flag(self, capsys): |
| 219 | + from flexaidds.__version__ import __version__ |
| 220 | + parser = build_parser() |
| 221 | + with pytest.raises(SystemExit) as exc_info: |
| 222 | + parser.parse_args(["-V"]) |
| 223 | + assert exc_info.value.code == 0 |
| 224 | + out = capsys.readouterr().out |
| 225 | + assert __version__ in out |
| 226 | + |
| 227 | + |
| 228 | +# =========================================================================== |
| 229 | +# main() – CSV output |
| 230 | +# =========================================================================== |
| 231 | + |
| 232 | +class TestMainCsvOutput: |
| 233 | + def _make_dir(self, tmp_path: Path) -> Path: |
| 234 | + _write_pdb( |
| 235 | + tmp_path / "mode_1_pose_1.pdb", |
| 236 | + ["binding_mode = 1", "pose_rank = 1", "CF = -42.5", |
| 237 | + "free_energy = -41.0", "temperature = 300.0"], |
| 238 | + ) |
| 239 | + _write_pdb( |
| 240 | + tmp_path / "mode_2_pose_1.pdb", |
| 241 | + ["binding_mode = 2", "pose_rank = 1", "CF = -35.0", |
| 242 | + "temperature = 300.0"], |
| 243 | + ) |
| 244 | + return tmp_path |
| 245 | + |
| 246 | + def test_returns_zero(self, tmp_path, monkeypatch): |
| 247 | + d = self._make_dir(tmp_path) |
| 248 | + csv_out = tmp_path / "out.csv" |
| 249 | + monkeypatch.setattr(sys, "argv", ["flexaidds", str(d), "--csv", str(csv_out)]) |
| 250 | + assert main() == 0 |
| 251 | + |
| 252 | + def test_creates_csv_file(self, tmp_path, monkeypatch): |
| 253 | + d = self._make_dir(tmp_path) |
| 254 | + csv_out = tmp_path / "out.csv" |
| 255 | + monkeypatch.setattr(sys, "argv", ["flexaidds", str(d), "--csv", str(csv_out)]) |
| 256 | + main() |
| 257 | + assert csv_out.exists() |
| 258 | + |
| 259 | + def test_csv_has_header_and_rows(self, tmp_path, monkeypatch): |
| 260 | + d = self._make_dir(tmp_path) |
| 261 | + csv_out = tmp_path / "out.csv" |
| 262 | + monkeypatch.setattr(sys, "argv", ["flexaidds", str(d), "--csv", str(csv_out)]) |
| 263 | + main() |
| 264 | + lines = csv_out.read_text().strip().splitlines() |
| 265 | + assert len(lines) == 3 # header + 2 modes |
| 266 | + assert "mode_id" in lines[0] |
| 267 | + |
| 268 | + def test_csv_confirmation_message(self, tmp_path, monkeypatch, capsys): |
| 269 | + d = self._make_dir(tmp_path) |
| 270 | + csv_out = tmp_path / "out.csv" |
| 271 | + monkeypatch.setattr(sys, "argv", ["flexaidds", str(d), "--csv", str(csv_out)]) |
| 272 | + main() |
| 273 | + out = capsys.readouterr().out |
| 274 | + assert "2" in out # n_modes in confirmation |
| 275 | + assert str(csv_out) in out |
| 276 | + |
| 277 | + |
| 278 | +# =========================================================================== |
| 279 | +# main() – --top flag |
| 280 | +# =========================================================================== |
| 281 | + |
| 282 | +class TestMainTopFlag: |
| 283 | + def _make_dir(self, tmp_path: Path) -> Path: |
| 284 | + for i in range(1, 4): |
| 285 | + _write_pdb( |
| 286 | + tmp_path / f"mode_{i}_pose_1.pdb", |
| 287 | + [f"binding_mode = {i}", "pose_rank = 1", |
| 288 | + f"CF = {-40.0 + i}", f"free_energy = {-39.0 + i}", |
| 289 | + "temperature = 300.0"], |
| 290 | + ) |
| 291 | + return tmp_path |
| 292 | + |
| 293 | + def test_top_limits_table_rows(self, tmp_path, monkeypatch, capsys): |
| 294 | + d = self._make_dir(tmp_path) |
| 295 | + monkeypatch.setattr(sys, "argv", ["flexaidds", str(d), "--top", "1"]) |
| 296 | + main() |
| 297 | + out = capsys.readouterr().out |
| 298 | + assert "Binding modes: 3" in out |
| 299 | + |
| 300 | + def test_top_default_is_none(self, tmp_path): |
| 301 | + parser = build_parser() |
| 302 | + args = parser.parse_args([str(tmp_path)]) |
| 303 | + assert args.top is None |
| 304 | + |
| 305 | + def test_top_parsed_as_int(self, tmp_path): |
| 306 | + parser = build_parser() |
| 307 | + args = parser.parse_args([str(tmp_path), "--top", "5"]) |
| 308 | + assert args.top == 5 |
0 commit comments