-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Test command line argument parsing (#12795)
- Loading branch information
Showing
3 changed files
with
261 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
from __future__ import annotations | ||
|
||
import os.path | ||
from typing import Any | ||
|
||
import pytest | ||
|
||
from sphinx.cmd import make_mode | ||
from sphinx.cmd.build import get_parser | ||
from sphinx.cmd.make_mode import run_make_mode | ||
|
||
DEFAULTS = { | ||
'filenames': [], | ||
'jobs': 1, | ||
'force_all': False, | ||
'freshenv': False, | ||
'doctreedir': None, | ||
'confdir': None, | ||
'noconfig': False, | ||
'define': [], | ||
'htmldefine': [], | ||
'tags': [], | ||
'nitpicky': False, | ||
'verbosity': 0, | ||
'quiet': False, | ||
'really_quiet': False, | ||
'color': 'auto', | ||
'warnfile': None, | ||
'warningiserror': False, | ||
'keep_going': False, | ||
'traceback': False, | ||
'pdb': False, | ||
'exception_on_warning': False, | ||
} | ||
|
||
EXPECTED_BUILD_MAIN = { | ||
'builder': 'html', | ||
'sourcedir': 'source_dir', | ||
'outputdir': 'build_dir', | ||
'filenames': ['filename1', 'filename2'], | ||
'freshenv': True, | ||
'noconfig': True, | ||
'quiet': True, | ||
} | ||
|
||
EXPECTED_MAKE_MODE = { | ||
'builder': 'html', | ||
'sourcedir': 'source_dir', | ||
'outputdir': os.path.join('build_dir', 'html'), | ||
'doctreedir': os.path.join('build_dir', 'doctrees'), | ||
'filenames': ['filename1', 'filename2'], | ||
'freshenv': True, | ||
'noconfig': True, | ||
'quiet': True, | ||
} | ||
|
||
BUILDER_BUILD_MAIN = [ | ||
'--builder', | ||
'html', | ||
] | ||
BUILDER_MAKE_MODE = [ | ||
'html', | ||
] | ||
POSITIONAL_DIRS = [ | ||
'source_dir', | ||
'build_dir', | ||
] | ||
POSITIONAL_FILENAMES = [ | ||
'filename1', | ||
'filename2', | ||
] | ||
POSITIONAL = POSITIONAL_DIRS + POSITIONAL_FILENAMES | ||
POSITIONAL_MAKE_MODE = BUILDER_MAKE_MODE + POSITIONAL | ||
EARLY_OPTS = [ | ||
'--quiet', | ||
] | ||
LATE_OPTS = [ | ||
'-E', | ||
'--isolated', | ||
] | ||
OPTS = EARLY_OPTS + LATE_OPTS | ||
OPTS_BUILD_MAIN = BUILDER_BUILD_MAIN + OPTS | ||
|
||
|
||
def parse_arguments(args: list[str]) -> dict[str, Any]: | ||
parsed = vars(get_parser().parse_args(args)) | ||
return {k: v for k, v in parsed.items() if k not in DEFAULTS or v != DEFAULTS[k]} | ||
|
||
|
||
def test_build_main_parse_arguments_pos_first() -> None: | ||
# <positional...> <opts> | ||
args = [ | ||
*POSITIONAL, | ||
*OPTS, | ||
] | ||
assert parse_arguments(args) == EXPECTED_BUILD_MAIN | ||
|
||
|
||
def test_build_main_parse_arguments_pos_last() -> None: | ||
# <opts> <positional...> | ||
args = [ | ||
*OPTS, | ||
*POSITIONAL, | ||
] | ||
assert parse_arguments(args) == EXPECTED_BUILD_MAIN | ||
|
||
|
||
def test_build_main_parse_arguments_pos_middle() -> None: | ||
# <opts> <positional...> <opts> | ||
args = [ | ||
*EARLY_OPTS, | ||
*BUILDER_BUILD_MAIN, | ||
*POSITIONAL, | ||
*LATE_OPTS, | ||
] | ||
assert parse_arguments(args) == EXPECTED_BUILD_MAIN | ||
|
||
|
||
@pytest.mark.xfail(reason='sphinx-build does not yet support filenames after options') | ||
def test_build_main_parse_arguments_filenames_last() -> None: | ||
args = [ | ||
*POSITIONAL_DIRS, | ||
*OPTS, | ||
*POSITIONAL_FILENAMES, | ||
] | ||
assert parse_arguments(args) == EXPECTED_BUILD_MAIN | ||
|
||
|
||
def test_build_main_parse_arguments_pos_intermixed( | ||
capsys: pytest.CaptureFixture[str], | ||
) -> None: | ||
args = [ | ||
*EARLY_OPTS, | ||
*BUILDER_BUILD_MAIN, | ||
*POSITIONAL_DIRS, | ||
*LATE_OPTS, | ||
*POSITIONAL_FILENAMES, | ||
] | ||
with pytest.raises(SystemExit): | ||
parse_arguments(args) | ||
stderr = capsys.readouterr().err.splitlines() | ||
assert stderr[-1].endswith('error: unrecognized arguments: filename1 filename2') | ||
|
||
|
||
def test_make_mode_parse_arguments_pos_first(monkeypatch: pytest.MonkeyPatch) -> None: | ||
# -M <positional...> <opts> | ||
monkeypatch.setattr(make_mode, 'build_main', parse_arguments) | ||
args = [ | ||
*POSITIONAL_MAKE_MODE, | ||
*OPTS, | ||
] | ||
assert run_make_mode(args) == EXPECTED_MAKE_MODE | ||
|
||
|
||
def test_make_mode_parse_arguments_pos_last( | ||
monkeypatch: pytest.MonkeyPatch, | ||
capsys: pytest.CaptureFixture[str], | ||
) -> None: | ||
# -M <opts> <positional...> | ||
monkeypatch.setattr(make_mode, 'build_main', parse_arguments) | ||
args = [ | ||
*OPTS, | ||
*POSITIONAL_MAKE_MODE, | ||
] | ||
with pytest.raises(SystemExit): | ||
run_make_mode(args) | ||
stderr = capsys.readouterr().err.splitlines() | ||
assert stderr[-1].endswith('error: argument --builder/-b: expected one argument') | ||
|
||
|
||
def test_make_mode_parse_arguments_pos_middle( | ||
monkeypatch: pytest.MonkeyPatch, | ||
capsys: pytest.CaptureFixture[str], | ||
) -> None: | ||
# -M <opts> <positional...> <opts> | ||
monkeypatch.setattr(make_mode, 'build_main', parse_arguments) | ||
args = [ | ||
*EARLY_OPTS, | ||
*POSITIONAL_MAKE_MODE, | ||
*LATE_OPTS, | ||
] | ||
with pytest.raises(SystemExit): | ||
run_make_mode(args) | ||
stderr = capsys.readouterr().err.splitlines() | ||
assert stderr[-1].endswith('error: argument --builder/-b: expected one argument') | ||
|
||
|
||
@pytest.mark.xfail(reason='sphinx-build does not yet support filenames after options') | ||
def test_make_mode_parse_arguments_filenames_last( | ||
monkeypatch: pytest.MonkeyPatch, | ||
) -> None: | ||
monkeypatch.setattr(make_mode, 'build_main', parse_arguments) | ||
args = [ | ||
*BUILDER_MAKE_MODE, | ||
*POSITIONAL_DIRS, | ||
*OPTS, | ||
*POSITIONAL_FILENAMES, | ||
] | ||
assert run_make_mode(args) == EXPECTED_MAKE_MODE | ||
|
||
|
||
def test_make_mode_parse_arguments_pos_intermixed( | ||
monkeypatch: pytest.MonkeyPatch, | ||
capsys: pytest.CaptureFixture[str], | ||
) -> None: | ||
monkeypatch.setattr(make_mode, 'build_main', parse_arguments) | ||
args = [ | ||
*EARLY_OPTS, | ||
*BUILDER_MAKE_MODE, | ||
*POSITIONAL_DIRS, | ||
*LATE_OPTS, | ||
*POSITIONAL_FILENAMES, | ||
] | ||
with pytest.raises(SystemExit): | ||
run_make_mode(args) | ||
stderr = capsys.readouterr().err.splitlines() | ||
assert stderr[-1].endswith('error: argument --builder/-b: expected one argument') |