Skip to content

Commit b3239fe

Browse files
committed
🚨 test(utils-commit-changelog): update tests for run_command signature && add tests for changelog edge cases && enhance commit tests for run_command args
1 parent 2ab2427 commit b3239fe

File tree

3 files changed

+103
-27
lines changed

3 files changed

+103
-27
lines changed

tests/unit/test_changelog.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,3 +872,44 @@ def test_handle_changelog_with_range(self, mock_print, mock_generate, mock_get_r
872872
mock_get_range.assert_called_once_with(mock_repo_instance, "v1.0.0", "v1.1.0")
873873
mock_generate.assert_called_once_with(mock_repo_instance, ["segment1"])
874874
mock_print.assert_called_once_with("generated changelog", None, prepend=False)
875+
876+
@patch("tgit.changelog.git.Repo")
877+
@patch("tgit.changelog.extract_latest_tag_from_changelog")
878+
@patch("tgit.changelog.prepare_changelog_segments")
879+
@patch("tgit.changelog.get_latest_git_tag")
880+
@patch("tgit.changelog.print")
881+
def test_handle_changelog_already_up_to_date(self, mock_print, mock_get_latest_tag, mock_prepare, mock_extract, mock_repo):
882+
"""Test handle_changelog when changelog is already up to date."""
883+
mock_repo_instance = Mock()
884+
mock_repo.return_value = mock_repo_instance
885+
886+
mock_extract.return_value = "v1.2.0"
887+
mock_get_latest_tag.return_value = "v1.2.0"
888+
mock_prepare.return_value = [] # No segments to process
889+
890+
args = ChangelogArgs(path=".", from_raw=None, to_raw=None, verbose=0, output="CHANGELOG.md")
891+
892+
with patch("pathlib.Path.exists", return_value=True):
893+
handle_changelog(args)
894+
895+
mock_extract.assert_called_once_with("CHANGELOG.md")
896+
mock_prepare.assert_called_once_with(mock_repo_instance, "v1.2.0", None)
897+
mock_get_latest_tag.assert_called_once_with(mock_repo_instance)
898+
mock_print.assert_called_once_with("[green]Changelog is already up to date.[/green]")
899+
900+
@patch("tgit.changelog.git.Repo")
901+
@patch("tgit.changelog.prepare_changelog_segments")
902+
@patch("tgit.changelog.print")
903+
def test_handle_changelog_no_changes_no_existing_file(self, mock_print, mock_prepare, mock_repo):
904+
"""Test handle_changelog when there are no changes and no existing file."""
905+
mock_repo_instance = Mock()
906+
mock_repo.return_value = mock_repo_instance
907+
908+
mock_prepare.return_value = [] # No segments to process
909+
910+
args = ChangelogArgs(path=".", from_raw=None, to_raw=None, verbose=0, output=None)
911+
912+
handle_changelog(args)
913+
914+
mock_prepare.assert_called_once_with(mock_repo_instance, None, None)
915+
mock_print.assert_called_once_with("[yellow]No changes found, nothing to output.[/yellow]")

tests/unit/test_commit.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,11 @@ def test_handle_commit_ai_mode(self, mock_run_command, mock_get_ai_command):
446446
handle_commit(args)
447447

448448
mock_get_ai_command.assert_called_once_with()
449-
mock_run_command.assert_called_once_with("git commit -m 'feat: add feature'")
449+
# run_command is called with settings and command
450+
mock_run_command.assert_called_once()
451+
call_args = mock_run_command.call_args[0]
452+
assert len(call_args) == 2
453+
assert call_args[1] == "git commit -m 'feat: add feature'"
450454

451455
@patch("tgit.commit.get_ai_command")
452456
@patch("tgit.commit.run_command")
@@ -458,7 +462,11 @@ def test_handle_commit_no_message(self, mock_run_command, mock_get_ai_command):
458462
handle_commit(args)
459463

460464
mock_get_ai_command.assert_called_once_with()
461-
mock_run_command.assert_called_once_with("git commit -m 'feat: add feature'")
465+
# run_command is called with settings and command
466+
mock_run_command.assert_called_once()
467+
call_args = mock_run_command.call_args[0]
468+
assert len(call_args) == 2
469+
assert call_args[1] == "git commit -m 'feat: add feature'"
462470

463471
@patch("tgit.commit.get_ai_command")
464472
@patch("tgit.commit.run_command")
@@ -470,7 +478,11 @@ def test_handle_commit_single_message_valid_type(self, mock_run_command, mock_ge
470478
handle_commit(args)
471479

472480
mock_get_ai_command.assert_called_once_with(specified_type="feat")
473-
mock_run_command.assert_called_once_with("git commit -m 'feat: add feature'")
481+
# run_command is called with settings and command
482+
mock_run_command.assert_called_once()
483+
call_args = mock_run_command.call_args[0]
484+
assert len(call_args) == 2
485+
assert call_args[1] == "git commit -m 'feat: add feature'"
474486

475487
def test_handle_commit_single_message_invalid_type(self):
476488
"""Test handle_commit with single message (invalid type)."""
@@ -495,7 +507,8 @@ def test_handle_commit_full_message(self, mock_settings, mock_run_command, mock_
495507
mock_get_commit_command.assert_called_once_with(
496508
"feat", None, "add feature", use_emoji=False, is_breaking=False
497509
)
498-
mock_run_command.assert_called_once_with("git commit -m 'feat: add feature'")
510+
# run_command is called with settings and command
511+
mock_run_command.assert_called_once_with(mock_settings, "git commit -m 'feat: add feature'")
499512

500513
@patch("tgit.commit.get_commit_command")
501514
@patch("tgit.commit.run_command")
@@ -511,7 +524,8 @@ def test_handle_commit_with_scope(self, mock_settings, mock_run_command, mock_ge
511524
mock_get_commit_command.assert_called_once_with(
512525
"feat", "auth", "add login", use_emoji=False, is_breaking=False
513526
)
514-
mock_run_command.assert_called_once_with("git commit -m 'feat(auth): add login'")
527+
# run_command is called with settings and command
528+
mock_run_command.assert_called_once_with(mock_settings, "git commit -m 'feat(auth): add login'")
515529

516530
@patch("tgit.commit.get_commit_command")
517531
@patch("tgit.commit.run_command")
@@ -527,6 +541,8 @@ def test_handle_commit_with_emoji_override(self, mock_settings, mock_run_command
527541
mock_get_commit_command.assert_called_once_with(
528542
"feat", None, "add feature", use_emoji=True, is_breaking=False
529543
)
544+
# run_command is called with settings and command
545+
mock_run_command.assert_called_once_with(mock_settings, "git commit -m '✨ feat: add feature'")
530546

531547
def test_handle_commit_invalid_type_in_full_message(self):
532548
"""Test handle_commit with invalid type in full message."""

tests/unit/test_utils.py

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55

66
from tgit.utils import run_command, simple_run_command, get_commit_command, type_emojis
7+
from tgit.types import TGitSettings, CommitSettings
78

89

910
class TestRunCommand:
@@ -16,9 +17,14 @@ def test_run_command_user_confirms(self, mock_confirm, mock_popen):
1617
process_mock = mock_popen.return_value
1718
process_mock.communicate.return_value = (b"output", b"")
1819
process_mock.returncode = 0
20+
settings = TGitSettings(
21+
commit=CommitSettings(emoji=False, types=[]),
22+
api_key="", api_url="", model="",
23+
show_command=False, skip_confirm=False
24+
)
1925

2026
# Act
21-
run_command("echo 'test'")
27+
run_command(settings, "echo 'test'")
2228

2329
# Assert
2430
mock_confirm.assert_called_once_with("Do you want to continue?", default=True)
@@ -30,89 +36,102 @@ def test_run_command_user_cancels(self, mock_confirm, mock_popen):
3036
"""Test run_command when user cancels execution."""
3137
# Arrange
3238
mock_confirm.return_value.ask.return_value = False
39+
settings = TGitSettings(
40+
commit=CommitSettings(emoji=False, types=[]),
41+
api_key="", api_url="", model="",
42+
show_command=False, skip_confirm=False
43+
)
3344

3445
# Act
35-
run_command("echo 'test'")
46+
run_command(settings, "echo 'test'")
3647

3748
# Assert
3849
mock_confirm.assert_called_once_with("Do you want to continue?", default=True)
3950
mock_popen.assert_not_called()
4051

41-
@patch("tgit.utils.settings")
4252
@patch("tgit.utils.subprocess.Popen")
4353
@patch("tgit.utils.questionary.confirm")
44-
def test_run_command_skip_confirm(self, mock_confirm, mock_popen, mock_settings):
54+
def test_run_command_skip_confirm(self, mock_confirm, mock_popen):
4555
"""Test run_command when skip_confirm is True."""
4656
# Arrange
47-
mock_settings.skip_confirm = True
48-
mock_settings.show_command = False
57+
settings = TGitSettings(
58+
commit=CommitSettings(emoji=False, types=[]),
59+
api_key="", api_url="", model="",
60+
show_command=False, skip_confirm=True
61+
)
4962
process_mock = mock_popen.return_value
5063
process_mock.communicate.return_value = (b"output", b"")
5164
process_mock.returncode = 0
5265

5366
# Act
54-
run_command("echo 'test'")
67+
run_command(settings, "echo 'test'")
5568

5669
# Assert
5770
mock_confirm.assert_not_called()
5871
mock_popen.assert_called_once()
5972

60-
@patch("tgit.utils.settings")
6173
@patch("tgit.utils.console.print")
6274
@patch("tgit.utils.subprocess.Popen")
6375
@patch("tgit.utils.questionary.confirm")
64-
def test_run_command_show_command(self, mock_confirm, mock_popen, mock_console_print, mock_settings):
76+
def test_run_command_show_command(self, mock_confirm, mock_popen, mock_console_print):
6577
"""Test run_command when show_command is True."""
6678
# Arrange
67-
mock_settings.show_command = True
68-
mock_settings.skip_confirm = False
79+
settings = TGitSettings(
80+
commit=CommitSettings(emoji=False, types=[]),
81+
api_key="", api_url="", model="",
82+
show_command=True, skip_confirm=False
83+
)
6984
mock_confirm.return_value.ask.return_value = True
7085
process_mock = mock_popen.return_value
7186
process_mock.communicate.return_value = (b"output", b"")
7287
process_mock.returncode = 0
7388

7489
# Act
75-
run_command("echo 'test'")
90+
run_command(settings, "echo 'test'")
7691

7792
# Assert
7893
assert mock_console_print.call_count >= 1
7994
mock_confirm.assert_called_once()
8095
mock_popen.assert_called_once()
8196

82-
@patch("tgit.utils.settings")
8397
@patch("tgit.utils.subprocess.Popen")
8498
@patch("tgit.utils.questionary.confirm")
8599
@patch("tgit.utils.sys.stderr.write")
86-
def test_run_command_error_handling(self, mock_stderr_write, mock_confirm, mock_popen, mock_settings):
100+
def test_run_command_error_handling(self, mock_stderr_write, mock_confirm, mock_popen):
87101
"""Test run_command error handling."""
88102
# Arrange
89-
mock_settings.skip_confirm = True
90-
mock_settings.show_command = False
103+
settings = TGitSettings(
104+
commit=CommitSettings(emoji=False, types=[]),
105+
api_key="", api_url="", model="",
106+
show_command=False, skip_confirm=True
107+
)
91108
mock_confirm.return_value.ask.return_value = True
92109
process_mock = mock_popen.return_value
93110
process_mock.communicate.return_value = (b"", b"error message")
94111
process_mock.returncode = 1
95112

96113
# Act
97-
run_command("failing command")
114+
run_command(settings, "failing command")
98115

99116
# Assert
100117
mock_stderr_write.assert_called_once_with("error message")
101118

102-
@patch("tgit.utils.settings")
103119
@patch("tgit.utils.subprocess.Popen")
104120
@patch("tgit.utils.questionary.confirm")
105-
def test_run_command_multiple_commands(self, mock_confirm, mock_popen, mock_settings):
121+
def test_run_command_multiple_commands(self, mock_confirm, mock_popen):
106122
"""Test run_command with multiple commands."""
107123
# Arrange
108-
mock_settings.skip_confirm = True
109-
mock_settings.show_command = False
124+
settings = TGitSettings(
125+
commit=CommitSettings(emoji=False, types=[]),
126+
api_key="", api_url="", model="",
127+
show_command=False, skip_confirm=True
128+
)
110129
process_mock = mock_popen.return_value
111130
process_mock.communicate.return_value = (b"output", b"")
112131
process_mock.returncode = 0
113132

114133
# Act
115-
run_command("echo 'first'\necho 'second'")
134+
run_command(settings, "echo 'first'\necho 'second'")
116135

117136
# Assert
118137
assert mock_popen.call_count == 2

0 commit comments

Comments
 (0)