Skip to content

Commit eff56e5

Browse files
yjawLee-W
authored andcommitted
test(commit): add some test for commit --body-length-limit flag
1 parent b076927 commit eff56e5

2 files changed

Lines changed: 232 additions & 3 deletions

File tree

‎commitizen/commands/commit.py‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,11 @@ def _rewrap_body(self, message: str) -> str:
121121
subject = message_parts[0]
122122
blank_line = message_parts[1]
123123
body = message_parts[2].strip()
124-
wrapped_body = textwrap.fill(
125-
body, width=body_length_limit, replace_whitespace=False
126-
)
124+
body_lines = body.split("\n")
125+
wrapped_body_lines = []
126+
for line in body_lines:
127+
wrapped_body_lines.append(textwrap.fill(line, width=body_length_limit))
128+
wrapped_body = "\n".join(wrapped_body_lines)
127129
return f"{subject}\n{blank_line}\n{wrapped_body}"
128130

129131
def manual_edit(self, message: str) -> str:

‎tests/commands/test_commit_command.py‎

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,3 +374,230 @@ def test_commit_command_with_config_message_length_limit(
374374
success_mock.reset_mock()
375375
commands.Commit(config, {"message_length_limit": 0})()
376376
success_mock.assert_called_once()
377+
378+
379+
@pytest.mark.usefixtures("staging_is_clean")
380+
def test_commit_command_with_body_length_limit_wrapping(
381+
config, success_mock: MockType, mocker: MockFixture
382+
):
383+
"""Test that long body lines are automatically wrapped to the specified limit."""
384+
mocker.patch(
385+
"questionary.prompt",
386+
return_value={
387+
"prefix": "feat",
388+
"subject": "add feature",
389+
"scope": "",
390+
"is_breaking_change": False,
391+
"body": "This is a very long line that exceeds 72 characters and should be automatically wrapped by the system to fit within the limit",
392+
"footer": "",
393+
},
394+
)
395+
396+
commit_mock = mocker.patch(
397+
"commitizen.git.commit", return_value=cmd.Command("success", "", b"", b"", 0)
398+
)
399+
400+
# Execute with body_length_limit
401+
commands.Commit(config, {"body_length_limit": 72})()
402+
success_mock.assert_called_once()
403+
404+
# Verify wrapping occurred
405+
committed_message = commit_mock.call_args[0][0]
406+
lines = committed_message.split("\n")
407+
assert lines[0] == "feat: add feature"
408+
assert lines[1] == ""
409+
body_lines = lines[2:]
410+
for line in body_lines:
411+
if line.strip():
412+
assert len(line) <= 72, (
413+
f"Line exceeds 72 chars: '{line}' ({len(line)} chars)"
414+
)
415+
416+
417+
@pytest.mark.usefixtures("staging_is_clean")
418+
def test_commit_command_with_body_length_limit_preserves_line_breaks(
419+
config, success_mock: MockType, mocker: MockFixture
420+
):
421+
"""Test that intentional line breaks (from | character) are preserved."""
422+
# Simulate what happens after multiple_line_breaker processes "line1 | line2 | line3"
423+
mocker.patch(
424+
"questionary.prompt",
425+
return_value={
426+
"prefix": "feat",
427+
"subject": "add feature",
428+
"scope": "",
429+
"is_breaking_change": False,
430+
"body": "Line1 that is very long and exceeds the limit\nLine2 that is very long and exceeds the limit\nLine3 that is very long and exceeds the limit",
431+
"footer": "",
432+
},
433+
)
434+
435+
commit_mock = mocker.patch(
436+
"commitizen.git.commit", return_value=cmd.Command("success", "", b"", b"", 0)
437+
)
438+
439+
commands.Commit(config, {"body_length_limit": 45})()
440+
success_mock.assert_called_once()
441+
442+
committed_message = commit_mock.call_args[0][0]
443+
lines = committed_message.split("\n")
444+
445+
# Should have a subject, a blank line
446+
assert lines[0] == "feat: add feature"
447+
assert lines[1] == ""
448+
# Each original line should be wrapped separately, preserving the line breaks
449+
body_lines = lines[2:]
450+
# All lines should be <= 45 chars
451+
for line in body_lines:
452+
if line.strip():
453+
assert len(line) == 45, (
454+
f"Line's length is not 45 chars: '{line}' ({len(line)} chars)"
455+
)
456+
457+
458+
@pytest.mark.usefixtures("staging_is_clean")
459+
def test_commit_command_with_body_length_limit_disabled(
460+
config, success_mock: MockType, mocker: MockFixture
461+
):
462+
"""Test that body_length_limit = 0 disables wrapping."""
463+
long_body = "This is a very long line that exceeds 72 characters and should NOT be wrapped when body_length_limit is set to 0"
464+
465+
mocker.patch(
466+
"questionary.prompt",
467+
return_value={
468+
"prefix": "feat",
469+
"subject": "add feature",
470+
"scope": "",
471+
"is_breaking_change": False,
472+
"body": long_body,
473+
"footer": "",
474+
},
475+
)
476+
477+
commit_mock = mocker.patch(
478+
"commitizen.git.commit", return_value=cmd.Command("success", "", b"", b"", 0)
479+
)
480+
481+
# Execute with body_length_limit = 0 (disabled)
482+
commands.Commit(config, {"body_length_limit": 0})()
483+
484+
success_mock.assert_called_once()
485+
486+
# Get the actual commit message
487+
committed_message = commit_mock.call_args[0][0]
488+
489+
# Verify the body was NOT wrapped (should contain the original long line)
490+
assert long_body in committed_message, "Body should not be wrapped when limit is 0"
491+
492+
493+
@pytest.mark.usefixtures("staging_is_clean")
494+
def test_commit_command_with_body_length_limit_from_config(
495+
config, success_mock: MockType, mocker: MockFixture
496+
):
497+
"""Test that body_length_limit can be set via config."""
498+
mocker.patch(
499+
"questionary.prompt",
500+
return_value={
501+
"prefix": "feat",
502+
"subject": "add feature",
503+
"scope": "",
504+
"is_breaking_change": False,
505+
"body": "This is a very long line that exceeds 50 characters and should be wrapped",
506+
"footer": "",
507+
},
508+
)
509+
510+
commit_mock = mocker.patch(
511+
"commitizen.git.commit", return_value=cmd.Command("success", "", b"", b"", 0)
512+
)
513+
514+
# Set body_length_limit in config
515+
config.settings["body_length_limit"] = 50
516+
517+
commands.Commit(config, {})()
518+
519+
success_mock.assert_called_once()
520+
521+
# Get the actual commit message
522+
committed_message = commit_mock.call_args[0][0]
523+
524+
# Verify all body lines are within the limit
525+
lines = committed_message.split("\n")
526+
body_lines = lines[2:]
527+
for line in body_lines:
528+
if line.strip():
529+
assert len(line) <= 50, (
530+
f"Line exceeds 50 chars: '{line}' ({len(line)} chars)"
531+
)
532+
533+
534+
@pytest.mark.usefixtures("staging_is_clean")
535+
def test_commit_command_body_length_limit_cli_overrides_config(
536+
config, success_mock: MockType, mocker: MockFixture
537+
):
538+
"""Test that CLI argument overrides config setting."""
539+
mocker.patch(
540+
"questionary.prompt",
541+
return_value={
542+
"prefix": "feat",
543+
"subject": "add feature",
544+
"scope": "",
545+
"is_breaking_change": False,
546+
"body": "This is a line that is longer than 40 characters but shorter than 80 characters",
547+
"footer": "",
548+
},
549+
)
550+
551+
commit_mock = mocker.patch(
552+
"commitizen.git.commit", return_value=cmd.Command("success", "", b"", b"", 0)
553+
)
554+
555+
# Set config to 40 (would wrap)
556+
config.settings["body_length_limit"] = 40
557+
558+
# Override with CLI argument to 0 (should NOT wrap)
559+
commands.Commit(config, {"body_length_limit": 0})()
560+
561+
success_mock.assert_called_once()
562+
563+
# Get the actual commit message
564+
committed_message = commit_mock.call_args[0][0]
565+
566+
# The line should NOT be wrapped (CLI override to 0 disables wrapping)
567+
assert (
568+
"This is a line that is longer than 40 characters but shorter than 80 characters"
569+
in committed_message
570+
)
571+
572+
573+
@pytest.mark.usefixtures("staging_is_clean")
574+
def test_commit_command_with_body_length_limit_no_body(
575+
config, success_mock: MockType, mocker: MockFixture
576+
):
577+
"""Test that commits without body work correctly with body_length_limit set."""
578+
mocker.patch(
579+
"questionary.prompt",
580+
return_value={
581+
"prefix": "feat",
582+
"subject": "add feature",
583+
"scope": "",
584+
"is_breaking_change": False,
585+
"body": "", # No body
586+
"footer": "",
587+
},
588+
)
589+
590+
commit_mock = mocker.patch(
591+
"commitizen.git.commit", return_value=cmd.Command("success", "", b"", b"", 0)
592+
)
593+
594+
# Execute commit with body_length_limit (should not crash)
595+
commands.Commit(config, {"body_length_limit": 72})()
596+
597+
success_mock.assert_called_once()
598+
599+
# Get the actual commit message
600+
committed_message = commit_mock.call_args[0][0]
601+
602+
# Should just be the subject line
603+
assert committed_message.strip() == "feat: add feature"

0 commit comments

Comments
 (0)