Skip to content

Commit

Permalink
add unit tests for config.py
Browse files Browse the repository at this point in the history
  • Loading branch information
mackenzie-grimes-noaa committed Jun 22, 2023
1 parent 1b1e002 commit 23053a0
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 10 deletions.
9 changes: 4 additions & 5 deletions python/idsse_common/idsse/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Config:
"""Configuration data class"""

def __init__(self,
config: Union[dict, str],
config: Union[dict, list[dict], str],
keys: Union[list, str] = None,
recursive: bool = False,
ignore_missing: bool = False) -> None:
Expand Down Expand Up @@ -116,7 +116,7 @@ def _from_config_dict(self, config_dict: dict, keys: str) -> Self:
# update the instance dictionary to hold all configuration attributes
self.__dict__.update(config_dict)

def _from_config_dicts(self, config_dicts, keys: str) -> Self:
def _from_config_dicts(self, config_dicts: list[dict], keys: str) -> Self:
self._from_config_dict(config_dicts[0], keys)
for config_dict in config_dicts[1:]:
# if inherited class takes only one argument
Expand All @@ -127,7 +127,7 @@ def _from_config_dicts(self, config_dicts, keys: str) -> Self:
self._next._previous = self # pylint: disable=protected-access


def _example():
def _example(): # pragma: no cover
class NameAsKeyConfig(Config):
"""Testing config class the uses class name as key"""
def __init__(self, config: Union[dict, str]) -> None:
Expand Down Expand Up @@ -197,7 +197,6 @@ def get_config_dict(key: Union[list, str]) -> dict:
logging.info('Metaphor:', config.metaphor)


if __name__ == '__main__':
if __name__ == '__main__': # pragma: no cover
import random

_example()
55 changes: 50 additions & 5 deletions python/idsse_common/test/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
def test_load_from_dict_without_key():
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.a_key = None
super().__init__(config, '')
Expand All @@ -32,6 +33,7 @@ def __init__(self, config: dict) -> None:
def test_load_from_dict_as_string_without_key():
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.some_key = None
super().__init__(config, '')
Expand All @@ -43,6 +45,7 @@ def __init__(self, config: dict) -> None:
def test_load_from_dict_with_name_key():
class NameAsKeyConfig(Config):
"""Config class that class name as the key to find config data"""

def __init__(self, config: dict) -> None:
self.best_key = None
super().__init__(config, None)
Expand All @@ -54,17 +57,20 @@ def __init__(self, config: dict) -> None:
def test_load_from_dict_require_string_key():
class RequireKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict, key: str) -> None:
self.some_key = None
super().__init__(config, key)

config = RequireKeyConfig('{"custom_key": {"some_key": "value found"}}', 'custom_key')
config = RequireKeyConfig(
'{"custom_key": {"some_key": "value found"}}', 'custom_key')
assert config.some_key == 'value found'


def test_load_from_dict_require_list_key():
class RequireKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict, key: list) -> None:
self.some_key = None
super().__init__(config, key)
Expand All @@ -78,6 +84,7 @@ def __init__(self, config: dict, key: list) -> None:
def test_load_with_missing_attribute_should_fail():
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.a_key = None
super().__init__(config, '')
Expand All @@ -86,9 +93,40 @@ def __init__(self, config: dict) -> None:
WithoutKeyConfig({'diff_key': 'value found'})


def test_config_str_with_no_files_raises_error(monkeypatch: MonkeyPatch):
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: str) -> None:
self.a_key = None
super().__init__(config, '')

monkeypatch.setattr('glob.glob', Mock(return_value=[]))

with pytest.raises(FileNotFoundError):
WithoutKeyConfig('wont_be_found')


def test_config_list_of_dicts_succeeds():
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.a_key = None
self.b_key = None
super().__init__(config, '', ignore_missing=True)

config = WithoutKeyConfig(
[{'a_key': 'value for a'}, {'b_key': 'value for b'}])

assert config.a_key == 'value for a'
assert config.next.b_key == 'value for b'


def test_load_with_ignore_missing_attribute():
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.a_key = None
self.b_key = None
Expand All @@ -101,6 +139,7 @@ def __init__(self, config: dict) -> None:
def test_load_from_file(monkeypatch: MonkeyPatch):
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.y_this_is_a_key = None
super().__init__(config, '')
Expand All @@ -118,15 +157,18 @@ def __init__(self, config: dict) -> None:
def test_load_from_files_with_out_key(monkeypatch: MonkeyPatch):
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.y_this_is_a_key = None
super().__init__(config, [])

monkeypatch.setattr('glob.glob', Mock(return_value=['filename1', 'filename2']))
monkeypatch.setattr('glob.glob', Mock(
return_value=['filename1', 'filename2']))

read_data = [json.dumps({"y_this_is_a_key": "value found in file1"}),
json.dumps({"y_this_is_a_key": "value found in file2"})]
mock_files = Mock(side_effect=(mock_open(read_data=data).return_value for data in read_data))
mock_files = Mock(side_effect=(
mock_open(read_data=data).return_value for data in read_data))
monkeypatch.setattr('builtins.open', mock_files)

config = WithoutKeyConfig('path/to/dir')
Expand All @@ -139,15 +181,18 @@ def __init__(self, config: dict) -> None:
def test_load_from_files_with_key(monkeypatch: MonkeyPatch):
class WithoutKeyConfig(Config):
"""Config class that doesn't use a key to find config data"""

def __init__(self, config: dict) -> None:
self.y_this_is_a_key = None
super().__init__(config, 'config_key')

monkeypatch.setattr('glob.glob', Mock(return_value=['filename1', 'filename2']))
monkeypatch.setattr('glob.glob', Mock(
return_value=['filename1', 'filename2']))

read_data = [json.dumps({"config_key": {"y_this_is_a_key": "value found in file1"}}),
json.dumps({"config_key": {"y_this_is_a_key": "value found in file2"}})]
mock_files = Mock(side_effect=(mock_open(read_data=data).return_value for data in read_data))
mock_files = Mock(side_effect=(
mock_open(read_data=data).return_value for data in read_data))
monkeypatch.setattr('builtins.open', mock_files)

config = WithoutKeyConfig('path/to/dir')
Expand Down

0 comments on commit 23053a0

Please sign in to comment.