""" Unit tests for package manager utilities. Tests pip command generation without actual installation. """ from __future__ import annotations import inspect from unittest.mock import patch from langbot.pkg.utils import pkgmgr class TestPkgMgr: """Tests for package manager functions.""" def test_install_calls_pipmain(self): """install calls pipmain with correct arguments.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.install('requests') mock_pipmain.assert_called_once_with(['install', 'requests']) def test_install_with_version(self): """install handles package with version specifier.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.install('requests>=2.0.0') mock_pipmain.assert_called_once_with(['install', 'requests>=2.0.0']) def test_install_upgrade_calls_pipmain(self): """install_upgrade calls pipmain with upgrade and mirror.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.install_upgrade('requests') expected_args = [ 'install', '--upgrade', 'requests', '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple', '--trusted-host', 'pypi.tuna.tsinghua.edu.cn', ] mock_pipmain.assert_called_once_with(expected_args) def test_run_pip_with_params(self): """run_pip passes params to pipmain.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.run_pip(['list', '--outdated']) mock_pipmain.assert_called_once_with(['list', '--outdated']) def test_run_pip_empty_params(self): """run_pip handles empty params.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.run_pip([]) mock_pipmain.assert_called_once_with([]) def test_install_requirements_calls_pipmain(self): """install_requirements calls pipmain with requirements file.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.install_requirements('requirements.txt') expected_args = [ 'install', '-r', 'requirements.txt', '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple', '--trusted-host', 'pypi.tuna.tsinghua.edu.cn', ] mock_pipmain.assert_called_once_with(expected_args) def test_install_requirements_with_extra_params(self): """install_requirements handles extra params.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.install_requirements('requirements.txt', ['--no-cache-dir']) expected_args = [ 'install', '-r', 'requirements.txt', '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple', '--trusted-host', 'pypi.tuna.tsinghua.edu.cn', '--no-cache-dir', ] mock_pipmain.assert_called_once_with(expected_args) def test_install_requirements_multiple_extra_params(self): """install_requirements handles multiple extra params.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.install_requirements('requirements.txt', ['--no-cache-dir', '--verbose']) call_args = mock_pipmain.call_args[0][0] assert '--no-cache-dir' in call_args assert '--verbose' in call_args def test_install_requirements_defaults_extra_params_to_none(self): """install_requirements does not use a mutable list default.""" signature = inspect.signature(pkgmgr.install_requirements) assert signature.parameters['extra_params'].default is None def test_install_requirements_omitted_extra_params_are_isolated(self): """Repeated calls without extra_params use independent base commands.""" with patch('langbot.pkg.utils.pkgmgr.pipmain') as mock_pipmain: pkgmgr.install_requirements('requirements.txt') pkgmgr.install_requirements('requirements-dev.txt') assert mock_pipmain.call_args_list[0].args[0] == [ 'install', '-r', 'requirements.txt', '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple', '--trusted-host', 'pypi.tuna.tsinghua.edu.cn', ] assert mock_pipmain.call_args_list[1].args[0] == [ 'install', '-r', 'requirements-dev.txt', '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple', '--trusted-host', 'pypi.tuna.tsinghua.edu.cn', ]