From 6ebef0bd870aa1efe19bb79de91ff8b7ab0ee464 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 17:10:08 +0800 Subject: [PATCH 01/11] test(cli): add test cases for uncovered parts --- tests/test_cli.py | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 619f1c5057..51638655b3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,11 +3,46 @@ import pytest from commitizen import cli +from commitizen.__version__ import __version__ -def test_sysexit_no_argv(): +def test_sysexit_no_argv(mocker, capsys): + testargs = ["cz"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(SystemExit): cli.main() + out, _ = capsys.readouterr() + assert out.startswith("usage") + + +def test_cz_with_arg_but_without_command(mocker, capsys): + testargs = ["cz", "--name", "cz_jira"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit): + cli.main() + _, err = capsys.readouterr() + assert "Command is required" in err + + +def test_name(mocker, capsys): + testargs = ["cz", "-n", "cz_jira", "example"] + mocker.patch.object(sys, "argv", testargs) + + cli.main() + out, _ = capsys.readouterr() + assert out.startswith("JRA") + + +def test_name_default_value(tmpdir, mocker, capsys): + with tmpdir.as_cwd() as _: + testargs = ["cz", "example"] + mocker.patch.object(sys, "argv", testargs) + + cli.main() + out, _ = capsys.readouterr() + assert out.startswith("fix: correct minor typos in code") def test_ls(mocker, capsys): @@ -20,11 +55,10 @@ def test_ls(mocker, capsys): assert isinstance(out, str) -def test_version(mocker): +def test_version(mocker, capsys): testargs = ["cz", "--version"] mocker.patch.object(sys, "argv", testargs) - error_mock = mocker.patch("commitizen.out.error") cli.main() - - error_mock.assert_called_once() + out, _ = capsys.readouterr() + assert out.strip() == __version__ From 7b9a605b8685f2d6a02695264bb2870d87730c5b Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 17:17:59 +0800 Subject: [PATCH 02/11] test(cz/utils): add test cases for required_validator, multiple_line_breaker --- tests/test_cz_utils.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/test_cz_utils.py diff --git a/tests/test_cz_utils.py b/tests/test_cz_utils.py new file mode 100644 index 0000000000..a8a56d762c --- /dev/null +++ b/tests/test_cz_utils.py @@ -0,0 +1,19 @@ +import pytest + +from commitizen.cz import utils, exceptions + + +def test_required_validator(): + assert utils.required_validator("test") == "test" + + with pytest.raises(exceptions.AnswerRequiredError): + utils.required_validator("") + + +def test_multiple_line_breaker(): + message = "this is the first line | and this is the second line " + result = utils.multiple_line_breaker(message) + assert result == "this is the first line\nand this is the second line" + + result = utils.multiple_line_breaker(message, "is") + assert result == "th\n\nthe first line | and th\n\nthe second line" From cfdf754f6e6c3b299e1c81e97e4671653e735a42 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 17:21:32 +0800 Subject: [PATCH 03/11] refactor(tests/commands): make commands related tests a module --- tests/{ => commands}/test_bump_command.py | 0 tests/{ => commands}/test_check_command.py | 0 tests/{ => commands}/test_commands.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => commands}/test_bump_command.py (100%) rename tests/{ => commands}/test_check_command.py (100%) rename tests/{ => commands}/test_commands.py (100%) diff --git a/tests/test_bump_command.py b/tests/commands/test_bump_command.py similarity index 100% rename from tests/test_bump_command.py rename to tests/commands/test_bump_command.py diff --git a/tests/test_check_command.py b/tests/commands/test_check_command.py similarity index 100% rename from tests/test_check_command.py rename to tests/commands/test_check_command.py diff --git a/tests/test_commands.py b/tests/commands/test_commands.py similarity index 100% rename from tests/test_commands.py rename to tests/commands/test_commands.py From c576a6605e2d3fe291d04e99f516ba2910093def Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 17:32:28 +0800 Subject: [PATCH 04/11] refactor(tests/commands): separate command unit tests into modules --- tests/commands/conftest.py | 11 ++ tests/commands/test_check_command.py | 52 ++++++ tests/commands/test_commands.py | 234 +------------------------ tests/commands/test_commit_command.py | 125 +++++++++++++ tests/commands/test_init_command.py | 11 ++ tests/commands/test_version_command.py | 42 +++++ 6 files changed, 242 insertions(+), 233 deletions(-) create mode 100644 tests/commands/conftest.py create mode 100644 tests/commands/test_commit_command.py create mode 100644 tests/commands/test_init_command.py create mode 100644 tests/commands/test_version_command.py diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py new file mode 100644 index 0000000000..cadf369f06 --- /dev/null +++ b/tests/commands/conftest.py @@ -0,0 +1,11 @@ +import pytest + +from commitizen import defaults +from commitizen.config import BaseConfig + + +@pytest.fixture() +def config(): + _config = BaseConfig() + _config.settings.update({"name": defaults.name}) + return _config diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 45acb57d80..55bd2572bd 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -1,8 +1,22 @@ import sys +import contextlib +import os +import shutil +import tempfile import pytest from commitizen import cli +from commitizen import commands + + +@contextlib.contextmanager +def get_temp_dir(): + temp_dir = tempfile.mkdtemp() + try: + yield temp_dir + finally: + shutil.rmtree(temp_dir) def test_check_jira_fails(mocker, capsys): @@ -76,3 +90,41 @@ def test_check_conventional_commit_succeeds(mocker, capsys): cli.main() out, _ = capsys.readouterr() assert "Commit validation: successful!" in out + + +def test_check_no_conventional_commit(config, mocker, tmpdir): + with pytest.raises(SystemExit): + error_mock = mocker.patch("commitizen.out.error") + + with get_temp_dir() as dir: + + tempfile = os.path.join(dir, "temp_commit_file") + with open(tempfile, "w") as f: + f.write("no conventional commit") + + check_cmd = commands.Check( + config=config, arguments={"commit_msg_file": tempfile} + ) + check_cmd() + error_mock.assert_called_once() + + +def test_check_conventional_commit(config, mocker): + success_mock = mocker.patch("commitizen.out.success") + with get_temp_dir() as dir: + + tempfile = os.path.join(dir, "temp_commit_file") + with open(tempfile, "w") as f: + f.write("feat(lang): added polish language") + + check_cmd = commands.Check( + config=config, arguments={"commit_msg_file": tempfile} + ) + + check_cmd() + success_mock.assert_called_once() + + +def test_check_command_when_commit_file_not_found(config): + with pytest.raises(FileNotFoundError): + commands.Check(config=config, arguments={"commit_msg_file": ""})() diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index c88a2716ba..354702c534 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,150 +1,6 @@ -import contextlib -import os -import shutil -import tempfile from unittest import mock -import pytest - -from commitizen import cmd, commands, defaults -from commitizen.cz.exceptions import CzException -from commitizen.config import BaseConfig -from commitizen.__version__ import __version__ - - -@pytest.fixture() -def config(): - _config = BaseConfig() - _config.settings.update({"name": defaults.name}) - return _config - - -@pytest.fixture -def staging_is_clean(mocker): - is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") - is_staging_clean_mock.return_value = False - - -@contextlib.contextmanager -def get_temp_dir(): - temp_dir = tempfile.mkdtemp() - try: - yield temp_dir - finally: - shutil.rmtree(temp_dir) - - -@pytest.mark.usefixtures("staging_is_clean") -def test_commit(config, mocker): - prompt_mock = mocker.patch("questionary.prompt") - prompt_mock.return_value = { - "prefix": "feat", - "subject": "user created", - "scope": "", - "is_breaking_change": False, - "body": "", - "footer": "", - } - - commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("success", "", "", "") - success_mock = mocker.patch("commitizen.out.success") - - commands.Commit(config, {})() - success_mock.assert_called_once() - - -@pytest.mark.usefixtures("staging_is_clean") -def test_commit_retry_fails_no_backup(config, mocker): - commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("success", "", "", "") - - with pytest.raises(SystemExit): - commands.Commit(config, {"retry": True})() - - -@pytest.mark.usefixtures("staging_is_clean") -def test_commit_retry_works(config, mocker): - prompt_mock = mocker.patch("questionary.prompt") - prompt_mock.return_value = { - "prefix": "feat", - "subject": "user created", - "scope": "", - "is_breaking_change": False, - "body": "closes #21", - "footer": "", - } - - commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("", "error", "", "") - error_mock = mocker.patch("commitizen.out.error") - - with pytest.raises(SystemExit): - commit_cmd = commands.Commit(config, {}) - temp_file = commit_cmd.temp_file - commit_cmd() - - prompt_mock.assert_called_once() - error_mock.assert_called_once() - assert os.path.isfile(temp_file) - - # Previous commit failed, so retry should pick up the backup commit - # commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("success", "", "", "") - success_mock = mocker.patch("commitizen.out.success") - - commands.Commit(config, {"retry": True})() - - commit_mock.assert_called_with("feat: user created\n\ncloses #21") - prompt_mock.assert_called_once() - success_mock.assert_called_once() - assert not os.path.isfile(temp_file) - - -@pytest.mark.usefixtures("staging_is_clean") -def test_commit_command_with_dry_run_option(config, mocker): - prompt_mock = mocker = mocker.patch("questionary.prompt") - prompt_mock.return_value = { - "prefix": "feat", - "subject": "user created", - "scope": "", - "is_breaking_change": False, - "body": "closes #57", - "footer": "", - } - - with pytest.raises(SystemExit): - commit_cmd = commands.Commit(config, {"dry_run": True}) - commit_cmd() - - -def test_commit_when_nothing_to_commit(config, mocker): - is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") - is_staging_clean_mock.return_value = True - - with pytest.raises(SystemExit) as err: - commit_cmd = commands.Commit(config, {}) - commit_cmd() - - assert err.value.code == commands.commit.NOTHING_TO_COMMIT - - -@pytest.mark.usefixtures("staging_is_clean") -def test_commit_when_customized_expected_raised(config, mocker, capsys): - _err = ValueError() - _err.__context__ = CzException("This is the root custom err") - prompt_mock = mocker.patch("questionary.prompt") - prompt_mock.side_effect = _err - - with pytest.raises(SystemExit) as err: - commit_cmd = commands.Commit(config, {}) - commit_cmd() - - assert err.value.code == commands.commit.CUSTOM_ERROR - - # Assert only the content in the formatted text - captured = capsys.readouterr() - assert "This is the root custom err" in captured.err +from commitizen import commands def test_example(config): @@ -169,91 +25,3 @@ def test_list_cz(config): with mock.patch("commitizen.out.write") as mocked_write: commands.ListCz(config)() mocked_write.assert_called_once() - - -def test_version_for_showing_project_version(config, capsys): - # No version exist - commands.Version(config, {"project": True, "commitizen": False, "verbose": False})() - captured = capsys.readouterr() - assert "No project information in this project." in captured.err - - config.settings["version"] = "v0.0.1" - commands.Version(config, {"project": True, "commitizen": False, "verbose": False})() - captured = capsys.readouterr() - assert "v0.0.1" in captured.out - - -def test_version_for_showing_commitizen_version(config, capsys): - commands.Version(config, {"project": False, "commitizen": True, "verbose": False})() - captured = capsys.readouterr() - assert f"{__version__}" in captured.out - - # default showing commitizen version - commands.Version( - config, {"project": False, "commitizen": False, "verbose": False} - )() - captured = capsys.readouterr() - assert f"{__version__}" in captured.out - - -def test_version_for_showing_both_versions(config, capsys): - commands.Version(config, {"project": False, "commitizen": False, "verbose": True})() - captured = capsys.readouterr() - assert f"Installed Commitizen Version: {__version__}" in captured.out - assert "No project information in this project." in captured.err - - config.settings["version"] = "v0.0.1" - commands.Version(config, {"project": False, "commitizen": False, "verbose": True})() - captured = capsys.readouterr() - expected_out = ( - f"Installed Commitizen Version: {__version__}\n" f"Project Version: v0.0.1" - ) - assert expected_out in captured.out - - -def test_check_no_conventional_commit(config, mocker): - with pytest.raises(SystemExit): - error_mock = mocker.patch("commitizen.out.error") - - with get_temp_dir() as dir: - - tempfile = os.path.join(dir, "temp_commit_file") - with open(tempfile, "w") as f: - f.write("no conventional commit") - - check_cmd = commands.Check( - config=config, arguments={"commit_msg_file": tempfile} - ) - check_cmd() - error_mock.assert_called_once() - - -def test_check_conventional_commit(config, mocker): - success_mock = mocker.patch("commitizen.out.success") - with get_temp_dir() as dir: - - tempfile = os.path.join(dir, "temp_commit_file") - with open(tempfile, "w") as f: - f.write("feat(lang): added polish language") - - check_cmd = commands.Check( - config=config, arguments={"commit_msg_file": tempfile} - ) - - check_cmd() - success_mock.assert_called_once() - - -def test_check_command_when_commit_file_not_found(config): - with pytest.raises(FileNotFoundError): - commands.Check(config=config, arguments={"commit_msg_file": ""})() - - -def test_init_when_config_already_exists(config, capsys): - # Set config path - path = "tests/pyproject.toml" - config.add_path(path) - - commands.Init(config)() - captured = capsys.readouterr() - assert captured.out == f"Config file {path} already exists\n" diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py new file mode 100644 index 0000000000..97614696dd --- /dev/null +++ b/tests/commands/test_commit_command.py @@ -0,0 +1,125 @@ +import os + +import pytest + +from commitizen import cmd, commands +from commitizen.cz.exceptions import CzException + + +@pytest.fixture +def staging_is_clean(mocker): + is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") + is_staging_clean_mock.return_value = False + + +@pytest.mark.usefixtures("staging_is_clean") +def test_commit(config, mocker): + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "", + "footer": "", + } + + commit_mock = mocker.patch("commitizen.git.commit") + commit_mock.return_value = cmd.Command("success", "", "", "") + success_mock = mocker.patch("commitizen.out.success") + + commands.Commit(config, {})() + success_mock.assert_called_once() + + +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_retry_fails_no_backup(config, mocker): + commit_mock = mocker.patch("commitizen.git.commit") + commit_mock.return_value = cmd.Command("success", "", "", "") + + with pytest.raises(SystemExit): + commands.Commit(config, {"retry": True})() + + +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_retry_works(config, mocker): + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "closes #21", + "footer": "", + } + + commit_mock = mocker.patch("commitizen.git.commit") + commit_mock.return_value = cmd.Command("", "error", "", "") + error_mock = mocker.patch("commitizen.out.error") + + with pytest.raises(SystemExit): + commit_cmd = commands.Commit(config, {}) + temp_file = commit_cmd.temp_file + commit_cmd() + + prompt_mock.assert_called_once() + error_mock.assert_called_once() + assert os.path.isfile(temp_file) + + # Previous commit failed, so retry should pick up the backup commit + # commit_mock = mocker.patch("commitizen.git.commit") + commit_mock.return_value = cmd.Command("success", "", "", "") + success_mock = mocker.patch("commitizen.out.success") + + commands.Commit(config, {"retry": True})() + + commit_mock.assert_called_with("feat: user created\n\ncloses #21") + prompt_mock.assert_called_once() + success_mock.assert_called_once() + assert not os.path.isfile(temp_file) + + +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_command_with_dry_run_option(config, mocker): + prompt_mock = mocker = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "closes #57", + "footer": "", + } + + with pytest.raises(SystemExit): + commit_cmd = commands.Commit(config, {"dry_run": True}) + commit_cmd() + + +def test_commit_when_nothing_to_commit(config, mocker): + is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") + is_staging_clean_mock.return_value = True + + with pytest.raises(SystemExit) as err: + commit_cmd = commands.Commit(config, {}) + commit_cmd() + + assert err.value.code == commands.commit.NOTHING_TO_COMMIT + + +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_when_customized_expected_raised(config, mocker, capsys): + _err = ValueError() + _err.__context__ = CzException("This is the root custom err") + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.side_effect = _err + + with pytest.raises(SystemExit) as err: + commit_cmd = commands.Commit(config, {}) + commit_cmd() + + assert err.value.code == commands.commit.CUSTOM_ERROR + + # Assert only the content in the formatted text + captured = capsys.readouterr() + assert "This is the root custom err" in captured.err diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py new file mode 100644 index 0000000000..1835d8db62 --- /dev/null +++ b/tests/commands/test_init_command.py @@ -0,0 +1,11 @@ +from commitizen import commands + + +def test_init_when_config_already_exists(config, capsys): + # Set config path + path = "tests/pyproject.toml" + config.add_path(path) + + commands.Init(config)() + captured = capsys.readouterr() + assert captured.out == f"Config file {path} already exists\n" diff --git a/tests/commands/test_version_command.py b/tests/commands/test_version_command.py new file mode 100644 index 0000000000..527c0b53f1 --- /dev/null +++ b/tests/commands/test_version_command.py @@ -0,0 +1,42 @@ +from commitizen import commands +from commitizen.__version__ import __version__ + + +def test_version_for_showing_project_version(config, capsys): + # No version exist + commands.Version(config, {"project": True, "commitizen": False, "verbose": False})() + captured = capsys.readouterr() + assert "No project information in this project." in captured.err + + config.settings["version"] = "v0.0.1" + commands.Version(config, {"project": True, "commitizen": False, "verbose": False})() + captured = capsys.readouterr() + assert "v0.0.1" in captured.out + + +def test_version_for_showing_commitizen_version(config, capsys): + commands.Version(config, {"project": False, "commitizen": True, "verbose": False})() + captured = capsys.readouterr() + assert f"{__version__}" in captured.out + + # default showing commitizen version + commands.Version( + config, {"project": False, "commitizen": False, "verbose": False} + )() + captured = capsys.readouterr() + assert f"{__version__}" in captured.out + + +def test_version_for_showing_both_versions(config, capsys): + commands.Version(config, {"project": False, "commitizen": False, "verbose": True})() + captured = capsys.readouterr() + assert f"Installed Commitizen Version: {__version__}" in captured.out + assert "No project information in this project." in captured.err + + config.settings["version"] = "v0.0.1" + commands.Version(config, {"project": False, "commitizen": False, "verbose": True})() + captured = capsys.readouterr() + expected_out = ( + f"Installed Commitizen Version: {__version__}\n" f"Project Version: v0.0.1" + ) + assert expected_out in captured.out From 963f10960bcf0a5417f0d8045f8caf0a58373b04 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 17:36:47 +0800 Subject: [PATCH 05/11] refactor(test/commands/other): replace unit test style mock with mocker fixture --- tests/commands/test_commands.py | 27 --------------------------- tests/commands/test_other_commands.py | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 27 deletions(-) delete mode 100644 tests/commands/test_commands.py create mode 100644 tests/commands/test_other_commands.py diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py deleted file mode 100644 index 354702c534..0000000000 --- a/tests/commands/test_commands.py +++ /dev/null @@ -1,27 +0,0 @@ -from unittest import mock - -from commitizen import commands - - -def test_example(config): - with mock.patch("commitizen.out.write") as write_mock: - commands.Example(config)() - write_mock.assert_called_once() - - -def test_info(config): - with mock.patch("commitizen.out.write") as write_mock: - commands.Info(config)() - write_mock.assert_called_once() - - -def test_schema(config): - with mock.patch("commitizen.out.write") as write_mock: - commands.Schema(config)() - write_mock.assert_called_once() - - -def test_list_cz(config): - with mock.patch("commitizen.out.write") as mocked_write: - commands.ListCz(config)() - mocked_write.assert_called_once() diff --git a/tests/commands/test_other_commands.py b/tests/commands/test_other_commands.py new file mode 100644 index 0000000000..619b6743d1 --- /dev/null +++ b/tests/commands/test_other_commands.py @@ -0,0 +1,25 @@ +from commitizen import commands + + +def test_example(config, mocker): + write_mock = mocker.patch("commitizen.out.write") + commands.Example(config)() + write_mock.assert_called_once() + + +def test_info(config, mocker): + write_mock = mocker.patch("commitizen.out.write") + commands.Info(config)() + write_mock.assert_called_once() + + +def test_schema(config, mocker): + write_mock = mocker.patch("commitizen.out.write") + commands.Schema(config)() + write_mock.assert_called_once() + + +def test_list_cz(config, mocker): + write_mock = mocker.patch("commitizen.out.write") + commands.ListCz(config)() + write_mock.assert_called_once() From 1b294c221171f43a65bf2728ebcc31a41f9c0d50 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 17:41:32 +0800 Subject: [PATCH 06/11] refactor(tests/commands/check): use pytest fixture tmpdir replace self implemented contextmanager --- tests/commands/test_check_command.py | 46 ++++++++-------------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 55bd2572bd..c5bed35e61 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -1,8 +1,4 @@ import sys -import contextlib -import os -import shutil -import tempfile import pytest @@ -10,15 +6,6 @@ from commitizen import commands -@contextlib.contextmanager -def get_temp_dir(): - temp_dir = tempfile.mkdtemp() - try: - yield temp_dir - finally: - shutil.rmtree(temp_dir) - - def test_check_jira_fails(mocker, capsys): testargs = ["cz", "-n", "cz_jira", "check", "--commit-msg-file", "some_file"] mocker.patch.object(sys, "argv", testargs) @@ -96,33 +83,26 @@ def test_check_no_conventional_commit(config, mocker, tmpdir): with pytest.raises(SystemExit): error_mock = mocker.patch("commitizen.out.error") - with get_temp_dir() as dir: - - tempfile = os.path.join(dir, "temp_commit_file") - with open(tempfile, "w") as f: - f.write("no conventional commit") + tempfile = tmpdir.join("temp_commit_file") + tempfile.write("no conventional commit") - check_cmd = commands.Check( - config=config, arguments={"commit_msg_file": tempfile} - ) - check_cmd() - error_mock.assert_called_once() + check_cmd = commands.Check( + config=config, arguments={"commit_msg_file": tempfile} + ) + check_cmd() + error_mock.assert_called_once() -def test_check_conventional_commit(config, mocker): +def test_check_conventional_commit(config, mocker, tmpdir): success_mock = mocker.patch("commitizen.out.success") - with get_temp_dir() as dir: - tempfile = os.path.join(dir, "temp_commit_file") - with open(tempfile, "w") as f: - f.write("feat(lang): added polish language") + tempfile = tmpdir.join("temp_commit_file") + tempfile.write("feat(lang): added polish language") - check_cmd = commands.Check( - config=config, arguments={"commit_msg_file": tempfile} - ) + check_cmd = commands.Check(config=config, arguments={"commit_msg_file": tempfile}) - check_cmd() - success_mock.assert_called_once() + check_cmd() + success_mock.assert_called_once() def test_check_command_when_commit_file_not_found(config): From 7a0915b193a4f7ac77192678f5cfd9645a334228 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 17:09:46 +0800 Subject: [PATCH 07/11] fix(cli): fix --version not functional --- commitizen/cli.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 552ee36184..0cfbb460b0 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -179,6 +179,7 @@ def main(): parser.print_help(sys.stderr) raise SystemExit() + # This is for the command required constraint in 2.0 try: args = parser.parse_args() except TypeError: @@ -195,7 +196,7 @@ def main(): "'cz --version' will be deprecated in next major version. " "Please use 'cz version' command from your scripts" ) - logging.getLogger("commitizen").setLevel(logging.DEBUG) + args.func = commands.Version if args.debug: warnings.warn( @@ -205,7 +206,9 @@ def main(): logging.getLogger("commitizen").setLevel(logging.DEBUG) # TODO: This try block can be removed after command is required in 2.0 + # Handle the case that argument is given, but no command is provided try: args.func(conf, vars(args))() except AttributeError: out.error("Command is required") + raise SystemExit() From f289ff661d696dd7569a8ace3ab81c60b79751a8 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 18:27:02 +0800 Subject: [PATCH 08/11] test(commands/init): add tests cases for the whole init process --- tests/commands/test_init_command.py | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 1835d8db62..1de8fef06a 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -1,6 +1,40 @@ from commitizen import commands +class FakeQuestion: + def __init__(self, expected_return): + self.expected_return = expected_return + + def ask(self): + return self.expected_return + + +def test_init(tmpdir, mocker, config): + mocker.patch( + "questionary.select", + side_effect=[ + FakeQuestion("pyproject.toml"), + FakeQuestion("cz_conventional_commits"), + ], + ) + mocker.patch("questionary.confirm", return_value=FakeQuestion("y")) + mocker.patch("questionary.text", return_value=FakeQuestion("y")) + expected_config = ( + "[tool.commitizen]\n" + 'name = "cz_conventional_commits"\n' + 'version = "0.0.1"\n' + 'tag_format = "y"\n' + ) + + with tmpdir.as_cwd(): + commands.Init(config)() + + with open("pyproject.toml", "r") as toml_file: + config_data = toml_file.read() + + assert config_data == expected_config + + def test_init_when_config_already_exists(config, capsys): # Set config path path = "tests/pyproject.toml" From 527ef05d3a3a04926d038a0fb596b08302583a9f Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 18:53:42 +0800 Subject: [PATCH 09/11] test(commands/bump): add test case for uncovered bump command condition --- commitizen/commands/bump.py | 11 +++--- tests/commands/test_bump_command.py | 55 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index cf325447df..1d07548d7e 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -69,9 +69,11 @@ def __call__(self): try: current_version_instance: Version = Version(self.parameters["version"]) except TypeError: - out.error("[NO_VERSION_SPECIFIED]") - out.error("Check if current version is specified in config file, like:") - out.error("version = 0.4.3") + out.error( + "[NO_VERSION_SPECIFIED]\n" + "Check if current version is specified in config file, like:\n" + "version = 0.4.3\n" + ) raise SystemExit(NO_VERSION_SPECIFIED) # Initialize values from sources (conf) @@ -95,8 +97,7 @@ def __call__(self): # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: - out.error("[NO_COMMITS_FOUND]") - out.error("No new commits found.") + out.error("[NO_COMMITS_FOUND]\n" "No new commits found.") raise SystemExit(NO_COMMITS_FOUND) if increment is None: diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 209a5efe53..d066e8c849 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -33,6 +33,7 @@ def create_project(): full_tmp_path = os.path.join(current_directory, tmp_proj_path) if not os.path.exists(full_tmp_path): os.makedirs(full_tmp_path) + os.chdir(full_tmp_path) yield os.chdir(current_directory) @@ -42,6 +43,7 @@ def create_project(): def create_file_and_commit(message: str, filename: Optional[str] = None): if not filename: filename = str(uuid.uuid4()) + Path(f"./{filename}").touch() cmd.run("git add .") git.commit(message) @@ -102,3 +104,56 @@ def test_bump_command(mocker, create_project): tag_exists = git.tag_exist("1.0.0") assert tag_exists is True + + +def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir): + with tmpdir.as_cwd(): + with open("./pyproject.toml", "w") as f: + f.write("[tool.commitizen]\n" 'version="0.1.0"') + + cmd.run("git init") + create_file_and_commit( + "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported" + ) + + testargs = ["cz", "-n", "cz_jira", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit): + cli.main() + + _, err = capsys.readouterr() + assert "'cz_jira' rule does not support bump" in err + + +def test_bump_is_not_specify(mocker, capsys, tmpdir): + mocker.patch.object(sys, "argv", ["cz", "bump"]) + + with pytest.raises(SystemExit): + with tmpdir.as_cwd(): + cli.main() + + expected_error_message = ( + "[NO_VERSION_SPECIFIED]\n" + "Check if current version is specified in config file, like:\n" + "version = 0.4.3\n" + ) + + _, err = capsys.readouterr() + assert expected_error_message in err + + +def test_bump_when_not_new_commit(mocker, capsys, tmpdir): + with tmpdir.as_cwd(): + with open("./pyproject.toml", "w") as f: + f.write("[tool.commitizen]\n" 'version="0.1.0"') + cmd.run("git init") + + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit): + cli.main() + expected_error_message = "[NO_COMMITS_FOUND]\n" "No new commits found." + _, err = capsys.readouterr() + assert expected_error_message in err From 09f7e59ddc17e3fc8e04bb6ce9dd4d158bf38fcf Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 12:57:10 -0500 Subject: [PATCH 10/11] refactor(test_bump_command): rename camel case variables --- tests/commands/test_bump_command.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index d066e8c849..e3bf435ed6 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -12,12 +12,12 @@ from commitizen import cli, cmd, git -def ReadOnlyException(Exception): +class ReadOnlyException(Exception): pass # https://stackoverflow.com/questions/1213706/what-user-do-python-scripts-run-as-in-windows -def handleRemoveReadOnly(func, path, exc): +def handle_remove_read_only(func, path, exc): excvalue = exc[1] if func in (os.rmdir, os.remove, shutil.rmtree) and excvalue.errno == errno.EACCESS: os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.IRWXO) # 744 @@ -37,7 +37,7 @@ def create_project(): os.chdir(full_tmp_path) yield os.chdir(current_directory) - shutil.rmtree(full_tmp_path, handleRemoveReadOnly) + shutil.rmtree(full_tmp_path, handle_remove_read_only) def create_file_and_commit(message: str, filename: Optional[str] = None): From 98d6e93e81f325328724f8f110d8ccb77646534d Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 19:07:11 +0800 Subject: [PATCH 11/11] refactor(tests/commands/bump): use tmp_dir to replace self implemented tmp dir behavior --- tests/commands/test_bump_command.py | 57 +++++++---------------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index e3bf435ed6..48ebeebfeb 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -1,7 +1,3 @@ -import errno -import os -import shutil -import stat import sys import uuid from pathlib import Path @@ -12,32 +8,15 @@ from commitizen import cli, cmd, git -class ReadOnlyException(Exception): - pass - - -# https://stackoverflow.com/questions/1213706/what-user-do-python-scripts-run-as-in-windows -def handle_remove_read_only(func, path, exc): - excvalue = exc[1] - if func in (os.rmdir, os.remove, shutil.rmtree) and excvalue.errno == errno.EACCESS: - os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.IRWXO) # 744 - func(path) - else: - raise ReadOnlyException - +@pytest.fixture(scope="function") +def tmp_git_project(tmpdir): + with tmpdir.as_cwd(): + with open("pyproject.toml", "w") as f: + f.write("[tool.commitizen]\n" 'version="0.1.0"') -@pytest.fixture -def create_project(): - current_directory = os.getcwd() - tmp_proj_path = "tests/tmp-proj" - full_tmp_path = os.path.join(current_directory, tmp_proj_path) - if not os.path.exists(full_tmp_path): - os.makedirs(full_tmp_path) + cmd.run("git init") - os.chdir(full_tmp_path) - yield - os.chdir(current_directory) - shutil.rmtree(full_tmp_path, handle_remove_read_only) + yield def create_file_and_commit(message: str, filename: Optional[str] = None): @@ -49,12 +28,8 @@ def create_file_and_commit(message: str, filename: Optional[str] = None): git.commit(message) -def test_bump_command(mocker, create_project): - with open("./pyproject.toml", "w") as f: - f.write("[tool.commitizen]\n" 'version="0.1.0"') - - cmd.run("git init") - +@pytest.mark.usefixtures("tmp_git_project") +def test_bump_command(mocker): # MINOR create_file_and_commit("feat: new file") @@ -143,17 +118,13 @@ def test_bump_is_not_specify(mocker, capsys, tmpdir): assert expected_error_message in err -def test_bump_when_not_new_commit(mocker, capsys, tmpdir): - with tmpdir.as_cwd(): - with open("./pyproject.toml", "w") as f: - f.write("[tool.commitizen]\n" 'version="0.1.0"') - cmd.run("git init") +def test_bump_when_not_new_commit(mocker, capsys, tmp_git_project): + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) - testargs = ["cz", "bump", "--yes"] - mocker.patch.object(sys, "argv", testargs) + with pytest.raises(SystemExit): + cli.main() - with pytest.raises(SystemExit): - cli.main() expected_error_message = "[NO_COMMITS_FOUND]\n" "No new commits found." _, err = capsys.readouterr() assert expected_error_message in err