Source code for configconfig.testing

#!/usr/bin/env python3
#
#  testing.py
"""
Helpers for testing :class:`~configconfig.configvar.ConfigVar`.

.. extras-require:: testing
	:pyproject:

.. versionadded:: 0.2.0
"""
#
#  Copyright © 2020 Dominic Davis-Foster <dominic@davis-foster.co.uk>
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in all
#  copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
#  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
#  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
#  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
#  OR OTHER DEALINGS IN THE SOFTWARE.
#

# stdlib
from abc import ABC
from typing import Any, Dict, List, Type

# 3rd party
import pytest  # nodep

# this package
from configconfig.configvar import ConfigVar

__all__ = [
		"ConfigVarTest",
		"NotIntTest",
		"NotBoolTest",
		"NotStrTest",
		"ListTest",
		"DirectoryTest",
		"BoolTrueTest",
		"BoolFalseTest",
		"RequiredStringTest",
		"OptionalStringTest",
		"EnumTest",
		"DictTest",
		"test_list_int",
		"test_list_str",
		]

test_list_int = [1, 2, 3, 4]
test_list_str = ['a', 'b', 'c', 'd']


[docs]class ConfigVarTest(ABC): r""" Base class for tests of :class:`~configconfig.configvar.ConfigVar`\s. """ #: The :class:`~configconfig.configvar.ConfigVar` under test. config_var: Type[ConfigVar]
[docs]class NotIntTest(ConfigVarTest): r""" Mixin to add tests for :class:`~configconfig.configvar.ConfigVar`\s that can't be integers. """ # noqa: D400
[docs] def test_error_int(self): """ Checks that the :class:`~configconfig.configvar.ConfigVar` raises a :class:`ValueError` when passed an :class:`int`. """ # noqa: D400 with pytest.raises(ValueError): # noqa: PT011 self.config_var.get({self.config_var.__name__: 1234})
[docs]class NotBoolTest(ConfigVarTest): r""" Mixin to add tests for :class:`~configconfig.configvar.ConfigVar`\s that can't be boolean values. """ # noqa: D400
[docs] def test_error_bool(self): """ Checks that the :class:`~configconfig.configvar.ConfigVar` raises a :class:`ValueError` when passed a :class:`bool`. """ # noqa: D400 with pytest.raises(ValueError): # noqa: PT011 self.config_var.get({self.config_var.__name__: True})
[docs]class NotStrTest(ConfigVarTest): r""" Mixin to add tests for :class:`~configconfig.configvar.ConfigVar`\s that can't be strings. """ # noqa: D400
[docs] def test_error_str(self): """ Checks that the :class:`~configconfig.configvar.ConfigVar` raises a :class:`ValueError` when passed a :class:`str`. """ # noqa: D400 with pytest.raises(ValueError): # noqa: PT011 self.config_var.get({self.config_var.__name__: "a string"})
[docs]class ListTest(NotStrTest, NotBoolTest, NotIntTest, ConfigVarTest): """ Test for list configuration values. """ #: A value that is valid and should be returned unchanged. test_value: List[str] #: The default value that should be returned when no valid is given. default_value: List[str] = [] different_key_value: Dict[str, Any] = {"username": "domdfcoding"} r""" A dictionary containing one or more keys that are not the keys used by the :class:`~configconfig.configvar.ConfigVar` """
[docs] def test_success(self): """ Checks that the :class:`~configconfig.configvar.ConfigVar` can correctly parse various :class:`list` values. """ assert self.config_var.get({self.config_var.__name__: self.test_value}) == self.test_value assert self.config_var.get({self.config_var.__name__: []}) == [] assert self.config_var.get(self.different_key_value) == self.default_value assert self.config_var.get() == self.default_value assert self.config_var.get({}) == self.default_value
[docs]class DirectoryTest(NotBoolTest, NotIntTest, ConfigVarTest): """ Test for configuration values which represent directories. """ #: A value that is valid and should be returned unchanged. test_value: str #: The default value that should be returned when no valid is given. default_value: str different_key_value: Dict[str, Any] = {"username": "domdfcoding"} r""" A dictionary containing one or more keys that are not the keys used by the :class:`~configconfig.configvar.ConfigVar` """
[docs] def test_success(self): """ Checks that the :class:`~configconfig.configvar.ConfigVar` can correctly parse various directory values. """ assert self.config_var.get({self.config_var.__name__: self.test_value}) == self.test_value assert self.config_var.get(self.different_key_value) == self.default_value assert self.config_var.get() == self.default_value assert self.config_var.get({}) == self.default_value
[docs] def test_error_list_int(self): """ Checks that the :class:`~configconfig.configvar.ConfigVar` raises a :class:`ValueError` when passed a :class:`str`. """ # noqa: D400 with pytest.raises(ValueError, match="'.*' must be a <class 'str'>"): self.config_var.get({self.config_var.__name__: test_list_int})
[docs] def test_error_list_str(self): """ Checks that the :class:`~configconfig.configvar.ConfigVar` raises a :class:`ValueError` when passed a :class:`str`. """ # noqa: D400 with pytest.raises(ValueError): # noqa: PT011 self.config_var.get({self.config_var.__name__: test_list_str})
[docs]class BoolTrueTest(ConfigVarTest): """ Test for boolean configuration values which default to :py:obj:`True`. """ different_key_value: Dict[str, Any] = {"username": "domdfcoding"} r""" A dictionary containing one or more keys that are not the keys used by the :class:`~configconfig.configvar.ConfigVar` """ @property def true_values(self) -> List[Dict[str, Any]]: """ A list of values which should be considered :py:obj:`True` by the :class:`~configconfig.configvar.ConfigVar`. """ # noqa: D400 return [ {self.config_var.__name__: True}, {self.config_var.__name__: 1}, {self.config_var.__name__: 200}, {self.config_var.__name__: -1}, {self.config_var.__name__: "True"}, self.different_key_value, {}, ] @property def false_values(self) -> List[Dict[str, Any]]: """ A list of values which should be considered :py:obj:`False` by the :class:`~configconfig.configvar.ConfigVar`. """ # noqa: D400 return [ {self.config_var.__name__: 0}, {self.config_var.__name__: False}, {self.config_var.__name__: "False"}, ]
[docs] def test_empty_get(self): # noqa: D102 assert self.config_var.get()
[docs] def test_true(self): # noqa: D102 for true_value in self.true_values: assert self.config_var.get(true_value)
[docs] def test_false(self): # noqa: D102 for false_value in self.false_values: assert not self.config_var.get(false_value)
@property def wrong_values(self) -> List[Dict[str, Any]]: """ A list of values which should are of the wrong type. """ return [ {self.config_var.__name__: "a string"}, {self.config_var.__name__: test_list_int}, {self.config_var.__name__: test_list_str}, ]
[docs] def test_errors(self): # noqa: D102 for wrong_value in self.wrong_values: with pytest.raises(ValueError): # noqa: PT011 self.config_var.get(wrong_value)
[docs]class BoolFalseTest(BoolTrueTest): """ Test for boolean configuration values which default to :py:obj:`False`. """ different_key_value: Dict[str, Any] = {"username": "domdfcoding"} r""" A dictionary containing one or more keys that are not the keys used by the :class:`~configconfig.configvar.ConfigVar` """ @property def true_values(self) -> List[Dict[str, Any]]: # noqa: D102 return [ {self.config_var.__name__: True}, {self.config_var.__name__: 1}, {self.config_var.__name__: 200}, {self.config_var.__name__: -1}, {self.config_var.__name__: "True"}, ] @property def false_values(self) -> List[Dict[str, Any]]: # noqa: D102 return [ {self.config_var.__name__: 0}, {self.config_var.__name__: False}, {self.config_var.__name__: "False"}, self.different_key_value, {}, ]
[docs] def test_empty_get(self): # noqa: D102 assert not self.config_var.get()
[docs]class RequiredStringTest(ConfigVarTest): """ Test for string configuration values which are required. """ #: A value that is valid and should be returned unchanged. test_value: str
[docs] def test_empty_get(self): # noqa: D102 with pytest.raises(ValueError): # noqa: PT011 self.config_var.get()
[docs] def test_success(self): # noqa: D102 assert self.config_var.get({self.config_var.__name__: self.test_value}) == self.test_value
@property def wrong_values(self) -> List[Dict[str, Any]]: """ A list of values which should are of the wrong type. """ return [ {self.config_var.__name__: 1234}, {self.config_var.__name__: True}, {self.config_var.__name__: test_list_int}, {self.config_var.__name__: test_list_str}, ]
[docs] def test_errors(self): # noqa: D102 for wrong_value in self.wrong_values: with pytest.raises(ValueError): # noqa: PT011 self.config_var.get(wrong_value)
[docs]class OptionalStringTest(RequiredStringTest): """ Test for string configuration values which are optional. """ #: The default value that should be returned when no valid is given. default_value: str = '' different_key_value: Dict[str, Any] = {"sphinx_html_theme": "alabaster"} r""" A dictionary containing one or more keys that are not the keys used by the :class:`~configconfig.configvar.ConfigVar` """
[docs] def test_empty_get(self): # noqa: D102 assert self.config_var.get() == self.default_value assert self.config_var.get({}) == self.default_value
[docs] def test_success(self): # noqa: D102 assert self.config_var.get({self.config_var.__name__: ''}) == '' assert self.config_var.get(self.different_key_value) == self.default_value super().test_success()
@property def wrong_values(self) -> List[Dict[str, Any]]: # noqa: D102 return [ {self.config_var.__name__: 1234}, {self.config_var.__name__: True}, {self.config_var.__name__: test_list_int}, {self.config_var.__name__: test_list_str}, ]
[docs] def test_errors(self): # noqa: D102 for wrong_value in self.wrong_values: with pytest.raises(ValueError): # noqa: PT011 self.config_var.get(wrong_value)
[docs]class EnumTest(RequiredStringTest): """ Test for :class:`~enum.Enum` configuration values. """ #: A list of values which are of the correct type but are invalid. non_enum_values: List[Any] #: The default value that should be returned when no valid is given. default_value: str
[docs] def test_empty_get(self): # noqa: D102 assert self.config_var.get() == self.default_value assert self.config_var.get({}) == self.default_value
[docs] def test_non_enum(self): # noqa: D102 for non_enum in self.non_enum_values: with pytest.raises(ValueError): # noqa: PT011 self.config_var.get({self.config_var.__name__: non_enum})
[docs] def test_errors(self): # noqa: D102 wrong_values: List[Dict[str, Any]] = [ {self.config_var.__name__: 1234}, {self.config_var.__name__: True}, {self.config_var.__name__: test_list_int}, {self.config_var.__name__: test_list_str}, ] for wrong_value in wrong_values: with pytest.raises(ValueError): # noqa: PT011 self.config_var.get(wrong_value)
[docs]class DictTest(NotStrTest, NotBoolTest, NotIntTest, ConfigVarTest): """ Test for dictionary configuration values. """ #: A value that is valid and should be returned unchanged. test_value: Dict[str, Any] #: The default value that should be returned when no valid is given. default_value: Dict[str, Any] = {} different_key_value: Dict[str, Any] = {"sphinx_html_theme": "alabaster"} r""" A dictionary containing one or more keys that are not the keys used by the :class:`~configconfig.configvar.ConfigVar` """
[docs] def test_success(self): # noqa: D102 assert self.config_var.get({self.config_var.__name__: self.test_value}) == self.test_value assert self.config_var.get({self.config_var.__name__: {}}) == {} assert self.config_var.get(self.different_key_value) == self.default_value assert self.config_var.get() == self.default_value assert self.config_var.get({}) == self.default_value
[docs] def test_error_list_int(self): # noqa: D102 with pytest.raises(ValueError): # noqa: PT011 self.config_var.get({self.config_var.__name__: test_list_int})