Skip to content

Commit

Permalink
test: added pytest tests for commitlint and cli
Browse files Browse the repository at this point in the history
  • Loading branch information
aj3sh committed Jan 18, 2024
1 parent d092c97 commit 401a172
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 5 deletions.
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
repos:
- repo: local
hooks:
- id: run-tests
name: Run tests
entry: pipenv run test
language: system
pass_filenames: false

- id: commitlint
name: Commitlint
entry: python -m src.commitlint.cli --file
Expand Down
10 changes: 9 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Install Development Dependencies (Using Pipenv)

All the dependencies are managed by Pipenv. Please install Pipenv on your system first by following the instructions at [https://pipenv.pypa.io/en/latest/installation/](https://pipenv.pypa.io/en/latest/installation/).
All the dependencies are managed by Pipenv. Please install Pipenv on your system first by following the instructions at [https://pipenv.pypa.io/en/latest/installation.html](https://pipenv.pypa.io/en/latest/installation.html).

Once Pipenv is installed, you can install the development dependencies by running the following command:

Expand All @@ -17,3 +17,11 @@ To install pre-commit and commit-msg hook for this project, run the following co
```bash
pipenv run install-hooks
```

## Run tests

Run the tests using the below command:

```bash
pipenv run test
```
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ pytest-cov = "*"
[scripts]
test = "pytest"
coverage = "pytest --cov=src/ --no-cov-on-fail"
coverage-html = "pytest --cov=src/ --cov-report=html --no-cov-on-fail"
install-hooks = "pre-commit install --hook-type pre-commit --hook-type commit-msg"
8 changes: 4 additions & 4 deletions src/commitlint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ def main() -> None:
if success:
sys.stdout.write(f"{COMMIT_SUCCESSFUL}\n")
sys.exit(0)

_show_errors(errors)
sys.exit(1)
else:
_show_errors(errors)
sys.exit(1)


if __name__ == "__main__":
main()
main() # pragma: no cover
Empty file added tests/__init__.py
Empty file.
98 changes: 98 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# type: ignore
# pylint: disable=all

from unittest.mock import MagicMock, call, mock_open, patch

from src.commitlint.cli import get_args, main
from src.commitlint.messages import COMMIT_SUCCESSFUL, INCORRECT_FORMAT_ERROR


class TestCLI:
@patch(
"argparse.ArgumentParser.parse_args",
return_value=MagicMock(commit_message="commit message", file=None),
)
def test__get_args__with_commit_message(self, *_):
args = get_args()
assert args.commit_message == "commit message"
assert args.file is None

@patch(
"argparse.ArgumentParser.parse_args",
return_value=MagicMock(commit_message=None, file="path/to/file.txt"),
)
def test__get_args__with_file(self, *_):
args = get_args()
assert args.file == "path/to/file.txt"
assert args.commit_message is None

@patch("argparse.ArgumentParser.error")
def test__get_args__without_commit_message_and_file(self, mock_error):
get_args()
mock_error.assert_called_with(
"Please provide either a commit message or a file."
)

@patch(
"src.commitlint.cli.get_args",
return_value=MagicMock(commit_message="feat: valid commit message", file=None),
)
@patch("sys.stdout.write")
@patch("sys.exit")
def test__main__valid_commit_message(
self,
mock_sys_exit,
mock_stdout_write,
*_,
):
main()
mock_sys_exit.assert_called_with(0)
mock_stdout_write.assert_called_with(f"{COMMIT_SUCCESSFUL}\n")

@patch(
"src.commitlint.cli.get_args",
return_value=MagicMock(commit_message="Invalid commit message", file=None),
)
@patch("sys.stderr.write")
@patch("sys.exit")
def test__main__invalid_commit_message(
self,
mock_sys_exit,
mock_stderr_write,
*_,
):
main()
mock_sys_exit.assert_called_with(1)
mock_stderr_write.assert_has_calls(
[call("✖ Found 1 errors.\n\n"), call(f"- {INCORRECT_FORMAT_ERROR}\n\n")]
)

@patch(
"src.commitlint.cli.get_args",
return_value=MagicMock(file="path/to/file.txt", commit_message=None),
)
@patch("sys.stdout.write")
@patch("sys.exit")
@patch("builtins.open", mock_open(read_data="feat: valid commit message"))
def test__main__valid_commit_message_from_file(
self, mock_sys_exit, mock_stdout_write, *_
):
main()
mock_sys_exit.assert_called_with(0)
mock_stdout_write.assert_called_with(f"{COMMIT_SUCCESSFUL}\n")

@patch(
"src.commitlint.cli.get_args",
return_value=MagicMock(file="path/to/file.txt", commit_message=None),
)
@patch("sys.stderr.write")
@patch("sys.exit")
@patch("builtins.open", mock_open(read_data="Invalid commit message"))
def test__main__invalid_commit_message_from_file(
self, mock_sys_exit, mock_stderr_write, *_
):
main()
mock_sys_exit.assert_called_with(1)
mock_stderr_write.assert_has_calls(
[call("✖ Found 1 errors.\n\n"), call(f"- {INCORRECT_FORMAT_ERROR}\n\n")]
)
Empty file.
94 changes: 94 additions & 0 deletions tests/test_commitlint/test_check_commit_message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# type: ignore
# pylint: disable=all

from src.commitlint import check_commit_message
from src.commitlint.constants import COMMIT_MAX_LENGTH
from src.commitlint.messages import HEADER_LENGTH_ERROR, INCORRECT_FORMAT_ERROR


def test__check_commit_message__header_length_error():
commit_message = "feat: " + "a" * (COMMIT_MAX_LENGTH + 1)
success, errors = check_commit_message(commit_message)
assert success is False
assert HEADER_LENGTH_ERROR in errors


def test__check_commit_message__header_length_valid():
commit_message = "feat: " + "a" * (COMMIT_MAX_LENGTH - 1)
success, errors = check_commit_message(commit_message)
assert success is False
assert HEADER_LENGTH_ERROR in errors


def test__check_commit_message__incorrect_format_error():
commit_message = "This is an invalid commit message"
success, errors = check_commit_message(commit_message)
assert success is False
assert INCORRECT_FORMAT_ERROR in errors


def test__check_commit_message__incorrect_format_error_and_health_length_invalid():
commit_message = "Test " + "a" * (COMMIT_MAX_LENGTH + 1)
success, errors = check_commit_message(commit_message)
assert success is False
assert HEADER_LENGTH_ERROR in errors
assert INCORRECT_FORMAT_ERROR in errors


def test__check_commit_message__valid():
commit_message = "feat: add new feature"
success, errors = check_commit_message(commit_message)
assert success is True
assert errors == []


def test__check_commit_message__valid_with_scope():
commit_message = "feat(scope): add new feature"
success, errors = check_commit_message(commit_message)
assert success is True
assert errors == []


def test__check_commit_message__empty_scope_error():
commit_message = "feat(): add new feature"
success, errors = check_commit_message(commit_message)
assert success is False
assert INCORRECT_FORMAT_ERROR in errors


def test__check_commit_message__valid_with_body():
commit_message = "fix(scope): fix a bug\n\nThis is the body of the commit message."
success, errors = check_commit_message(commit_message)
assert success is True
assert errors == []


def test__check_commit_message__header_line_error():
commit_message = "feat(): add new feature\ntest"
success, errors = check_commit_message(commit_message)
assert success is False
assert INCORRECT_FORMAT_ERROR in errors


def test__check_commit_message__with_comments():
commit_message = "feat(scope): add new feature\n#this is a comment"
success, errors = check_commit_message(commit_message)
assert success is True
assert errors == []


def test__check_commit_message__with_diff():
commit_message = (
"fix: fixed a bug\n\nthis is body\n"
"# ------------------------ >8 ------------------------\nDiff message"
)
success, errors = check_commit_message(commit_message)
assert success is True
assert errors == []


def test__check_commit_message__ignored():
commit_message = "Merge pull request #123"
success, errors = check_commit_message(commit_message)
assert success is True
assert errors == []
34 changes: 34 additions & 0 deletions tests/test_commitlint/test_is_ingored.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# type: ignore
# pylint: disable=all

import pytest

from src.commitlint.commitlint import is_ignored


@pytest.mark.parametrize(
"commit_message, expected_result",
[
("Merge pull request #123", True),
("Merge feature-branch into production", True),
("Merge branch hotfix-123", True),
("Merge tag release-v2.0.1", True),
('Revert "Undo last commit"', True),
("revert Fix-Typo", True),
("Merged bugfix-789 in master", True),
("Merged PR #987: Update documentation", True),
("Merge remote-tracking branch upstream/develop", True),
("Automatic merge from CI/CD", True),
("Auto-merged feature-branch into staging", True),
("Merge tag v3.5.0", True),
("Merge pull request #456: Feature XYZ", True),
('Revert "Apply security patch"', True),
("Merged PR #321: Bugfix - Resolve issue with login", True),
("Merge my feature", False),
("Add new feature", False),
("feat: this is conventional commit format", False),
],
)
def test__is_ignored(commit_message, expected_result):
result = is_ignored(commit_message)
assert result == expected_result
47 changes: 47 additions & 0 deletions tests/test_commitlint/test_remove_comments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# type: ignore
# pylint: disable=all

from src.commitlint.commitlint import remove_comments


def test__remove_comments__no_comments():
input_msg = "Commit message without comments"
expected_output = "Commit message without comments"
result = remove_comments(input_msg)
assert result == expected_output


def test__remove_comments__with_comments():
input_msg = "# Comment\nRegular text"
expected_output = "Regular text"
result = remove_comments(input_msg)
assert result == expected_output


def test__remove_comments__with_diff_message():
input_msg = (
"Fix a bug\n"
"# ------------------------ >8 ------------------------\n"
"Diff message"
)
expected_output = "Fix a bug"
result = remove_comments(input_msg)
assert result == expected_output


def test__remove_comments__multiple_comments():
input_msg = "New feature\n# Comment\n# Another comment"
expected_output = "New feature"
result = remove_comments(input_msg)
assert result == expected_output


def test__remove_comments__comments_before_diff():
input_msg = (
"#Comments\n"
"# ------------------------ >8 ------------------------\n"
"Diff message"
)
expected_output = ""
result = remove_comments(input_msg)
assert result == expected_output

0 comments on commit 401a172

Please sign in to comment.