def test_dict_constructor(): regular_dict = {'a': 1, 'b': 2} d = sanest.dict(regular_dict) assert d == regular_dict d = sanest.dict(regular_dict, c=3) regular_dict['c'] = 3 assert d == regular_dict
def test_dict_get_with_path(): d = sanest.dict() d['a'] = sanest.dict() d['a']['b'] = 123 assert d.get(('a', 'b')) == 123 assert d.get(['a', 'c']) is None assert d.get(['b', 'c'], 456) == 456
def test_dict_validate(): d = sanest.dict({'a': 1, 'b': 2}) d.check_types(type=int) d = sanest.dict({'a': [1, 2]}) d.check_types(type=[int]) with pytest.raises(sanest.InvalidValueError) as excinfo: d.check_types(type=str) assert str(excinfo.value) == "expected str, got list at path ['a']: [1, 2]"
def test_dict_items_view_iteration(): d = sanest.dict({'a': 1}) assert list(d.items()) == [('a', 1)] d = sanest.dict({'a': {'b': 2}}) items_view = d.items(type={str: int}) assert list(items_view) == [('a', {'b': 2})] with pytest.raises(sanest.InvalidValueError) as excinfo: d.values(type=bool) assert str( excinfo.value) == ("expected bool, got dict at path ['a']: {'b': 2}")
def test_dict_validate_assigned_values(): d = sanest.dict() with pytest.raises(sanest.InvalidValueError) as excinfo: d['a'] = MyClass() assert str(excinfo.value) == "invalid value of type MyClass: <MyClass>" d = sanest.dict() with pytest.raises(sanest.InvalidValueError) as excinfo: d['a', 'b'] = MyClass() assert str(excinfo.value) == "invalid value of type MyClass: <MyClass>"
def test_dict_comparison(): d1 = sanest.dict({'a': 1}) d2 = sanest.dict({'a': 1}) d3 = {'a': 1} d4 = sanest.dict({'b': 2}) assert d1 == d2 assert d1 == d3 assert d1 == d1 assert d4 != d1 assert d4 != d3 assert d1 != object()
def test_dict_getitem_with_path_and_type(): d = sanest.dict() d['a'] = sanest.dict() d['a']['b'] = 123 assert d['a', 'b':int] == 123 path = ['a', 'b'] assert d[path:int] == 123 assert d['a':dict] path = ['a'] assert d[path:dict] with pytest.raises(KeyError) as excinfo: d['x', 'y'] assert str(excinfo.value) == "['x']"
def test_dict_values_view_iteration(): d = sanest.dict({'a': 'b'}) assert list(d.values()) == ['b'] d = sanest.dict({'a': [1, 2]}) values_view = d.values(type=[int]) values = list(values_view) assert len(values) == 1 value = values[0] assert value == [1, 2] assert isinstance(value, sanest.list) with pytest.raises(sanest.InvalidValueError) as excinfo: d.values(type=bool) assert str( excinfo.value) == ("expected bool, got list at path ['a']: [1, 2]")
def test_dict_items_view_contains(): d = sanest.dict({'a': {'b': 2}}) items_view = d.items() key = 'a' value = {'b': 2} assert (key, value) in items_view key = 'a' value = sanest.dict({'b': 2}) assert (key, value) in items_view key = ['a', 'b'] value = 2 assert (key, value) in items_view key = ['a', 'x'] value = 123 assert not (key, value) in items_view
def test_dict_setdefault(): d = sanest.dict() d['a'] = 1 assert d.setdefault('a', 2) == 1 assert d.setdefault(['b', 'c'], 'foo', type=str) == 'foo' assert d['a'] == 1 assert d['b', 'c'] == 'foo' d.setdefault('d') assert d['d'] is None d.setdefault('e', None) assert d['e'] is None with pytest.raises(sanest.InvalidValueError) as excinfo: d.setdefault(['b', 'c'], 'not an int', type=int) assert str( excinfo.value) == ("expected int, got str at path ['b', 'c']: 'foo'") with pytest.raises(sanest.InvalidValueError) as excinfo: d.setdefault('x', 'not an int', type=int) assert str(excinfo.value) == ("expected int, got str: 'not an int'") assert 'x' not in d with pytest.raises(sanest.InvalidValueError) as excinfo: d.setdefault('a', 'not an int', type=int) assert str(excinfo.value) == ("expected int, got str: 'not an int'") d2 = d.setdefault('xy', {'x': 'y'}) assert isinstance(d2, sanest.dict) assert d2 == {'x': 'y'}
def test_dict_pop_with_path(): d = sanest.dict({ 'a': { 'b': 2, 'c': 3, }, 'd': { 'e': { 'f': { 'g': 'hello', }, }, } }) assert d.pop(['a', 'b']) == 2 assert ['a', 'b'] not in d assert d.pop(['a', 'c'], 33) == 3 assert ['a', 'c'] not in d assert d['a'] == {} assert d.pop(['a', 'x'], 99, type=str) == 99 with pytest.raises(KeyError) as excinfo: d.pop(['a', 'x']) assert str(excinfo.value) == "['a', 'x']" assert excinfo.value.__cause__ is None assert excinfo.value.__suppress_context__ with pytest.raises(KeyError) as excinfo: d.pop(['d', 'e', 'x', 'y', 'z']) assert str(excinfo.value) == "['d', 'e', 'x']" assert d.pop(['d', 'e', 'x', 'y', 'z'], 'hi') == 'hi' d.pop(['d', 'e', 'f']) == {'g': 'hello'}
def test_slots(): d = sanest.dict() with pytest.raises(AttributeError): d.foo = 123 ll = sanest.list() with pytest.raises(AttributeError): ll.foo = 123
def test_dict_deep_copy(): d1 = sanest.dict({'a': 1, 'b': {'b1': 21, 'b2': 22}}) d2 = sanest.dict({'a': 1, 'b': {'b1': 21, 'b2': 22}}) copies = [ (d1, d1.copy(deep=True)), (d2, copy.deepcopy(d2)), ] for original, other in copies: assert other == original assert other is not original # change shallow field: original is unchanged other['a'] = 111 assert original['a'] == 1 # change nested field: copy is unchanged change original['b', 'b2'] = 2222 assert other['b', 'b2'] == 22
def test_list_index(): ll = sanest.list([ 'a', # 0 { 'b': 'c' }, # 1 None, # 2 None, # 3 'a', # 4 None, # 5 None, # 6 ]) assert ll.index('a') == 0 assert ll.index('a', type=str) == 0 assert ll.index('a', 2) == 4 assert ll.index('a', 2, type=str) == 4 assert ll.index('a', 2, 6) == 4 assert ll.index(None, 2) == 2 assert ll.index(None, 4) == 5 assert ll.index({'b': 'c'}) == 1 assert ll.index(sanest.dict({'b': 'c'})) == 1 with pytest.raises(ValueError) as excinfo: ll.index('a', 5) assert str(excinfo.value) == "'a' is not in list" with pytest.raises(ValueError) as excinfo: ll.index('a', 2, 3) assert str(excinfo.value) == "'a' is not in list" with pytest.raises(sanest.InvalidValueError) as excinfo: ll.index(2, type=str) assert str(excinfo.value) == "expected str, got int: 2"
def test_dict_setitem_with_path(): d = sanest.dict() d['a', 'b'] = 123 assert d['a', 'b'] == 123 path = ['a', 'b'] d[path] = 456 assert d[path] == 456
def test_dict_pop_with_type(): d = sanest.dict({'a': 1, 'b': 2}) # existing key, correct type assert d.pop('a', type=int) == 1 # existing key, wrong type with pytest.raises(sanest.InvalidValueError) as excinfo: d.pop('b', type=str) assert str(excinfo.value) == "expected str, got int at path ['b']: 2" assert d['b'] == 2 # existing key, with default arg, wrong type with pytest.raises(sanest.InvalidValueError) as excinfo: assert d.pop('b', 22, type=str) assert str(excinfo.value) == "expected str, got int at path ['b']: 2" assert d['b'] == 2 # existing key, with default arg, correct type assert d.pop('b', 22, type=int) == 2 # missing key with pytest.raises(KeyError) as excinfo: d.pop('x', type=str) assert str(excinfo.value) == "['x']" assert excinfo.value.__cause__ is None assert excinfo.value.__suppress_context__ # missing key, with default arg: not type checked, just like .get() assert d.pop('x', 99, type=int) == 99 assert d.pop('x', 'not an int', type=int) == 'not an int' assert not d
def test_dict_delitem_with_path(): d = sanest.dict({'a': {'b': 2}}) with pytest.raises(KeyError) as excinfo: del d['a', 'x'] assert str(excinfo.value) == "['a', 'x']" del d['a', 'b'] assert d['a'] == {}
def test_dict_clear(): d = sanest.dict() d['a'] = 1 assert len(d) == 1 d.clear() assert 'a' not in d assert len(d) == 0 assert not d
def test_dict_basics(): d = sanest.dict() d['a'] = 1 assert d['a'] == 1 d['a'] = 2 d['b'] = 3 assert d['a'] == 2 assert d['b'] == 3
def test_dict_contains_with_path_and_type(): d = sanest.dict() d['a', 'b'] = 123 assert ['a', 'b', int] in d assert ('a', 'b', int) in d assert ('a', 'b', str) not in d assert ('a', 'b', 'c') not in d assert ('a', 'b', 'c', int) not in d
def test_dict_contains_with_path(): d = sanest.dict() d['a', 'b'] = 123 assert ('a', 'b') in d # tuple assert ['a', 'b'] in d # list assert ['c', 'd'] not in d with pytest.raises(sanest.InvalidPathError): ['a', None] in d
def test_dict_contains_with_type(): d = sanest.dict() d['a'] = 123 d['b'] = [1, 2, 3] assert ['a', int] in d assert ['a', str] not in d assert ['b', [int]] in d assert not ['b', [str]] in d
def test_dict_delitem_with_type(): d = sanest.dict({'a': 1, 'b': 2}) del d['a':int] assert 'a' not in d with pytest.raises(sanest.InvalidValueError) as excinfo: del d['b':str] assert str(excinfo.value) == "expected str, got int at path ['b']: 2" assert d['b'] == 2
def test_dict_pop_with_path_and_type(): d = sanest.dict({'a': {'b': 2}}) with pytest.raises(sanest.InvalidValueError) as excinfo: assert d.pop(['a', 'b'], type=str) assert str(excinfo.value) == "expected str, got int at path ['a', 'b']: 2" assert d.pop(['a', 'b'], 22, type=int) == 2 assert d == {'a': {}} assert d.pop(['a', 'x'], 99, type=str) == 99
def test_list_count(): ll = sanest.list([1, 2, 3, 1, 1, 2, 3, {'a': 'b'}]) assert ll.count(1) == 3 assert ll.count(1, type=int) == 3 with pytest.raises(sanest.InvalidValueError) as excinfo: ll.count(1, type=str) assert str(excinfo.value) == "expected str, got int: 1" assert ll.count({'a': 'b'}) == 1 assert ll.count(sanest.dict({'a': 'b'})) == 1
def test_dict_list_contains(): d = sanest.dict({ 'a': ['b', 'c'], }) assert ['a'] in d assert ['a', 0] in d assert ['a', 0, 'x'] not in d assert ['a', 'x'] not in d assert ['a', 3] not in d
def test_dict_value_atomic_type(): d1 = sanest.dict() d2 = {} for d in [d1, d2]: d['a'] = 1 d['b'] = 1.23 d['c'] = "foo" d['d'] = True assert d1 == d2
def test_dict_delitem_with_path_and_type(): original = {'a': {'b': 2}} d = sanest.dict(original) with pytest.raises(sanest.InvalidValueError) as excinfo: del d['a', 'b':str] assert str(excinfo.value) == "expected str, got int at path ['a', 'b']: 2" assert d == original del d['a', 'b':int] assert d['a'] == {}
def test_wrong_path_for_container_type(): d = sanest.dict() ll = sanest.list() with pytest.raises(sanest.InvalidPathError) as excinfo: d[2, 'a'] assert str(excinfo.value) == "dict path must start with str: [2, 'a']" with pytest.raises(sanest.InvalidPathError) as excinfo: ll['a', 2] assert str(excinfo.value) == "list path must start with int: ['a', 2]"
def test_dict_getitem(): d = sanest.dict() d['a'] = 1 assert d['a'] == 1 with pytest.raises(KeyError) as excinfo: d['x'] assert str(excinfo.value) == "['x']"