def test_replace_attributes_only_overridden_if_None(self): for attrname in self.attributes[3:]: good = { attrname: '' } # a False value != None to make readonly work bad = {attrname: 'unwanted'} assert '' == getattr(Property().replace(**good), attrname) assert '' == getattr(Property(**good).replace(**bad), attrname)
def test_from_and_to_properties(self): properties = [Property('a'), Property('a.b', 5, int, '\d+', True, True, 'doc'), Property('b', 5, int, '\d+', True, True, 'doc')] conf = Configuration.from_properties(properties) assert properties == list(conf.to_properties()) assert 'a' in conf assert 'a.b' in conf assert 'b' in conf
def test_type_inferrence(self): for T in (bool, int, float, str, type(''),): assert T.__name__ == Property(value=T()).type, T class UnknownType: pass assert None == Property(value=UnknownType()).type assert 'float' == Property('', 4, float).type
def test_builder(self): properties = [Property('a', 5), Property('a.b', 6, int, '6.*', True, True, 'doc')] cb = cfg.ConfigBuilder() with cb['a'] as a: a.value = 5 with a['b'] as ab: ab.value = 6 ab.valid = '6.*' ab.readonly = True ab.hidden = True ab.doc = 'doc' assert properties == list(cb.to_configuration().to_properties())
def assert_value_conversion(kind, testvalue, expected): p = Property('test', testvalue, type=kind) actual = p.value self.assertEqual( expected, actual, ('Bad %s conversion for value: %r! expect: %r, actual: %r' % (kind, p.value, expected, actual)))
def test_tupleness_attributes_and_defaults(self): """A property is a tuple with named values.""" default = OrderedDict.fromkeys(self.attributes, None) default['key'] = '' p = Property() assert tuple(default.values()) == p, p for attrname, value in default.items(): assert getattr(p, attrname) == value
def test_immutable(self): p = Property() assert p is not p.replace(**p.to_dict()) for attrname in self.attributes: try: setattr(p, attrname, None) except AttributeError: pass else: assert False, 'must not be able to change %r ' % (attrname, )
def test_cannot_replace_if_readonly(self): Property(readonly=True).replace()
def test_key_is_normalized(self): assert 'x.y' == Property('X.Y').key
def test_replace_changes_existing(self): conf = Configuration.from_properties([Property('b', 'old')]) newvalues = {'b': 'replaced'} assert newvalues == conf.replace(newvalues)
def test_update(self): conf = Configuration.from_properties([Property('b', 'old')]) newvalues = {'b': 'replaced', 'c': 'new'} assert newvalues == conf.update(newvalues)
def test_attribute_access(self): p = Property('b', 5, int, '\d+', True, True, 'doc') conf = Configuration.from_properties([p]) assert 5 == conf['b'] assert p == conf.property('b')
def test_autocast(self): assert 13 == Property('', '13', int).value
def test_replace_value(self): p = Property(value='original') assert 'new' == p.replace(value='new').value assert 'original' == p.replace(value=None).value
def test_replace_type(self): assert 'int' == Property().replace(type=int).type assert 'int' == Property(type=int).replace(type=str).type
def test_bad_value_for_type(self): Property('', 'a', int)
def test_replace_key(self): assert 'different.key' == Property().replace(key='different.key').key Property('some.key').replace(key='different.key')
def test_replace_without_values(self): p = Property('a', 5, int, '\d+', False, False, 'doc') assert p == p.replace() assert p == p.replace(**dict.fromkeys(self.attributes))
def test_to_dict(self): p = Property('bla', 12, int, '\d+', True, True, '') assert p == Property(**p.to_dict())
def test_None_value_is_not_cast_or_validated(self): assert None == Property(type=bool, valid=lambda v: v is not None).value
def test_validation_by_callable(self): Property('', False, valid=lambda v: v)
def test_validation_by_regex(self): assert 0 == Property('', 0, valid='[0-9]').value Property('', ['x'], valid='[0-9]')