+cli tests
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
"""Tests for cli.piptool module."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
import pyflowx as px
|
||||
from pyflowx.cli import piptool
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# pip_uninstall
|
||||
# ---------------------------------------------------------------------- #
|
||||
class TestPipUninstall:
|
||||
"""Test pip_uninstall function."""
|
||||
|
||||
def test_pip_uninstall_single_package(self) -> None:
|
||||
"""Should uninstall single package."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
piptool.pip_uninstall(["numpy"])
|
||||
# Should call pip uninstall
|
||||
assert mock_run.called
|
||||
|
||||
def test_pip_uninstall_multiple_packages(self) -> None:
|
||||
"""Should uninstall multiple packages."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
piptool.pip_uninstall(["numpy", "pandas", "scipy"])
|
||||
# Should call pip uninstall
|
||||
assert mock_run.called
|
||||
|
||||
def test_pip_uninstall_with_wildcard(self) -> None:
|
||||
"""Should handle wildcard in package name."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
piptool.pip_uninstall(["numpy*"])
|
||||
assert mock_run.called
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# pip_reinstall
|
||||
# ---------------------------------------------------------------------- #
|
||||
class TestPipReinstall:
|
||||
"""Test pip_reinstall function."""
|
||||
|
||||
def test_pip_reinstall_online(self) -> None:
|
||||
"""Should reinstall packages online."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
piptool.pip_reinstall(["numpy"], offline=False)
|
||||
assert mock_run.called
|
||||
|
||||
def test_pip_reinstall_offline(self) -> None:
|
||||
"""Should reinstall packages offline."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
piptool.pip_reinstall(["numpy"], offline=True)
|
||||
# Should call pip install with offline flags
|
||||
assert mock_run.called
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# pip_download
|
||||
# ---------------------------------------------------------------------- #
|
||||
class TestPipDownload:
|
||||
"""Test pip_download function."""
|
||||
|
||||
def test_pip_download_online(self) -> None:
|
||||
"""Should download packages online."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
piptool.pip_download(["numpy"], offline=False)
|
||||
assert mock_run.called
|
||||
|
||||
def test_pip_download_offline(self) -> None:
|
||||
"""Should download packages offline."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
piptool.pip_download(["numpy"], offline=True)
|
||||
# Should call pip download with offline flags
|
||||
assert mock_run.called
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# pip_freeze
|
||||
# ---------------------------------------------------------------------- #
|
||||
class TestPipFreeze:
|
||||
"""Test pip_freeze function."""
|
||||
|
||||
def test_pip_freeze_creates_file(self, tmp_path: Path) -> None:
|
||||
"""Should create requirements.txt file."""
|
||||
with patch("subprocess.run") as mock_run, patch.object(Path, "cwd", return_value=tmp_path):
|
||||
mock_run.return_value = MagicMock(stdout="numpy==1.0.0\npandas==2.0.0\n", returncode=0)
|
||||
piptool.pip_freeze()
|
||||
# Should create requirements.txt
|
||||
req_file = tmp_path / "requirements.txt"
|
||||
# Note: The actual implementation might write to current directory
|
||||
|
||||
def test_pip_freeze_calls_subprocess(self) -> None:
|
||||
"""Should call pip freeze."""
|
||||
with patch("subprocess.run") as mock_run:
|
||||
mock_run.return_value = MagicMock(stdout="", returncode=0)
|
||||
piptool.pip_freeze()
|
||||
assert mock_run.called
|
||||
call_args = mock_run.call_args[0][0]
|
||||
assert "pip" in call_args
|
||||
assert "freeze" in call_args
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------- #
|
||||
# main function
|
||||
# ---------------------------------------------------------------------- #
|
||||
class TestMain:
|
||||
"""Test main function."""
|
||||
|
||||
def test_main_install_single_package(self) -> None:
|
||||
"""main() should handle install single package."""
|
||||
with patch("sys.argv", ["piptool", "i", "numpy"]), patch.object(px, "run") as mock_run:
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
graph = mock_run.call_args[0][0]
|
||||
specs = graph.all_specs()
|
||||
for spec in specs.values():
|
||||
assert "pip" in spec.cmd
|
||||
assert "install" in spec.cmd
|
||||
assert "numpy" in spec.cmd
|
||||
|
||||
def test_main_install_multiple_packages(self) -> None:
|
||||
"""main() should handle install multiple packages."""
|
||||
with patch("sys.argv", ["piptool", "i", "numpy", "pandas", "scipy"]), patch.object(px, "run") as mock_run:
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
|
||||
def test_main_uninstall_packages(self) -> None:
|
||||
"""main() should handle uninstall packages."""
|
||||
with patch("sys.argv", ["piptool", "u", "numpy"]), patch.object(px, "run") as mock_run, patch.object(
|
||||
piptool, "pip_uninstall"
|
||||
):
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
|
||||
def test_main_reinstall_packages(self) -> None:
|
||||
"""main() should handle reinstall packages."""
|
||||
with patch("sys.argv", ["piptool", "r", "numpy"]), patch.object(px, "run") as mock_run, patch.object(
|
||||
piptool, "pip_reinstall"
|
||||
):
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
|
||||
def test_main_reinstall_offline(self) -> None:
|
||||
"""main() should handle reinstall offline."""
|
||||
with patch("sys.argv", ["piptool", "r", "numpy", "--offline"]), patch.object(
|
||||
px, "run"
|
||||
) as mock_run, patch.object(piptool, "pip_reinstall"):
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
|
||||
def test_main_download_packages(self) -> None:
|
||||
"""main() should handle download packages."""
|
||||
with patch("sys.argv", ["piptool", "d", "numpy"]), patch.object(px, "run") as mock_run, patch.object(
|
||||
piptool, "pip_download"
|
||||
):
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
|
||||
def test_main_download_offline(self) -> None:
|
||||
"""main() should handle download offline."""
|
||||
with patch("sys.argv", ["piptool", "d", "numpy", "--offline"]), patch.object(
|
||||
px, "run"
|
||||
) as mock_run, patch.object(piptool, "pip_download"):
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
|
||||
def test_main_upgrade_pip(self) -> None:
|
||||
"""main() should handle upgrade pip."""
|
||||
with patch("sys.argv", ["piptool", "up"]), patch.object(px, "run") as mock_run:
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
graph = mock_run.call_args[0][0]
|
||||
specs = graph.all_specs()
|
||||
for spec in specs.values():
|
||||
assert "python" in spec.cmd
|
||||
assert "-m" in spec.cmd
|
||||
assert "pip" in spec.cmd
|
||||
assert "install" in spec.cmd
|
||||
assert "--upgrade" in spec.cmd
|
||||
|
||||
def test_main_freeze(self) -> None:
|
||||
"""main() should handle freeze."""
|
||||
with patch("sys.argv", ["piptool", "f"]), patch.object(px, "run") as mock_run, patch.object(
|
||||
piptool, "pip_freeze"
|
||||
):
|
||||
piptool.main()
|
||||
assert mock_run.called
|
||||
|
||||
def test_main_with_no_args_shows_help(self) -> None:
|
||||
"""main() with no args should show help and exit."""
|
||||
with patch("sys.argv", ["piptool"]), pytest.raises(SystemExit) as exc_info:
|
||||
piptool.main()
|
||||
assert exc_info.value.code == 2
|
||||
|
||||
def test_main_creates_task_specs_with_verbose(self) -> None:
|
||||
"""main() should create TaskSpecs with verbose=True."""
|
||||
with patch("sys.argv", ["piptool", "i", "numpy"]), patch.object(px, "run") as mock_run:
|
||||
piptool.main()
|
||||
graph = mock_run.call_args[0][0]
|
||||
specs = graph.all_specs()
|
||||
for spec in specs.values():
|
||||
assert spec.verbose is True
|
||||
|
||||
def test_main_uses_thread_strategy(self) -> None:
|
||||
"""main() should use thread strategy."""
|
||||
with patch("sys.argv", ["piptool", "i", "numpy"]), patch.object(px, "run") as mock_run:
|
||||
piptool.main()
|
||||
assert mock_run.call_args[1]["strategy"] == "thread"
|
||||
Reference in New Issue
Block a user