# pylint: disable=redefined-outer-name from copy import deepcopy import pytest import preserve import configspec @pytest.fixture def example_spec(): confspec = configspec.ConfigSpecification() confspec.add_spec("bool_a", configspec.BoolSpec(False, False, "Bool A")) confspec.add_spec("boollist_a", configspec.BoolListSpec(False, False, "Bool A")) confspec.add_spec("int_a", configspec.IntSpec(0, -4, 4, False, "Int A")) confspec.add_spec("intlist_a", configspec.IntListSpec(0, -4, 4, False, "Int A")) confspec.add_spec("string_a", configspec.StringSpec("ThisIsAString", 4, 15, False, "String A")) confspec.add_spec("stringlist_a", configspec.StringListSpec("ThisIsAString", 4, 15, False, "String A")) confdictspec = confspec.add_spec("dict_a", configspec.DictSpec(None, False, "Dict A")) confdictspec.add_spec("bool_b", configspec.BoolSpec(False, False, "Bool B")) confdictspec.add_spec("int_b", configspec.IntSpec(0, -4, 4, False, "Int B")) confdictspec.add_spec("string_b", configspec.StringSpec("ThisIsAString", 4, 15, False, "String B")) confdictlist = confspec.add_spec("dictlist_a", configspec.DictListSpec(None, False, "List of Dicts B")) confdictlist.add_spec("bool_c", configspec.BoolSpec(False, False, "Bool C")) confdictlist.add_spec("int_c", configspec.IntSpec(0, -4, 4, False, "Int C")) confdictlist.add_spec("string_c", configspec.StringSpec("ThisIsAString", 4, 15, False, "String C")) return confspec @pytest.fixture def example_values(): vals = {'bool_a': True, 'boollist_a': [False, True], 'int_a': 1, 'intlist_a': [1, 2, 3, 4], 'string_a': 'sometext', 'stringlist_a': ['somemoretext', 'yetmoretext'], 'dict_a': { 'bool_b': False, 'int_b': 0, 'string_b': 'texttesttext'}, 'dictlist_a': [{'bool_c': False, 'int_c': 0, 'string_c': 'string1'}, {'bool_c': False, 'int_c': 0, 'string_c': 'string2'}]} return vals def test_addspec(example_spec): confspec = configspec.ConfigSpecification() confspec.add_specs([ ("bool_a", configspec.BoolSpec(False, False, "Bool A")), ("boollist_a", configspec.BoolListSpec(False, False, "Bool A")), ("int_a", configspec.IntSpec(0, -4, 4, False, "Int A")), ("intlist_a", configspec.IntListSpec(0, -4, 4, False, "Int A")), ("string_a", configspec.StringSpec("ThisIsAString", 4, 15, False, "String A")), ("stringlist_a", configspec.StringListSpec("ThisIsAString", 4, 15, False, "String A")) ]) confdictspec = confspec.add_spec("dict_a", configspec.DictSpec(None, False, "Dict A")) confdictspec.add_specs([ ("bool_b", configspec.BoolSpec(False, False, "Bool B")), ("int_b", configspec.IntSpec(0, -4, 4, False, "Int B")), ("string_b", configspec.StringSpec("ThisIsAString", 4, 15, False, "String B")) ]) confdictlist = confspec.add_spec("dictlist_a", configspec.DictListSpec(None, False, "List of Dicts B")) confdictlist.add_specs([ ("bool_c", configspec.BoolSpec(False, False, "Bool C")), ("int_c", configspec.IntSpec(0, -4, 4, False, "Int C")), ("string_c", configspec.StringSpec("ThisIsAString", 4, 15, False, "String C")) ]) # Preserve to be able to directly compare resulting confspec structure assert preserve.preserve(example_spec) == preserve.preserve(confspec) def test_config_validate(example_spec, example_values): spec = example_spec spec.validate(example_values) def test_invalid_bool(): spec = configspec.BoolSpec() with pytest.raises(configspec.InvalidConfigError, match="value must be a boolean"): spec.validate("false") with pytest.raises(configspec.InvalidConfigError, match="value must be a boolean"): spec.validate(None) def test_invalid_int(): spec = configspec.IntSpec(minval=-4, maxval=4) with pytest.raises(configspec.InvalidConfigError, match="value must be >="): spec.validate(-5) with pytest.raises(configspec.InvalidConfigError, match="value must be <="): spec.validate(5) with pytest.raises(configspec.InvalidConfigError, match="value must be an integer"): spec.validate("5") with pytest.raises(configspec.InvalidConfigError, match="value must be an integer"): spec.validate(None) def test_invalid_string(): spec = configspec.StringSpec(minlength=4, maxlength=15) with pytest.raises(configspec.InvalidConfigError, match="string length must be >="): spec.validate("123") with pytest.raises(configspec.InvalidConfigError, match="string length must be <="): spec.validate("1234567890abcdef") with pytest.raises(configspec.InvalidConfigError, match="value must be a string"): spec.validate(1) with pytest.raises(configspec.InvalidConfigError, match="value must be a string"): spec.validate(None) def test_man(example_spec, example_values): confman = configspec.ConfigManager() confman.add_confspec("test_bundle", example_spec) confman.load({"test_bundle": example_values}) assert confman.get_config_bundle("test_bundle") == example_values confman.freeze_value("test_bundle", "int_a") newvals = deepcopy(example_values) newvals["int_a"] = 4 confman.load({"test_bundle": newvals}) assert confman.get_config_bundle("test_bundle") == example_values confman.load_overlay({"test_bundle": {"string_a": "new text"}}) assert confman.get_config_bundle("test_bundle")["string_a"] == "new text"