From a8674ceae4c00aaec03ba59171e2239b20bebeaf Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Mon, 28 Oct 2024 22:01:44 -0700 Subject: [PATCH] Add some testing of CLI loading of config The unit testing was lacking any testing at all. This change adds coverage of CLI loading of configuration files. Signed-off-by: Eric Brown --- precli/cli/main.py | 31 +++++++++++++++++------- tests/unit/cli/test_main.py | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 tests/unit/cli/test_main.py diff --git a/precli/cli/main.py b/precli/cli/main.py index 46ad118e..e4dba11d 100644 --- a/precli/cli/main.py +++ b/precli/cli/main.py @@ -7,6 +7,7 @@ import sys import tempfile import zipfile +from argparse import ArgumentParser from datetime import datetime from importlib import metadata from urllib.parse import urljoin @@ -37,7 +38,7 @@ def setup_arg_parser(): - parser = argparse.ArgumentParser( + parser = ArgumentParser( description="precli - a static analysis security tool", formatter_class=argparse.RawDescriptionHelpFormatter, ) @@ -163,20 +164,32 @@ def setup_arg_parser(): parser.print_usage() sys.exit(2) - return args + return parser, args -def load_config(config: dict, targets: list[str]) -> dict: +def load_config( + parser: ArgumentParser, config: dict, targets: list[str] +) -> dict: if config: - return tomllib.load(config) + try: + return tomllib.load(config) + except tomllib.TOMLDecodeError as err: + parser.error( + f"argument -c/--config: can't load '{config.name}': {err}" + ) else: default_confs = (".precli.toml", "precli.toml", "pyproject.toml") for target in filter(os.path.isdir, targets): for conf in default_confs: path = pathlib.Path(target) / conf - if path.exists(): - with open(path, "rb") as f: - return tomllib.load(f) + try: + if path.exists(): + with open(path, "rb") as f: + return tomllib.load(f) + except tomllib.TOMLDecodeError: + # TODO: Log but don't exit + pass + return {} @@ -364,10 +377,10 @@ def main(): logging.getLogger("urllib3").setLevel(debug) # Setup the command line arguments - args = setup_arg_parser() + parser, args = setup_arg_parser() # Load optional configuration file - config = load_config(args.config, args.targets) + config = load_config(parser, args.config, args.targets) # CLI enabled/disabled override any config in files config["enabled"] = ( diff --git a/tests/unit/cli/test_main.py b/tests/unit/cli/test_main.py new file mode 100644 index 00000000..ca07bd54 --- /dev/null +++ b/tests/unit/cli/test_main.py @@ -0,0 +1,47 @@ +# Copyright 2024 Secure Sauce LLC +# SPDX-License-Identifier: BUSL-1.1 +import json +import os +import tempfile +from unittest import mock + +import pytest + +from precli.cli import main + + +class TestMain: + @classmethod + def setup_class(cls): + cls.base_path = os.path.join( + "tests", + "unit", + "cli", + "examples", + ) + cls.current_dir = os.getcwd() + + @classmethod + def teardown_class(cls): + os.chdir(cls.current_dir) + + + @mock.patch("sys.argv", ["precli", "-c", "missing_file.toml"]) + def test_main_config_not_found(self): + with pytest.raises(SystemExit) as excinfo: + main.main() + assert str(excinfo.value) == "2" + + @mock.patch("sys.argv", ["precli", "-c", "not_toml.json", "."]) + def test_main_invalid_config(self): + temp_dir = tempfile.mkdtemp() + os.chdir(temp_dir) + config = { + "enable": ["PY001"] + } + with open("not_toml.json", "w") as fd: + json.dump(config, fd) + + with pytest.raises(SystemExit) as excinfo: + main.main() + assert str(excinfo.value) == "2"