# Copyright Kevin Deldycke <[email protected]> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""mise output-parsing and CLI-construction tests.
These tests stub `run_cli` and exercise the pure-Python branches of the
`Mise` manager. They do not invoke the real `mise` binary.
"""
from __future__ import annotations
import pytest
from meta_package_manager.managers.mise import Mise
[docs]
@pytest.fixture
def manager():
return Mise()
[docs]
def test_installed_yields_packages(manager, stub_run_cli):
output = (
'{"node": [{"version": "20.10.0", '
'"install_path": "/home/me/.local/share/mise/installs/node/20.10.0"}]}'
)
stub_run_cli(manager, output)
packages = list(manager.installed)
assert len(packages) == 1
assert packages[0].id == "node"
assert str(packages[0].installed_version) == "20.10.0"
[docs]
@pytest.mark.parametrize("output", ("", "{}"))
def test_installed_handles_empty(manager, stub_run_cli, output):
stub_run_cli(manager, output)
assert list(manager.installed) == []
[docs]
def test_installed_yields_one_package_per_version(manager, stub_run_cli):
output = (
'{"node": ['
'{"version": "18.20.0", "install_path": "/x/node/18.20.0"},'
'{"version": "20.10.0", "install_path": "/x/node/20.10.0"}'
"]}"
)
stub_run_cli(manager, output)
packages = list(manager.installed)
assert len(packages) == 2
assert {p.id for p in packages} == {"node"}
assert {str(p.installed_version) for p in packages} == {"18.20.0", "20.10.0"}
[docs]
def test_installed_preserves_backend_prefix(manager, stub_run_cli):
"""Backend-prefixed IDs like `pipx:ruff` round-trip without rewriting."""
output = (
'{"pipx:ruff": [{"version": "0.6.9", "install_path": "/x/pipx-ruff/0.6.9"}]}'
)
stub_run_cli(manager, output)
packages = list(manager.installed)
assert len(packages) == 1
assert packages[0].id == "pipx:ruff"
[docs]
def test_outdated_yields_upgrades(manager, stub_run_cli):
output = '{"node": {"requested": "20", "current": "20.0.0", "latest": "20.10.0"}}'
stub_run_cli(manager, output)
packages = list(manager.outdated)
assert len(packages) == 1
assert packages[0].id == "node"
assert str(packages[0].installed_version) == "20.0.0"
assert str(packages[0].latest_version) == "20.10.0"
[docs]
@pytest.mark.parametrize("output", ("", "{}"))
def test_outdated_handles_empty(manager, stub_run_cli, output):
stub_run_cli(manager, output)
assert list(manager.outdated) == []
[docs]
def test_search_parses_table(manager, stub_run_cli):
output = (
"node Node.js JavaScript runtime\n"
"node-build Compile and install Node.js\n"
"nodejs alias for node\n"
)
stub_run_cli(manager, output)
packages = list(manager.search("node", extended=False, exact=False))
assert [p.id for p in packages] == ["node", "node-build", "nodejs"]
assert packages[0].description == "Node.js JavaScript runtime"
assert packages[1].description == "Compile and install Node.js"
[docs]
def test_search_keeps_descriptions_with_inner_spaces(manager, stub_run_cli):
"""A description with single-space-separated words is preserved intact.
The regex only treats the run of 2+ spaces between columns as a delimiter.
"""
output = "ripgrep line-oriented search tool\n"
stub_run_cli(manager, output)
packages = list(manager.search("rg", extended=False, exact=False))
assert len(packages) == 1
assert packages[0].description == "line-oriented search tool"
[docs]
@pytest.mark.parametrize(
("version", "expected_spec"),
(
(None, "node"),
("20", "node@20"),
("20.10.0", "[email protected]"),
),
)
def test_install_builds_spec(manager, capture_run_cli, version, expected_spec):
captured = capture_run_cli(manager)
manager.install("node", version=version)
assert captured == [("install", expected_spec)]
[docs]
def test_upgrade_all_cli_omits_target(manager):
cli = manager.upgrade_all_cli()
assert "upgrade" in cli
# No tool argument tacked on the end.
assert cli[-1] == "upgrade"
[docs]
@pytest.mark.parametrize(
("version", "expected_spec"),
(
(None, "node"),
("20", "node@20"),
),
)
def test_upgrade_one_cli_builds_spec(manager, version, expected_spec):
cli = manager.upgrade_one_cli("node", version=version)
assert "upgrade" in cli
assert cli[-1] == expected_spec
[docs]
@pytest.mark.parametrize(
("operation", "args", "expected"),
(
# `--all` matches the "remove the package, full stop" contract of mpm,
# even when `mise` holds several versions of the same tool.
pytest.param("remove", ("node",), ("uninstall", "--all", "node"), id="remove"),
pytest.param("sync", (), ("plugins", "update"), id="sync"),
pytest.param("cleanup", (), ("cache", "clear"), id="cleanup"),
),
)
def test_operation_command(manager, capture_run_cli, operation, args, expected):
captured = capture_run_cli(manager)
getattr(manager, operation)(*args)
assert captured == [expected]