Mark stable commit / test-unit (push) Has been cancelled
Mark stable commit / test-integration (push) Has been cancelled
Mark stable commit / test-env-virtual (push) Has been cancelled
Mark stable commit / test-env-nix (push) Has been cancelled
Mark stable commit / test-e2e (push) Has been cancelled
Mark stable commit / test-virgin-user (push) Has been cancelled
Mark stable commit / test-virgin-root (push) Has been cancelled
Mark stable commit / codesniffer-shellcheck (push) Has been cancelled
Mark stable commit / codesniffer-ruff (push) Has been cancelled
Mark stable commit / mark-stable (push) Has been cancelled
216 lines
6.8 KiB
Python
216 lines
6.8 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Unit tests for pkgmgr.cli.commands.repos
|
|
|
|
We focus on the behaviour of:
|
|
|
|
- _resolve_repository_directory(...)
|
|
- handle_repos_command(...) for the "path" and "shell" commands
|
|
|
|
Goals:
|
|
|
|
* "path" should:
|
|
- print repo["directory"] if present
|
|
- fall back to get_repo_dir(ctx.repositories_base_dir, repo) otherwise
|
|
- handle "no selected repos" gracefully
|
|
|
|
* "shell" should:
|
|
- resolve the directory via _resolve_repository_directory(...)
|
|
- call run_command(...) with cwd set to the resolved directory
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
import unittest
|
|
from contextlib import redirect_stdout
|
|
from types import SimpleNamespace
|
|
from typing import Any, Dict, List
|
|
from unittest.mock import patch
|
|
|
|
from pkgmgr.cli.context import CLIContext
|
|
from pkgmgr.cli.commands.repos import handle_repos_command
|
|
|
|
|
|
Repository = Dict[str, Any]
|
|
|
|
|
|
class TestReposCommand(unittest.TestCase):
|
|
def _make_ctx(self, repositories: List[Repository]) -> CLIContext:
|
|
"""
|
|
Helper to build a minimal CLIContext for tests.
|
|
"""
|
|
return CLIContext(
|
|
config_merged={},
|
|
repositories_base_dir="/base/dir",
|
|
all_repositories=repositories,
|
|
binaries_dir="/bin/dir",
|
|
user_config_path="~/.config/pkgmgr/config.yaml",
|
|
)
|
|
|
|
# ------------------------------------------------------------------
|
|
# "path" command tests
|
|
# ------------------------------------------------------------------
|
|
|
|
def test_path_uses_explicit_directory_if_present(self) -> None:
|
|
"""
|
|
When repository["directory"] is present, handle_repos_command("path")
|
|
should print this value directly without calling get_repo_dir().
|
|
"""
|
|
repos: List[Repository] = [
|
|
{
|
|
"provider": "github.com",
|
|
"account": "kevinveenbirkenbach",
|
|
"repository": "package-manager",
|
|
"directory": "/custom/path/pkgmgr",
|
|
}
|
|
]
|
|
ctx = self._make_ctx(repos)
|
|
|
|
args = SimpleNamespace(
|
|
command="path",
|
|
preview=False,
|
|
list=False,
|
|
system=False,
|
|
extra_args=[],
|
|
)
|
|
|
|
buf = io.StringIO()
|
|
|
|
with patch(
|
|
"pkgmgr.cli.commands.repos.get_repo_dir"
|
|
) as mock_get_repo_dir, redirect_stdout(buf):
|
|
handle_repos_command(args, ctx, selected=repos)
|
|
|
|
output = buf.getvalue().strip().splitlines()
|
|
self.assertIn("/custom/path/pkgmgr", output)
|
|
mock_get_repo_dir.assert_not_called()
|
|
|
|
def test_path_falls_back_to_get_repo_dir_if_directory_missing(self) -> None:
|
|
"""
|
|
When repository["directory"] is missing, handle_repos_command("path")
|
|
should call get_repo_dir(ctx.repositories_base_dir, repo) and print
|
|
the returned value.
|
|
"""
|
|
repos: List[Repository] = [
|
|
{
|
|
"provider": "github.com",
|
|
"account": "kevinveenbirkenbach",
|
|
"repository": "package-manager",
|
|
}
|
|
]
|
|
ctx = self._make_ctx(repos)
|
|
|
|
args = SimpleNamespace(
|
|
command="path",
|
|
preview=False,
|
|
list=False,
|
|
system=False,
|
|
extra_args=[],
|
|
)
|
|
|
|
buf = io.StringIO()
|
|
|
|
with patch(
|
|
"pkgmgr.cli.commands.repos.get_repo_dir",
|
|
return_value="/resolved/from/get_repo_dir",
|
|
) as mock_get_repo_dir, redirect_stdout(buf):
|
|
handle_repos_command(args, ctx, selected=repos)
|
|
|
|
output = buf.getvalue().strip().splitlines()
|
|
self.assertIn("/resolved/from/get_repo_dir", output)
|
|
mock_get_repo_dir.assert_called_once_with("/base/dir", repos[0])
|
|
|
|
def test_path_with_no_selected_repos_prints_message(self) -> None:
|
|
"""
|
|
When 'selected' is empty, the 'path' command should print a friendly
|
|
message and not raise.
|
|
"""
|
|
ctx = self._make_ctx(repositories=[])
|
|
args = SimpleNamespace(
|
|
command="path",
|
|
preview=False,
|
|
list=False,
|
|
system=False,
|
|
extra_args=[],
|
|
)
|
|
|
|
buf = io.StringIO()
|
|
with redirect_stdout(buf):
|
|
handle_repos_command(args, ctx, selected=[])
|
|
|
|
output = buf.getvalue()
|
|
self.assertIn("No repositories selected for path", output)
|
|
|
|
# ------------------------------------------------------------------
|
|
# "shell" command tests
|
|
# ------------------------------------------------------------------
|
|
|
|
def test_shell_resolves_directory_and_calls_run_command(self) -> None:
|
|
"""
|
|
'shell' should resolve the repository directory and pass it as cwd
|
|
to run_command(), along with the full shell command string.
|
|
"""
|
|
repos: List[Repository] = [
|
|
{
|
|
"provider": "github.com",
|
|
"account": "kevinveenbirkenbach",
|
|
"repository": "package-manager",
|
|
}
|
|
]
|
|
ctx = self._make_ctx(repos)
|
|
|
|
args = SimpleNamespace(
|
|
command="shell",
|
|
preview=False,
|
|
shell_command=["echo", "hello"],
|
|
)
|
|
|
|
with patch(
|
|
"pkgmgr.cli.commands.repos.get_repo_dir",
|
|
return_value="/resolved/for/shell",
|
|
) as mock_get_repo_dir, patch(
|
|
"pkgmgr.cli.commands.repos.run_command"
|
|
) as mock_run_command:
|
|
buf = io.StringIO()
|
|
with redirect_stdout(buf):
|
|
handle_repos_command(args, ctx, selected=repos)
|
|
|
|
# _resolve_repository_directory should have called get_repo_dir
|
|
mock_get_repo_dir.assert_called_once_with("/base/dir", repos[0])
|
|
|
|
# run_command should be invoked with cwd set to the resolved path
|
|
mock_run_command.assert_called_once()
|
|
called_args, called_kwargs = mock_run_command.call_args
|
|
|
|
self.assertEqual("echo hello", called_args[0]) # command string
|
|
self.assertEqual("/resolved/for/shell", called_kwargs["cwd"])
|
|
self.assertFalse(called_kwargs["preview"])
|
|
|
|
def test_shell_without_command_exits_with_error(self) -> None:
|
|
"""
|
|
'shell' without -c/--command should print an error and exit with code 2.
|
|
"""
|
|
repos: List[Repository] = []
|
|
ctx = self._make_ctx(repos)
|
|
|
|
args = SimpleNamespace(
|
|
command="shell",
|
|
preview=False,
|
|
shell_command=[],
|
|
)
|
|
|
|
buf = io.StringIO()
|
|
with redirect_stdout(buf), self.assertRaises(SystemExit) as cm:
|
|
handle_repos_command(args, ctx, selected=repos)
|
|
|
|
self.assertEqual(cm.exception.code, 2)
|
|
output = buf.getvalue()
|
|
self.assertIn("'shell' requires a command via -c/--command", output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|