def test_validation(self): p = Property('test') p.value = object() # uninitialized validation must allow all, including weird, values '''can't re-set validity string''' with self.assertRaises(AttributeError): p.validity = 'something' '''validation takes place in constructor''' with self.assertRaises(ValueError): Property('test', validity='brai+ns!') ### REGULAR EXPRESSIONS self.assertEqual('braiiins!', Property('test', 'braiiins!', validity='brai+ns!').value, 'validation is through regex') '''validation is by match, not by find''' with self.assertRaises(ValueError): Property('test', 'halfbrains!', validity='brai+ns!') '''validation is by full match''' with self.assertRaises(ValueError): Property('test', 'brains! supple brains!', validity='brai+ns!') ### NON-STRING VALUES self.assertEqual(99, Property('test', 99, validity='\d+').value, 'validation str(ingifies) value temporarily') ### WHITESPACE self.assertEqual('brains!', Property('test', '\f\n\r\t\vbrains! ', validity='brai+ns!').value, 'validation trims whitespace from value') self.assertEqual('brains!', Property('test', 'brains!', validity=' brai+ns!\f\n\r\t\v').value, 'validation trims whitespace from validity expression') '''validation respects explicit whitespace in regex''' with self.assertRaises(ValueError): Property('test', '\f\n\r\t\v XY ', validity=r'\f\n\r\t\v XY\s') # invalid because value gets trimmed self.assertEqual('brains!', Property('test', 'brains!', validity=' ^ brai+ns! $ ').value, 'leading ^ and trailing $ is ignored, even if embedded in whitespace') ### LISTS '''empty list must be ok''' p = Property('', type='list', validity='\d+') '''value must be validated as list''' p.value = ' 1, 123 ' with self.assertRaises(ValueError): p.value = '1, 123, None'
def test_readonly_locks_value_and_description(self): p = Property('p') p.readonly = True with self.assertRaises(ConfigError): p.value = True with self.assertRaises(ConfigError): p.desc = "Lala"
def test_typechecks_and_type_effects(self): self.assertEqual(-23.42, Property('test', "-23.42", type=float).value, 'builtin types can be used as type argument') ### CONSTRUCTOR self.assertEqual(11, Property('test', 11).value, 'without type, the value remains untransformed') self.assertEqual(11, Property('test', 11.5, type='int').value, 'with type, the value is transformed') self.assertEqual('', Property('test', None, type='str').value, 'with type, the value is transformed') self.assertRaises(configuration.TransformError, configuration.Transformers['int'], None) self.assertEqual(0, Property('test', None, type='int').value, 'with type, trying to set None sets Transformer default') self.assertFalse(Property('test', type='FRXMBL').type, 'unknown type will default to no type') ### ASSIGNMENT ## with type ## p = Property('test', type='int') '''can assign convertible values''' p.value = '0x10' self.assertEqual(16, p.value) '''can't assign inconvertible objects''' self.assertRaises(configuration.TransformError, configuration.Transformers['int'], object()) with self.assertRaises(TypeError): p.value = object() '''assigning None works though and goes to default''' p.value = None self.assertEqual(0, p.value) ## without type ## '''without value set, any crap can be assigned''' no_type = Property('no_type') crap = object() no_type.value = crap self.assertEqual(crap, no_type.value) '''with transformable-type value set, new value will be transformed or not accepted''' no_type = Property('no_type', 0) no_type.value = 3.14 self.assertEqual(3, no_type.value) with self.assertRaises(TypeError): no_type.value = 'not an int' '''with non-transformable-type value set, can assign value of same type''' no_type = Property('no_type', object()) no_type.value = 3.14 self.assertEqual(3.14, no_type.value) '''with non-transformable-type value set, can't assign different type''' no_type = Property('no_type', type(object)) with self.assertRaises(TypeError): no_type.value = 3.14