From ff276c90fff00b20c82b2456caa6a503f0a18bc6 Mon Sep 17 00:00:00 2001 From: William Woodruff Date: Wed, 2 Nov 2022 15:20:06 -0400 Subject: [PATCH] _cli, test: add test coverage for more CLI helpers Signed-off-by: William Woodruff --- pip_audit/_cli.py | 38 ++++++++++++++++++----------------- pyproject.toml | 4 ---- test/test_cli.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/pip_audit/_cli.py b/pip_audit/_cli.py index 537f6626..3a5ae3f4 100644 --- a/pip_audit/_cli.py +++ b/pip_audit/_cli.py @@ -64,7 +64,7 @@ def to_format(self, output_desc: bool) -> VulnerabilityFormat: elif self is OutputFormatChoice.Markdown: return MarkdownFormat(output_desc) else: - assert_never(self) + assert_never(self) # pragma: no cover def __str__(self) -> str: return self.value @@ -85,7 +85,7 @@ def to_service(self, timeout: int, cache_dir: Optional[Path]) -> VulnerabilitySe elif self is VulnerabilityServiceChoice.Pypi: return PyPIService(cache_dir, timeout) else: - assert_never(self) + assert_never(self) # pragma: no cover def __str__(self) -> str: return self.value @@ -109,7 +109,7 @@ def to_bool(self, format_: OutputFormatChoice) -> bool: elif self is VulnerabilityDescriptionChoice.Auto: return bool(format_ is OutputFormatChoice.Json) else: - assert_never(self) + assert_never(self) # pragma: no cover def __str__(self) -> str: return self.value @@ -131,14 +131,14 @@ def __str__(self) -> str: return self.value -def _enum_help(msg: str, e: Type[enum.Enum]) -> str: +def _enum_help(msg: str, e: Type[enum.Enum]) -> str: # pragma: no cover """ Render a `--help`-style string for the given enumeration. """ return f"{msg} (choices: {', '.join(str(v) for v in e)})" -def _fatal(msg: str) -> NoReturn: +def _fatal(msg: str) -> NoReturn: # pragma: no cover """ Log a fatal error to the standard error stream and exit. """ @@ -148,7 +148,7 @@ def _fatal(msg: str) -> NoReturn: sys.exit(1) -def _parser() -> argparse.ArgumentParser: +def _parser() -> argparse.ArgumentParser: # pragma: no cover parser = argparse.ArgumentParser( prog="pip-audit", description="audit the Python environment for dependencies with known vulnerabilities", @@ -312,13 +312,23 @@ def _parser() -> argparse.ArgumentParser: return parser -def _parse_args(parser: argparse.ArgumentParser) -> argparse.Namespace: - return parser.parse_args() +def _parse_args(parser: argparse.ArgumentParser) -> argparse.Namespace: # pragma: no cover + args = parser.parse_args() + + if args.verbose: + logging.root.setLevel("DEBUG") + + if args.output is None: + args.output = sys.stdout + + logger.debug(f"parsed arguments: {args}") + + return args def _dep_source_from_project_path( project_path: Path, resolver: ResolveLibResolver, state: AuditState -) -> DependencySource: +) -> DependencySource: # pragma: no cover # Check for a `pyproject.toml` pyproject_path = project_path / "pyproject.toml" if pyproject_path.is_file(): @@ -329,21 +339,13 @@ def _dep_source_from_project_path( _fatal(f"couldn't find a supported project file in {project_path}") -def audit() -> None: +def audit() -> None: # pragma: no cover """ The primary entrypoint for `pip-audit`. """ parser = _parser() args = _parse_args(parser) - if args.verbose: - logging.root.setLevel("DEBUG") - - if args.output is None: - args.output = sys.stdout - - logger.debug(f"parsed arguments: {args}") - service = args.vulnerability_service.to_service(args.timeout, args.cache_dir) output_desc = args.desc.to_bool(args.format) formatter = args.format.to_format(output_desc) diff --git a/pyproject.toml b/pyproject.toml index 4c0763dc..275a5723 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,10 +82,6 @@ include_trailing_comma = true [tool.black] line-length = 100 -[tool.coverage.run] -# don't attempt code coverage for the CLI entrypoints -omit = ["pip_audit/_cli.py"] - [tool.interrogate] # don't enforce documentation coverage for packaging, testing, the virtual # environment, or the CLI (which is documented separately). diff --git a/test/test_cli.py b/test/test_cli.py index 46a2b382..e884a4ad 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -2,6 +2,56 @@ import pytest import pip_audit._cli +from pip_audit._cli import ( + OutputFormatChoice, + ProgressSpinnerChoice, + VulnerabilityDescriptionChoice, + VulnerabilityServiceChoice, +) + + +class TestOutputFormatChoice: + def test_to_format_is_exhaustive(self): + for choice in OutputFormatChoice: + assert choice.to_format(False) is not None + assert choice.to_format(True) is not None + + def test_str(self): + for choice in OutputFormatChoice: + assert str(choice) == choice.value + + +class TestVulnerabilityServiceChoice: + def test_to_service_is_exhaustive(self): + for choice in VulnerabilityServiceChoice: + assert choice.to_service(0, pretend.stub()) is not None + + def test_str(self): + for choice in VulnerabilityServiceChoice: + assert str(choice) == choice.value + + +class TestVulnerabilityDescriptionChoice: + def test_to_bool_is_exhaustive(self): + for choice in VulnerabilityDescriptionChoice: + assert choice.to_bool(OutputFormatChoice.Json) in {True, False} + + def test_auto_to_bool_for_json(self): + assert VulnerabilityDescriptionChoice.Auto.to_bool(OutputFormatChoice.Json) is True + + def test_str(self): + for choice in VulnerabilityDescriptionChoice: + assert str(choice) == choice.value + + +class TestProgressSpinnerChoice: + def test_bool(self): + assert bool(ProgressSpinnerChoice.On) + assert not bool(ProgressSpinnerChoice.Off) + + def test_str(self): + for choice in ProgressSpinnerChoice: + assert str(choice) == choice.value @pytest.mark.parametrize(