diff --git a/pipconf/cli.py b/pipconf/cli.py index 3000a38..e0e682f 100644 --- a/pipconf/cli.py +++ b/pipconf/cli.py @@ -5,7 +5,7 @@ from rich.panel import Panel from rich.padding import Padding from pipconf.configs import PipConfigs -from pipconf.consts import PADDING, ExitCodes, Chars, HelpPanels +from pipconf.consts import PADDING, PADDING_LIST, ExitCodes, Chars, HelpPanels from pipconf import __help__ @@ -38,12 +38,7 @@ def list(): console.print( Padding( '\n'.join(lines), - ( - 0, - 0, - 1, - 1, - ), + PADDING_LIST, ) ) @@ -69,7 +64,9 @@ def current(): @app.command(rich_help_panel=HelpPanels.DISPLAY) -def show(name: Annotated[Optional[str], Argument()] = None, local: bool = False): +def show( + name: Annotated[Optional[str], Argument()] = None, local: bool = False +): """Shows a config file content""" try: if local: diff --git a/pipconf/configs.py b/pipconf/configs.py index 0683c08..8e7d09c 100644 --- a/pipconf/configs.py +++ b/pipconf/configs.py @@ -76,5 +76,4 @@ def create(self, path: Path): def show(self, path: Path) -> str: if not path.exists(): raise EnvironmentError(f'The file {path} does not exist!') - with open(path, 'r') as file: - return file.read() + return path.read_text() diff --git a/pipconf/consts.py b/pipconf/consts.py index 3214dec..4802eda 100644 --- a/pipconf/consts.py +++ b/pipconf/consts.py @@ -3,6 +3,11 @@ 1, ) +PADDING_LIST = ( + 1, + 1, +) + class Chars: FILLED_CIRCLE = b'\xe2\x97\x8f' diff --git a/pyproject.toml b/pyproject.toml index 69d33e0..1a79f7b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,9 +48,9 @@ quote-style = "single" docstring-code-format = true [tool.taskipy.tasks] -tests = { cmd = "pytest", help = "Runs all unit tests" } +tests = { cmd = "pytest -vvv", help = "Runs all unit tests" } lint = { cmd = "ruff format && ruff check --fix", help = "Format and lint the code" } -security = { cmd = "bandit -c pyproject.toml -r fastrpa", help = "Check security issues on the code" } +security = { cmd = "bandit -c pyproject.toml -r pipconf", help = "Check security issues on the code" } check = { cmd = "ruff format --check && ruff check && mypy .", help = "Check code issues" } [build-system] diff --git a/tests/test_configs.py b/tests/test_configs.py index 3bb2433..7313650 100644 --- a/tests/test_configs.py +++ b/tests/test_configs.py @@ -1,6 +1,6 @@ from pipconf.configs import PipConfigs from unittest.mock import MagicMock, patch -from pytest import raises +from pytest import mark, raises from pathlib import Path @@ -71,3 +71,95 @@ def test_local(): def test_available_configs_empty(): with raises(EnvironmentError): PipConfigs().available_configs + + +@patch('pipconf.configs.Path.home', HOME_MOCK) +@patch('pipconf.configs.Path.exists', MagicMock(return_value=True)) +@patch('pipconf.configs.Path.iterdir', MagicMock(return_value=[SOME_PATH])) +@patch('pipconf.configs.Path.is_symlink', MagicMock(return_value=True)) +def test_available_configs_empty_cause_of_symlinks(): + with raises(EnvironmentError): + PipConfigs().available_configs + + +@patch('pipconf.configs.Path.home', HOME_MOCK) +@patch('pipconf.configs.Path.exists', MagicMock(return_value=True)) +@patch('pipconf.configs.Path.iterdir', MagicMock(return_value=[SOME_PATH])) +@patch('pipconf.configs.Path.is_symlink', MagicMock(return_value=False)) +def test_available_configs(): + configs = PipConfigs() + assert configs.available_configs == [SOME_PATH] + + +@mark.parametrize( + ('input_name', 'expected_return'), + [ + ('file', Path(HOME_DIRECTORY, '.pip/file.conf')), + ('file.conf', Path(HOME_DIRECTORY, '.pip/file.conf')), + ], +) +@patch('pipconf.configs.Path.home', HOME_MOCK) +@patch('pipconf.configs.Path.exists', MagicMock(return_value=True)) +def test_get_path(input_name: str, expected_return: Path): + configs = PipConfigs() + assert configs.get_path(input_name) == expected_return + + +@patch('pipconf.configs.Path.home', HOME_MOCK) +@patch('pipconf.configs.Path.exists', MagicMock(return_value=False)) +def test_select_path_does_not_exists(): + with raises(EnvironmentError): + PipConfigs().select(SOME_PATH) + + +@patch('pipconf.configs.Path.home', HOME_MOCK) +@patch('pipconf.configs.Path.exists', MagicMock(return_value=True)) +@patch('pipconf.configs.Path.is_symlink', MagicMock(return_value=True)) +@patch('pipconf.configs.Path.unlink') +@patch('pipconf.configs.Path.symlink_to') +def test_select(symlink_to_mock: MagicMock, unlink_mock: MagicMock): + PipConfigs().select(SOME_PATH) + assert symlink_to_mock.call_count == 1 + assert unlink_mock.call_count == 1 + + +@patch('pipconf.configs.Path.home', HOME_MOCK) +@patch('pipconf.configs.Path.exists', MagicMock(return_value=True)) +@patch('pipconf.configs.Path.is_symlink', MagicMock(return_value=False)) +@patch('pipconf.configs.Path.unlink') +@patch('pipconf.configs.Path.symlink_to') +@patch('pipconf.configs.copyfile') +def test_select_backup_original_conf( + copyfile_mock: MagicMock, symlink_to_mock: MagicMock, unlink_mock: MagicMock +): + PipConfigs().select(SOME_PATH) + assert copyfile_mock.call_count == 1 + assert symlink_to_mock.call_count == 1 + assert unlink_mock.call_count == 1 + + +@patch('pipconf.configs.Path.exists', MagicMock(return_value=True)) +def test_create_path_does_not_exists(): + with raises(EnvironmentError): + PipConfigs().create(SOME_PATH) + + +@patch('pipconf.configs.Path.exists', MagicMock(return_value=False)) +@patch('pipconf.configs.copyfile') +def test_create(copyfile_mock: MagicMock): + PipConfigs().create(SOME_PATH) + assert copyfile_mock.call_count == 1 + + +@patch('pipconf.configs.Path.exists', MagicMock(return_value=False)) +def test_show_path_does_not_exists(): + with raises(EnvironmentError): + PipConfigs().show(SOME_PATH) + + +@patch('pipconf.configs.Path.exists', MagicMock(return_value=True)) +@patch('pipconf.configs.Path.read_text') +def test_show(read_text_mock: MagicMock): + read_text_mock.return_value = 'some content' + config = PipConfigs() + assert config.show(SOME_PATH) == 'some content'