poetry/tests/console/commands/test_check.py

224 lines
6.4 KiB
Python

from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from poetry.packages import Locker
from poetry.toml import TOMLFile
if TYPE_CHECKING:
import httpretty
from cleo.testers.command_tester import CommandTester
from pytest_mock import MockerFixture
from poetry.poetry import Poetry
from tests.types import CommandTesterFactory
from tests.types import FixtureDirGetter
from tests.types import ProjectFactory
@pytest.fixture()
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
return command_tester_factory("check")
def _project_factory(
fixture_name: str,
project_factory: ProjectFactory,
fixture_dir: FixtureDirGetter,
) -> Poetry:
source = fixture_dir(fixture_name)
pyproject_content = (source / "pyproject.toml").read_text(encoding="utf-8")
poetry_lock_content = (source / "poetry.lock").read_text(encoding="utf-8")
return project_factory(
name="foobar",
pyproject_content=pyproject_content,
poetry_lock_content=poetry_lock_content,
source=source,
)
@pytest.fixture
def poetry_with_outdated_lockfile(
project_factory: ProjectFactory, fixture_dir: FixtureDirGetter
) -> Poetry:
return _project_factory("outdated_lock", project_factory, fixture_dir)
@pytest.fixture
def poetry_with_up_to_date_lockfile(
project_factory: ProjectFactory, fixture_dir: FixtureDirGetter
) -> Poetry:
return _project_factory("up_to_date_lock", project_factory, fixture_dir)
def test_check_valid(tester: CommandTester) -> None:
tester.execute()
expected = """\
All set!
"""
assert tester.io.fetch_output() == expected
def test_check_invalid(
mocker: MockerFixture, tester: CommandTester, fixture_dir: FixtureDirGetter
) -> None:
mocker.patch(
"poetry.poetry.Poetry.file",
return_value=TOMLFile(fixture_dir("invalid_pyproject") / "pyproject.toml"),
new_callable=mocker.PropertyMock,
)
tester.execute("--lock")
fastjsonschema_error = "data must contain ['description'] properties"
custom_error = "The fields ['description'] are required in package mode."
expected_template = """\
Error: {schema_error}
Error: Project name (invalid) is same as one of its dependencies
Error: Unrecognized classifiers: ['Intended Audience :: Clowns'].
Error: Declared README file does not exist: never/exists.md
Error: Invalid source "not-exists" referenced in dependencies.
Error: Invalid source "not-exists2" referenced in dependencies.
Error: poetry.lock was not found.
Warning: A wildcard Python dependency is ambiguous.\
Consider specifying a more explicit one.
Warning: The "pendulum" dependency specifies the "allows-prereleases" property,\
which is deprecated. Use "allow-prereleases" instead.
Warning: Deprecated classifier 'Natural Language :: Ukranian'.\
Must be replaced by ['Natural Language :: Ukrainian'].
Warning: Deprecated classifier\
'Topic :: Communications :: Chat :: AOL Instant Messenger'.\
Must be removed.
"""
expected = {
expected_template.format(schema_error=schema_error)
for schema_error in (fastjsonschema_error, custom_error)
}
assert tester.io.fetch_error() in expected
def test_check_private(
mocker: MockerFixture, tester: CommandTester, fixture_dir: FixtureDirGetter
) -> None:
mocker.patch(
"poetry.poetry.Poetry.file",
return_value=TOMLFile(fixture_dir("private_pyproject") / "pyproject.toml"),
new_callable=mocker.PropertyMock,
)
tester.execute()
expected = """\
All set!
"""
assert tester.io.fetch_output() == expected
def test_check_non_package_mode(
mocker: MockerFixture, tester: CommandTester, fixture_dir: FixtureDirGetter
) -> None:
mocker.patch(
"poetry.poetry.Poetry.file",
return_value=TOMLFile(fixture_dir("non_package_mode") / "pyproject.toml"),
new_callable=mocker.PropertyMock,
)
tester.execute()
expected = """\
All set!
"""
assert tester.io.fetch_output() == expected
@pytest.mark.parametrize(
("options", "expected", "expected_status"),
[
("", "All set!\n", 0),
("--lock", "Error: poetry.lock was not found.\n", 1),
],
)
def test_check_lock_missing(
mocker: MockerFixture,
tester: CommandTester,
fixture_dir: FixtureDirGetter,
options: str,
expected: str,
expected_status: int,
) -> None:
mocker.patch(
"poetry.poetry.Poetry.file",
return_value=TOMLFile(fixture_dir("private_pyproject") / "pyproject.toml"),
new_callable=mocker.PropertyMock,
)
status_code = tester.execute(options)
assert status_code == expected_status
if status_code == 0:
assert tester.io.fetch_output() == expected
else:
assert tester.io.fetch_error() == expected
@pytest.mark.parametrize("options", ["", "--lock"])
def test_check_lock_outdated(
command_tester_factory: CommandTesterFactory,
poetry_with_outdated_lockfile: Poetry,
http: type[httpretty.httpretty],
options: str,
) -> None:
http.disable()
locker = Locker(
lock=poetry_with_outdated_lockfile.pyproject.file.path.parent / "poetry.lock",
local_config=poetry_with_outdated_lockfile.locker._local_config,
)
poetry_with_outdated_lockfile.set_locker(locker)
tester = command_tester_factory("check", poetry=poetry_with_outdated_lockfile)
status_code = tester.execute(options)
expected = (
"Error: pyproject.toml changed significantly since poetry.lock was last generated. "
"Run `poetry lock [--no-update]` to fix the lock file.\n"
)
assert tester.io.fetch_error() == expected
# exit with an error
assert status_code == 1
@pytest.mark.parametrize("options", ["", "--lock"])
def test_check_lock_up_to_date(
command_tester_factory: CommandTesterFactory,
poetry_with_up_to_date_lockfile: Poetry,
http: type[httpretty.httpretty],
options: str,
) -> None:
http.disable()
locker = Locker(
lock=poetry_with_up_to_date_lockfile.pyproject.file.path.parent / "poetry.lock",
local_config=poetry_with_up_to_date_lockfile.locker._local_config,
)
poetry_with_up_to_date_lockfile.set_locker(locker)
tester = command_tester_factory("check", poetry=poetry_with_up_to_date_lockfile)
status_code = tester.execute(options)
expected = "All set!\n"
assert tester.io.fetch_output() == expected
# exit with an error
assert status_code == 0