Skip to content

Commit

Permalink
_cli, test: add test coverage for more CLI helpers (#401)
Browse files Browse the repository at this point in the history
Signed-off-by: William Woodruff <william@trailofbits.com>

Signed-off-by: William Woodruff <william@trailofbits.com>
  • Loading branch information
woodruffw authored Nov 2, 2022
1 parent 457c093 commit af0d743
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 22 deletions.
38 changes: 20 additions & 18 deletions pip_audit/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
"""
Expand All @@ -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",
Expand Down Expand Up @@ -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():
Expand All @@ -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)
Expand Down
4 changes: 0 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
50 changes: 50 additions & 0 deletions test/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit af0d743

Please sign in to comment.