# 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.
from __future__ import annotations
import json
from functools import partial
import pytest
from meta_package_manager.pool import pool
from meta_package_manager.tables import MANAGERS_COLUMNS
from .conftest import all_manager_ids, unsupported_manager_ids
from .test_cli import CLITableTests, check_manager_selection, managers_table_signals
[docs]
@pytest.fixture
def subcmd():
return "managers"
[docs]
def evaluate_signals(mid, stdout, stderr):
yield from managers_table_signals(mid, stdout, stderr)
check_selection = partial(check_manager_selection, signals=evaluate_signals)
"""Selection assertions reading this subcommand's own signals."""
[docs]
class TestManagers(CLITableTests):
columns_registry = MANAGERS_COLUMNS
columns_test_pair = ("manager_id", "version")
[docs]
@all_manager_ids
def test_all_managers(self, invoke, subcmd, manager_id):
"""Check only the selected manager is listed."""
result = invoke(f"--{manager_id}", "--all-managers", subcmd)
assert result.exit_code == 0
check_selection(
result,
{manager_id},
reference_set=pool.all_manager_ids,
)
[docs]
@unsupported_manager_ids
def test_unsupported_managers(self, invoke, subcmd, manager_id):
"""A manager named by the user is reported whatever its state.
The default view widens to `supported` on an explicit selection, so the row
spelling out why `mpm` cannot use it is the answer the selector asked for.
"""
result = invoke(f"--{manager_id}", subcmd, color=False)
assert result.exit_code == 0
check_selection(result, set())
assert manager_id in result.stdout
[docs]
@pytest.mark.parametrize(
("view_args", "expected_ids"),
(
pytest.param(
(),
lambda: {
mid for mid in pool.default_manager_ids if pool[mid].available
},
id="default-view-is-detected",
),
pytest.param(
("--view", "detected"),
lambda: {
mid for mid in pool.default_manager_ids if pool[mid].available
},
id="detected",
),
pytest.param(
("--view", "supported"),
lambda: set(pool.default_manager_ids),
id="supported",
),
pytest.param(
("--view", "all"),
lambda: set(pool.all_manager_ids),
id="all",
),
),
)
def test_view_widths(self, invoke, subcmd, view_args, expected_ids):
"""Each view reports its own nested slice of the pool."""
result = invoke("--table-format", "json", subcmd, *view_args)
assert result.exit_code == 0
assert set(json.loads(result.stdout)) == expected_ids()
[docs]
def test_all_managers_flag_selects_widest_view(self, invoke, subcmd):
"""The global flag keeps naming the widest view, as `--view all` does."""
result = invoke("--all-managers", "--table-format", "json", subcmd)
assert result.exit_code == 0
assert set(json.loads(result.stdout)) == set(pool.all_manager_ids)
[docs]
def test_default_view_drops_constant_columns(self, invoke, subcmd):
"""The default view leaves out `Supported` and `Executable`.
Both are a ✓ on every detected row. The wider views bring them back.
"""
labels = {spec.id: spec.label for spec, _ in MANAGERS_COLUMNS}
dropped = (labels["supported"], labels["executable"])
detected = invoke(subcmd, color=False)
assert detected.exit_code == 0
assert not any(label in detected.stdout for label in dropped)
for view in ("supported", "all"):
wider = invoke(subcmd, "--view", view, color=False)
assert wider.exit_code == 0
assert all(label in wider.stdout for label in dropped)
[docs]
def test_json_parsing(self, invoke, subcmd):
result = invoke("--table-format", "json", subcmd)
assert result.exit_code == 0
data = json.loads(result.stdout)
assert data
assert isinstance(data, dict)
assert set(data) <= set(pool.default_manager_ids)
for manager_id, info in data.items():
assert isinstance(manager_id, str)
assert isinstance(info, dict)
assert set(info) == {
"available",
"cli_path",
"errors",
"executable",
"fresh",
"id",
"name",
"supported",
"version",
}
assert isinstance(info["available"], bool)
if info["cli_path"] is not None:
assert isinstance(info["cli_path"], str)
assert isinstance(info["errors"], list)
if info["errors"]:
assert all(isinstance(error, str) for error in info["errors"])
assert isinstance(info["executable"], bool)
assert isinstance(info["fresh"], bool)
assert isinstance(info["id"], str)
assert isinstance(info["name"], str)
assert isinstance(info["supported"], bool)
if info["version"] is not None:
assert isinstance(info["version"], str)
assert info["id"] == manager_id
[docs]
def test_managers_stamps_global_timeout(invoke):
"""The `managers` subcommand forwards the global `--timeout` to the pool.
The version probes behind the table's detection columns fire in the pool's warm-up
round, right after selection, so the pool must bind the timeout on each candidate
beforehand. An unstamped instance falls back to the 120-second read-only default,
letting a wedged binary hold the whole round for that long.
"""
original = pool["pip"].timeout
try:
result = invoke("--timeout", "987", "managers")
assert result.exit_code == 0
assert pool["pip"].timeout == 987
finally:
pool["pip"].timeout = original