1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
|
from typing import Any, Dict, List, Literal, Optional, Tuple, Type, Union
import pytest
from pytest import raises
from knot_resolver.utils.modeling import ConfigSchema, parse_json, parse_yaml
from knot_resolver.utils.modeling.exceptions import DataDescriptionError, DataValidationError
class _TestBool(ConfigSchema):
v: bool
class _TestInt(ConfigSchema):
v: int
class _TestStr(ConfigSchema):
v: str
@pytest.mark.parametrize("val,exp", [("false", False), ("true", True), ("False", False), ("True", True)])
def test_parsing_bool_valid(val: str, exp: bool):
assert _TestBool(parse_yaml(f"v: {val}")).v == exp
@pytest.mark.parametrize("val", ["0", "1", "5", "'true'", "'false'", "5.5"]) # int, str, float
def test_parsing_bool_invalid(val: str):
with raises(DataValidationError):
_TestBool(parse_yaml(f"v: {val}"))
@pytest.mark.parametrize("val,exp", [("0", 0), ("5335", 5335), ("-5001", -5001)])
def test_parsing_int_valid(val: str, exp: int):
assert _TestInt(parse_yaml(f"v: {val}")).v == exp
@pytest.mark.parametrize("val", ["false", "'5'", "5.5"]) # bool, str, float
def test_parsing_int_invalid(val: str):
with raises(DataValidationError):
_TestInt(parse_yaml(f"v: {val}"))
# int and float are allowed inputs for string
@pytest.mark.parametrize("val,exp", [("test", "test"), (65, "65"), (5.5, "5.5")])
def test_parsing_str_valid(val: Any, exp: str):
assert _TestStr(parse_yaml(f"v: {val}")).v == exp
def test_parsing_str_invalid():
with raises(DataValidationError):
_TestStr(parse_yaml("v: false")) # bool
def test_parsing_list_empty():
class ListSchema(ConfigSchema):
empty: List[Any]
with raises(DataValidationError):
ListSchema(parse_yaml("empty: []"))
@pytest.mark.parametrize("typ,val", [(_TestInt, 5), (_TestBool, False), (_TestStr, "test")])
def test_parsing_nested(typ: Type[ConfigSchema], val: Any):
class UpperSchema(ConfigSchema):
l: typ
yaml = f"""
l:
v: {val}
"""
o = UpperSchema(parse_yaml(yaml))
assert o.l.v == val
def test_parsing_simple_compound_types():
class TestSchema(ConfigSchema):
l: List[int]
d: Dict[str, str]
t: Tuple[str, int]
o: Optional[int]
yaml = """
l:
- 1
- 2
- 3
- 4
- 5
d:
something: else
w: all
t:
- test
- 5
"""
o = TestSchema(parse_yaml(yaml))
assert o.l == [1, 2, 3, 4, 5]
assert o.d == {"something": "else", "w": "all"}
assert o.t == ("test", 5)
assert o.o is None
def test_parsing_nested_compound_types():
class TestSchema(ConfigSchema):
i: int
o: Optional[Dict[str, str]]
yaml1 = "i: 5"
yaml2 = f"""
{yaml1}
o:
key1: str1
key2: str2
"""
o = TestSchema(parse_yaml(yaml1))
assert o.i == 5
assert o.o is None
o = TestSchema(parse_yaml(yaml2))
assert o.i == 5
assert o.o == {"key1": "str1", "key2": "str2"}
def test_dash_conversion():
class TestSchema(ConfigSchema):
awesome_field: Dict[str, str]
yaml = """
awesome-field:
awesome-key: awesome-value
"""
o = TestSchema(parse_yaml(yaml))
assert o.awesome_field["awesome-key"] == "awesome-value"
def test_eq():
class B(ConfigSchema):
a: _TestInt
field: str
b1 = B({"a": {"v": 6}, "field": "val"})
b2 = B({"a": {"v": 6}, "field": "val"})
b_diff = B({"a": {"v": 7}, "field": "val"})
assert b1 == b2
assert b2 != b_diff
assert b1 != b_diff
assert b_diff == b_diff
def test_docstring_parsing_valid():
class NormalDescription(ConfigSchema):
"""
Does nothing special
Really
"""
desc = NormalDescription.json_schema()
assert desc["description"] == "Does nothing special\nReally"
class FieldsDescription(ConfigSchema):
"""
This is an awesome test class
---
field: This field does nothing interesting
value: Neither does this
"""
field: str
value: int
schema = FieldsDescription.json_schema()
assert schema["description"] == "This is an awesome test class"
assert schema["properties"]["field"]["description"] == "This field does nothing interesting"
assert schema["properties"]["value"]["description"] == "Neither does this"
class NoDescription(ConfigSchema):
nothing: str
_ = NoDescription.json_schema()
def test_docstring_parsing_invalid():
class AdditionalItem(ConfigSchema):
"""
This class is wrong
---
field: nope
nothing: really nothing
"""
nothing: str
with raises(DataDescriptionError):
_ = AdditionalItem.json_schema()
class WrongDescription(ConfigSchema):
"""
This class is wrong
---
other: description
"""
nothing: str
with raises(DataDescriptionError):
_ = WrongDescription.json_schema()
|