From 90780a77df1b384ab4e3e7a3385af8d0cefc5218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Fri, 26 Apr 2024 20:31:24 -0300 Subject: [PATCH] Increase test coverage --- cookieplone/utils/commands/__init__.py | 4 +- cookieplone/utils/git.py | 2 + cookieplone/utils/sanity.py | 3 +- cookieplone/utils/validators.py | 15 ++- pyproject.toml | 1 + tests/conftest.py | 22 ++++ tests/utils/test_commands.py | 133 +++++++++++++++++++++++++ tests/utils/test_git.py | 31 +++--- tests/utils/test_internal.py | 15 +++ tests/utils/test_validators.py | 34 +++++++ 10 files changed, 230 insertions(+), 30 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/utils/test_commands.py diff --git a/cookieplone/utils/commands/__init__.py b/cookieplone/utils/commands/__init__.py index 9dfef39..7600840 100644 --- a/cookieplone/utils/commands/__init__.py +++ b/cookieplone/utils/commands/__init__.py @@ -77,8 +77,8 @@ def check_docker_version(min_version: str) -> str: version = _parse_docker_version(raw_version) return ( "" - if version >= settings.MIN_DOCKER_VERSION - else f"Docker version is not supported: Got {raw_version}" + if version >= min_version + else f"Docker version is not supported: Got {version}" ) diff --git a/cookieplone/utils/git.py b/cookieplone/utils/git.py index c59d2d3..e30372a 100644 --- a/cookieplone/utils/git.py +++ b/cookieplone/utils/git.py @@ -26,6 +26,8 @@ def initialize_repository(path: Path) -> Repo: if not check_path_is_repository(path): repo = Repo.init(path) repo.git.add(path) + else: + repo = Repo(path) return repo diff --git a/cookieplone/utils/sanity.py b/cookieplone/utils/sanity.py index 450e53f..6b81b41 100644 --- a/cookieplone/utils/sanity.py +++ b/cookieplone/utils/sanity.py @@ -9,6 +9,7 @@ def run_sanity_checks(checks: list[data.SanityCheck]) -> data.SanityCheckResults global_status = True results = [] for check in checks: + status = False name = check.name func = check.func args = check.args @@ -19,8 +20,6 @@ def run_sanity_checks(checks: list[data.SanityCheck]) -> data.SanityCheckResults message = "✓" elif level == "warning": status = True - elif level == "error": - status = False global_status = global_status and status results.append(data.SanityCheckResult(name, status, message)) global_message = ( diff --git a/cookieplone/utils/validators.py b/cookieplone/utils/validators.py index 3697897..9adcf10 100644 --- a/cookieplone/utils/validators.py +++ b/cookieplone/utils/validators.py @@ -84,19 +84,19 @@ def validate_npm_package_name(value: str) -> str: def validate_plone_version(value: str) -> str: """Validate Plone Version.""" - status = False version = _version_from_str(value) - if version: - status = version >= _version_from_str(settings.PLONE_MIN_VERSION) + status = bool(version) and ( + version >= _version_from_str(settings.PLONE_MIN_VERSION) + ) return "" if status else f"{value} is not a valid Plone version." def validate_volto_version(value: str) -> str: """Validate Volto Version.""" - status = False version = _version_from_str(value) - if version: - status = version >= _version_from_str(settings.VOLTO_MIN_VERSION) + status = bool(version) and ( + version >= _version_from_str(settings.VOLTO_MIN_VERSION) + ) return "" if status else f"{value} is not a valid Volto version." @@ -114,6 +114,7 @@ def run_context_validations( continue validations.append(data.ItemValidator(key, func, "error")) for validation in validations: + status = False key = validation.key func = validation.func value = context.get(key, "") @@ -124,8 +125,6 @@ def run_context_validations( message = "✓" elif level == "warning": status = True - elif level == "error": - status = False global_status = global_status and status results.append(data.ItemValidatorResult(key, status, message)) global_message = ( diff --git a/pyproject.toml b/pyproject.toml index f751a8f..06e6488 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,7 @@ tests = ["tests", "*/cookieplone/tests"] [tool.coverage.report] skip_empty = true +show_missing = true exclude_lines = [ "no cov", "if __name__ == .__main__.:", diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..fbecc13 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,22 @@ +import random +import string + +import pytest +from git import Repo + + +@pytest.fixture() +def tmp_repo(tmp_path): + repo = Repo.init(tmp_path) + repo.index.add(tmp_path) + repo.index.commit("test commit") + + return tmp_path + + +@pytest.fixture() +def no_repo(tmp_path): + sub_path = "".join(random.choice(string.ascii_lowercase) for _ in range(20)) # noQA:S311 + path = tmp_path / sub_path + path.mkdir(parents=True) + return path diff --git a/tests/utils/test_commands.py b/tests/utils/test_commands.py new file mode 100644 index 0000000..86024fb --- /dev/null +++ b/tests/utils/test_commands.py @@ -0,0 +1,133 @@ +import sys + +import pytest + +from cookieplone.utils import commands + + +@pytest.fixture +def mock_get_command_version(monkeypatch): + def func(raw_version): + def patch(cmd: str): + return raw_version + + monkeypatch.setattr(commands, "_get_command_version", patch) + + return func + + +@pytest.mark.parametrize( + "value,expected", + [ + ["v20.11.1", "20"], + ["v22.11.1", "22"], + ["v22.11", ""], + ["v22", ""], + ["22.11.1", ""], + ["22", ""], + ["foo", ""], + ], +) +def test_parse_node_major_version(value: str, expected: str): + func = commands._parse_node_major_version + assert func(value) == expected + + +@pytest.mark.parametrize( + "value,expected", + [ + ["Docker version 25.0.3, build 4debf41", "25.0"], + ["Docker version 25.0.3", "25.0"], + [" Docker version 25.0.3", "25.0"], + [" Docker version 25.0.3 ", "25.0"], + ["25.0.3", ""], + ["25.0", ""], + ["25", ""], + ["foo", ""], + ], +) +def test_parse_docker_version(value: str, expected: str): + func = commands._parse_docker_version + assert func(value) == expected + + +@pytest.mark.parametrize( + "cli,expected", + [ + ["git", ""], + ["python", ""], + ["kowabunga0123", "Command kowabunga0123 is not available."], + ], +) +def test_check_command_is_available(cli: str, expected: str): + func = commands.check_command_is_available + assert func(cli) == expected + + +@pytest.mark.parametrize( + "versions,expected", + [ + [[], ""], + [ + [ + "3.10", + "3.11", + "3.12", + "3.13", + ], + "", + ], + [ + [ + "1.5", + "2.4", + ], + f"Python version is not supported: Got {sys.version}", + ], + ], +) +def test_check_python_version(versions: list[str], expected: str): + func = commands.check_python_version + assert func(versions) == expected + + +@pytest.mark.parametrize( + "raw_version,min_version,expected", + [ + ["", "", "Docker not found."], + ["", "20.04", "Docker not found."], + ["Docker version 25.0.3, build 4debf41", "20.4", ""], + [ + "Docker version 25.0.3, build 4debf41", + "26.4", + "Docker version is not supported: Got 25.0", + ], + ], +) +def test_check_docker_version( + mock_get_command_version, raw_version: str, min_version: str, expected: str +): + mock_get_command_version(raw_version) + func = commands.check_docker_version + assert func(min_version) == expected + + +@pytest.mark.parametrize( + "raw_version,versions,expected", + [ + ["", [], "NodeJS not found."], + ["", ["16", "17", "18", "19", "20"], "NodeJS not found."], + ["v20.11.1", ["16", "17", "18", "19", "20"], ""], + [ + "v22.11.1", + ["16", "17", "18", "19", "20"], + "Node version is not supported: Got v22.11.1", + ], + ], +) +def test_check_node_version( + mock_get_command_version, raw_version: str, versions: list[str], expected: str +): + mock_get_command_version(raw_version) + func = commands.check_node_version + assert func(versions) == expected diff --git a/tests/utils/test_git.py b/tests/utils/test_git.py index de3f304..84b536f 100644 --- a/tests/utils/test_git.py +++ b/tests/utils/test_git.py @@ -1,25 +1,15 @@ -import pytest from git import Commit, Repo from cookieplone.utils import git -@pytest.fixture -def tmp_repo(tmp_path): - repo = Repo.init(tmp_path) - repo.index.add(tmp_path) - repo.index.commit("test commit") - - return tmp_path - - def test_repo_from_path(tmp_repo): repo = git.repo_from_path(tmp_repo) assert repo == Repo(tmp_repo) -def test_repo_from_path_invalid(tmp_path): - repo = git.repo_from_path(tmp_path) +def test_repo_from_path_invalid(no_repo): + repo = git.repo_from_path(no_repo) assert repo is None @@ -27,12 +17,17 @@ def test_check_path_is_repository(tmp_repo): assert git.check_path_is_repository(tmp_repo) -def test_check_path_is_repository_invalid(tmp_path): - assert not git.check_path_is_repository(tmp_path) +def test_check_path_is_repository_invalid(no_repo): + assert not git.check_path_is_repository(no_repo) + + +def test_initialize_repository_existing_repo(tmp_repo): + repo = git.initialize_repository(tmp_repo) + assert isinstance(repo, Repo) -def test_initialize_repository(tmp_path): - repo = git.initialize_repository(tmp_path) +def test_initialize_repository_new_repo(no_repo): + repo = git.initialize_repository(no_repo) assert isinstance(repo, Repo) @@ -42,5 +37,5 @@ def test_get_last_commit(tmp_repo): assert commit.summary == "test commit" -def test_get_last_commit_invalid(tmp_path): - assert git.get_last_commit(tmp_path) is None +def test_get_last_commit_invalid(no_repo): + assert git.get_last_commit(no_repo) is None diff --git a/tests/utils/test_internal.py b/tests/utils/test_internal.py index 0cf3453..fcbd142 100644 --- a/tests/utils/test_internal.py +++ b/tests/utils/test_internal.py @@ -1,3 +1,4 @@ +import re import sys from pathlib import Path @@ -16,3 +17,17 @@ def test_version_info(): f"Python {sys.version})" ) assert result == expected + + +def test_signature_md_without_commit(no_repo): + result = internal.signature_md(no_repo) + assert isinstance(result, str) + assert result.startswith(f"Generated using [Cookieplone ({__version__})]") + assert "[cookiecutter-plone]" in result + + +def test_signature_md_with_commit(tmp_repo): + result = internal.signature_md(tmp_repo) + assert isinstance(result, str) + assert result.startswith(f"Generated using [Cookieplone ({__version__})]") + assert re.search(r"\[cookiecutter-plone \([a-f0-9]{7}\)]\([^\)]*\)", result) diff --git a/tests/utils/test_validators.py b/tests/utils/test_validators.py index c7a01bb..f6f3fff 100644 --- a/tests/utils/test_validators.py +++ b/tests/utils/test_validators.py @@ -9,6 +9,10 @@ ["foo", "", "foo should be provided"], ["", "", " should be provided"], ["foo", "not empty", ""], + ["foo", 0, ""], + ["foo", 0.0, ""], + ["foo", [0], ""], + ["foo", [], "foo should be provided"], ], ) def test_validate_not_empty(key: str, value: str, expected: str): @@ -130,6 +134,7 @@ def test_validate_npm_package_name(value: str, expected: str): @pytest.fixture def context(): return { + "__foo": "", "addon_name": "volto-code-block", "npm_package_name": "@plonegovbr/volto-code-block", "another": "", @@ -144,6 +149,7 @@ def my_validators(): return [ data.ItemValidator("addon_name", validators.validate_volto_addon_name), data.ItemValidator("npm_package_name", validators.validate_npm_package_name), + data.ItemValidator("another", validators.validate_plone_version, "warning"), ] @@ -160,3 +166,31 @@ def test_run_context_validations( """Test run_context_validations function.""" result = validators.run_context_validations(context, my_validators, allow_empty) assert result.status is expected + + +@pytest.mark.parametrize( + "version,expected", + ( + ("5.2.99", "5.2.99 is not a valid Plone version."), + ("6.0.1", ""), + ("6.1.0a3", ""), + ("7.0.0", ""), + ), +) +def test_validate_plone_version(version: str, expected: str): + func = validators.validate_plone_version + assert func(version) == expected + + +@pytest.mark.parametrize( + "version,expected", + ( + ("14.0.0", "14.0.0 is not a valid Volto version."), + ("18.0.0-alpha.21", ""), + ("17.0.0", ""), + ("16.15.1", ""), + ), +) +def test_validate_volto_version(version: str, expected: str): + func = validators.validate_volto_version + assert func(version) == expected