Marco Ricci commited on 2026-08-19 21:32:12
Zeige 1 geänderte Dateien mit 52 Einfügungen und 0 Löschungen.
Add a test for non-applicability of the eager option scan step for command-lines without eager options, and a test for idempotence of the eager option scan step on every (normalized) command-line. As with the test for normalized command-lines, the test for non-applicability on non-eager command-lines is a smoke test, combining the check for lack of eager options and the check that the scan step also detects no eager options into a single unit.
| ... | ... |
@@ -1735,6 +1735,41 @@ class Test010CLIMachinery: |
| 1735 | 1735 |
assert actual_result.state == data_tuple.expected_result.state |
| 1736 | 1736 |
assert actual_result == data_tuple.expected_result |
| 1737 | 1737 |
|
| 1738 |
+ @hypothesis.given( |
|
| 1739 |
+ starting_state=Strategies.parse_states( |
|
| 1740 |
+ normalized=True, allow_eager=False |
|
| 1741 |
+ ) |
|
| 1742 |
+ ) |
|
| 1743 |
+ def test_non_eager_starting_states_are_non_eager( |
|
| 1744 |
+ self, |
|
| 1745 |
+ starting_state: cli_machinery.ParseState, |
|
| 1746 |
+ ) -> None: |
|
| 1747 |
+ command_line = starting_state.command_line |
|
| 1748 |
+ canon_map = starting_state.subcommand.canon_map |
|
| 1749 |
+ for token in command_line: |
|
| 1750 |
+ tokentype = cli_machinery.CommandLineTokenType.classify(token) |
|
| 1751 |
+ assert ( |
|
| 1752 |
+ tokentype != cli_machinery.CommandLineTokenType.SHORT_OPTION |
|
| 1753 |
+ ), f"Short option {token!r} not allowed in normalized command-line"
|
|
| 1754 |
+ assert ( |
|
| 1755 |
+ tokentype != cli_machinery.CommandLineTokenType.POSITIONAL |
|
| 1756 |
+ ), ( |
|
| 1757 |
+ f"Positional argument {token!r} not allowed "
|
|
| 1758 |
+ "in normalized command-line without preceding " |
|
| 1759 |
+ "end-of-options token" |
|
| 1760 |
+ ) |
|
| 1761 |
+ if tokentype == cli_machinery.CommandLineTokenType.END_OF_OPTIONS: |
|
| 1762 |
+ break |
|
| 1763 |
+ assert tokentype == cli_machinery.CommandLineTokenType.LONG_OPTION |
|
| 1764 |
+ opt_name = token.split("=")[0] if "=" in token else token
|
|
| 1765 |
+ opt = cast("cli_machinery.CLIOption", canon_map[opt_name])
|
|
| 1766 |
+ assert not opt.eager, ( |
|
| 1767 |
+ f"Eager option {token!r} not allowed in non-eager command-line"
|
|
| 1768 |
+ ) |
|
| 1769 |
+ |
|
| 1770 |
+ result = cli_machinery.scan_for_eager_options(starting_state) |
|
| 1771 |
+ assert result == cli_machinery.ParseResult.unit(starting_state) |
|
| 1772 |
+ |
|
| 1738 | 1773 |
@hypothesis.given( |
| 1739 | 1774 |
data_tuple=Strategies.scan_for_eager_options_parser_states() |
| 1740 | 1775 |
) |
| ... | ... |
@@ -1748,6 +1783,23 @@ class Test010CLIMachinery: |
| 1748 | 1783 |
assert actual_result.state == data_tuple.expected_result.state |
| 1749 | 1784 |
assert actual_result == data_tuple.expected_result |
| 1750 | 1785 |
|
| 1786 |
+ @hypothesis.given( |
|
| 1787 |
+ data_tuple=Strategies.scan_for_eager_options_parser_states() |
|
| 1788 |
+ ) |
|
| 1789 |
+ def test_scan_for_eager_options_is_idempotent( |
|
| 1790 |
+ self, |
|
| 1791 |
+ data_tuple: ParseStateAndExpectedResult, |
|
| 1792 |
+ ) -> None: |
|
| 1793 |
+ first_result = cli_machinery.scan_for_eager_options( |
|
| 1794 |
+ data_tuple.starting_state |
|
| 1795 |
+ ) |
|
| 1796 |
+ assert first_result.state == data_tuple.expected_result.state |
|
| 1797 |
+ assert first_result == data_tuple.expected_result |
|
| 1798 |
+ new_start_state = data_tuple.expected_result.state |
|
| 1799 |
+ second_result = cli_machinery.scan_for_eager_options(new_start_state) |
|
| 1800 |
+ assert second_result.state == data_tuple.expected_result.state |
|
| 1801 |
+ assert second_result == data_tuple.expected_result |
|
| 1802 |
+ |
|
| 1751 | 1803 |
|
| 1752 | 1804 |
class TestHelpOutput: |
| 1753 | 1805 |
"""Tests for all command-line interfaces' `--help` output.""" |
| 1754 | 1806 |