diff --git a/fenn/parser.py b/fenn/parser.py index 221517d..2914c6b 100644 --- a/fenn/parser.py +++ b/fenn/parser.py @@ -45,6 +45,12 @@ def _config_missing(self) -> None: self._config_file, ) + def _config_invalid(self, detail: str) -> None: + message = f"Configuration file {self._config_file} is invalid: {detail}" + logger.exception(message) + + raise ValueError(message) + def load_configuration(self) -> Any: """Loads the YAML configuration into the _args dictionary.""" @@ -53,8 +59,17 @@ def load_configuration(self) -> Any: # File exists → load YAML with open(self._config_file) as f: - self._args = yaml.safe_load(f) - self._args["project"] = self._config_file.stem + loaded = yaml.safe_load(f) + + if loaded is None: + self._config_invalid("the file is empty") + if not isinstance(loaded, dict): + self._config_invalid( + f"the top level must be a mapping, got {type(loaded).__name__}" + ) + + self._args = loaded + self._args["project"] = self._config_file.stem return self._args diff --git a/tests/unit/test_parser.py b/tests/unit/test_parser.py new file mode 100644 index 0000000..8c7d147 --- /dev/null +++ b/tests/unit/test_parser.py @@ -0,0 +1,43 @@ +"""Tests for `fenn.parser.Parser.load_configuration`.""" + +import pytest + +from fenn.parser import Parser + + +@pytest.fixture(autouse=True) +def _reset_parser(): + Parser.reset() + yield + Parser.reset() + + +def test_load_configuration_reads_a_mapping(tmp_path): + cfg = tmp_path / "fenn.yaml" + cfg.write_text("logger:\n dir: logs\n") + + args = Parser(cfg).load_configuration() + + assert args["logger"] == {"dir": "logs"} + assert args["project"] == "fenn" + + +def test_load_configuration_missing_file_raises_file_not_found(tmp_path): + with pytest.raises(FileNotFoundError): + Parser(tmp_path / "missing.yaml").load_configuration() + + +def test_load_configuration_empty_file_raises_value_error(tmp_path): + cfg = tmp_path / "fenn.yaml" + cfg.write_text("") + + with pytest.raises(ValueError, match="empty"): + Parser(cfg).load_configuration() + + +def test_load_configuration_non_mapping_raises_value_error(tmp_path): + cfg = tmp_path / "fenn.yaml" + cfg.write_text("- just\n- a\n- list\n") + + with pytest.raises(ValueError, match="mapping"): + Parser(cfg).load_configuration()