diff --git a/src/borg/helpers/nanorst.py b/src/borg/helpers/nanorst.py index dc2f6d1a7..3d7c3316e 100644 --- a/src/borg/helpers/nanorst.py +++ b/src/borg/helpers/nanorst.py @@ -159,6 +159,12 @@ def rst_to_text(text, state_hook=None, references=None): state = "text" out.write(char) + if state == "code-block": + # without this, we would need 2 empty lines after a code block, + # even if it is at the end of the string anyway. + state_hook(state, "text", out) + state = "text" + assert state == "text", "Invalid final state %r (This usually indicates unmatched */**)" % state return out.getvalue() diff --git a/src/borg/testsuite/archiver/help_cmd_test.py b/src/borg/testsuite/archiver/help_cmd_test.py index acea7151f..e411244a9 100644 --- a/src/borg/testsuite/archiver/help_cmd_test.py +++ b/src/borg/testsuite/archiver/help_cmd_test.py @@ -2,7 +2,7 @@ import pytest from ...constants import * # NOQA from ...helpers.nanorst import RstToTextLazy, rst_to_terminal -from . import Archiver, cmd +from . import Archiver, cmd, exec_cmd def get_all_parsers(): @@ -14,7 +14,9 @@ def get_all_parsers(): def discover_level(prefix, parser, Archiver, extra_choices=None): choices = {} for action in parser._actions: - if action.choices is not None and "SubParsersAction" in str(action.__class__): + if action.choices is not None and ( + "SubParsersAction" in str(action.__class__) or "ActionSubCommands" in str(action.__class__) + ): for command, parser in action.choices.items(): choices[prefix + command] = parser if extra_choices is not None: @@ -62,3 +64,15 @@ def test_main_help_epilog(archiver): assert "match-archives" in help_output assert "placeholders" in help_output assert "compression" in help_output + + +@pytest.mark.parametrize("command", list(get_all_parsers().keys())) +def test_commands_help_invocation(archiver, command): + if command == "borgfs": + ret, output = exec_cmd("--help", archiver=Archiver(prog="borgfs"), fork=False) + assert ret == 0 + else: + args = command.split() + output = cmd(archiver, *args, "--help", exit_code=0) + assert "usage:" in output + assert "Traceback (most recent call last):" not in output diff --git a/src/borg/testsuite/helpers/nanorst_test.py b/src/borg/testsuite/helpers/nanorst_test.py index dad408db0..b47db6c4a 100644 --- a/src/borg/testsuite/helpers/nanorst_test.py +++ b/src/borg/testsuite/helpers/nanorst_test.py @@ -36,3 +36,9 @@ def test_undefined_ref(): with pytest.raises(ValueError) as exc_info: rst_to_text("See :ref:`foo`.") assert "Undefined reference" in str(exc_info.value) + + +def test_code_block_end_of_string(): + # check that there is no unexpected exception if a code block + # is not followed by blank lines, but the string just ends. + assert rst_to_text("This is a code block::\n\n borg --help") == "This is a code block:\n\n borg --help"