Skip to content

Commit 6344e23

Browse files
committed
More test updates.
1 parent 3104948 commit 6344e23

1 file changed

Lines changed: 63 additions & 25 deletions

File tree

tests/test_argparse_custom.py

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -343,11 +343,12 @@ def test_register_argparse_argument_parameter() -> None:
343343

344344

345345
def test_parser_attachment() -> None:
346+
"""Test the monkey-patched attach_parser and detach_parser methods on argparse._SubParsersAction."""
346347
# Attach a parser as a subcommand
347-
root_parser = Cmd2ArgumentParser(description="root command")
348+
root_parser = Cmd2ArgumentParser(prog="root", description="root command")
348349
root_subparsers = root_parser.add_subparsers()
349350

350-
child_parser = Cmd2ArgumentParser(description="child command")
351+
child_parser = Cmd2ArgumentParser(prog="child", description="child command")
351352
root_subparsers.attach_parser( # type: ignore[attr-defined]
352353
"child",
353354
child_parser,
@@ -385,11 +386,24 @@ def test_parser_attachment() -> None:
385386

386387

387388
def test_subcommand_attachment() -> None:
388-
# Attach a subcommand
389-
root_parser = Cmd2ArgumentParser(description="root command")
389+
"""Test Cmd2ArgumentParser convenience methods for attaching and detaching subcommands."""
390+
391+
###############################
392+
# Set up parsers
393+
###############################
394+
root_parser = Cmd2ArgumentParser(prog="root", description="root command")
390395
root_subparsers = root_parser.add_subparsers()
391396

392-
child_parser = Cmd2ArgumentParser(description="child command")
397+
child_parser = Cmd2ArgumentParser(prog="child", description="child command")
398+
child_subparsers = child_parser.add_subparsers() # Must have subparsers to host grandchild
399+
400+
grandchild_parser = Cmd2ArgumentParser(prog="grandchild", description="grandchild command")
401+
402+
###############################
403+
# Attach subcommands
404+
###############################
405+
406+
# Attach child to root
393407
root_parser.attach_subcommand(
394408
[],
395409
"child",
@@ -398,35 +412,59 @@ def test_subcommand_attachment() -> None:
398412
aliases=["child_alias"],
399413
)
400414

401-
# Verify the same parser instance was used
415+
# Attach grandchild to child
416+
root_parser.attach_subcommand(
417+
["child"],
418+
"grandchild",
419+
grandchild_parser,
420+
help="a grandchild command",
421+
)
422+
423+
###############################
424+
# Verify hierarchy navigation
425+
###############################
426+
427+
assert root_parser._find_parser(["child", "grandchild"]) is grandchild_parser
428+
assert root_parser._find_parser(["child"]) is child_parser
429+
assert root_parser._find_parser([]) is root_parser
430+
431+
###############################
432+
# Verify attachments
433+
###############################
434+
435+
# Verify child attachment and aliases
402436
assert root_subparsers._name_parser_map["child"] is child_parser
403437
assert root_subparsers._name_parser_map["child_alias"] is child_parser
404438

405-
# Verify an action with the help text exists
406-
child_action = None
407-
for action in root_subparsers._choices_actions:
408-
if action.dest == "child":
409-
child_action = action
410-
break
411-
assert child_action is not None
412-
assert child_action.help == "a child command"
439+
# Verify grandchild attachment
440+
assert child_subparsers._name_parser_map["grandchild"] is grandchild_parser
413441

414-
# Detatch the subcommand
415-
detached_parser = root_parser.detach_subcommand([], "child")
442+
###############################
443+
# Detach subcommands
444+
###############################
416445

417-
# Verify subcommand and its aliases were removed
418-
assert detached_parser is child_parser
446+
# Detach grandchild from child
447+
detached_grandchild = root_parser.detach_subcommand(["child"], "grandchild")
448+
assert detached_grandchild is grandchild_parser
449+
assert "grandchild" not in child_subparsers._name_parser_map
450+
451+
# Detach child from root
452+
detached_child = root_parser.detach_subcommand([], "child")
453+
assert detached_child is child_parser
419454
assert "child" not in root_subparsers._name_parser_map
420455
assert "child_alias" not in root_subparsers._name_parser_map
421456

422-
# Verify the help text action was removed
423-
choices_actions = [action.dest for action in root_subparsers._choices_actions]
424-
assert "child" not in choices_actions
457+
###############################
458+
# Test error handling
459+
###############################
425460

426-
# Verify it raises a ValueError when subcommand does not exist
427-
expected_err = "Subcommand 'fake' not found"
428-
with pytest.raises(ValueError, match=expected_err):
429-
assert root_parser.detach_subcommand([], "fake") is None
461+
# Verify ValueError when path is invalid (find_parser fails)
462+
with pytest.raises(ValueError, match="Subcommand 'nonexistent' not found"):
463+
root_parser.detach_subcommand(["nonexistent"], "anything")
464+
465+
# Verify ValueError when path is valid but subcommand name is wrong
466+
with pytest.raises(ValueError, match="Subcommand 'fake' not found in 'root'"):
467+
root_parser.detach_subcommand([], "fake")
430468

431469

432470
def test_completion_items_as_choices(capsys) -> None:

0 commit comments

Comments
 (0)