Commits

Jean-Tiare Le Bigot committed 3c7ac10

I was told tests MUST be under main module

Comments (0)

Files changed (19)

onctuous/tests/__init__.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>

onctuous/tests/functional/__init__.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>

onctuous/tests/functional/test_global.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
+
+
+import unittest, mock
+
+class TestGlobal(unittest.TestCase):
+    def test_nested_data(self):
+        from onctuous import InvalidList, Schema, All, Coerce, Any
+
+        data1 = {
+            'exclude': ['Users', 'Uptime'],
+            'include': [],
+            'set': {
+                'snmp_community': 'public',
+                'snmp_timeout': 15,
+                'snmp_version': '2c',
+            },
+            'targets': {
+                'localhost': {
+                    'exclude': ['Uptime'],
+                    'features': {
+                        'Uptime': {
+                            'retries': 3,
+                        },
+                        'Users': {
+                            'snmp_community': 'monkey',
+                            'snmp_port': 15,
+                        },
+                    },
+                    'include': ['Users'],
+                    'set': {
+                        'snmp_community': 'monkeys',
+                    },
+                },
+            },
+        }
+
+        data2 = {
+            'set': {
+                'snmp_community': 'public',
+                'snmp_version': '2c',
+            },
+            'targets': {
+                'exclude': ['Ping'],
+                'features': {
+                    'Uptime': {'retries': 3},
+                    'Users': {'snmp_community': 'monkey'},
+                },
+            },
+        }
+
+        settings = {
+          'snmp_community': str,
+          'retries': int,
+          'snmp_version': All(Coerce(str), Any('3', '2c', '1')),
+        }
+        features = ['Ping', 'Uptime', 'Http']
+        validate = Schema({
+           'exclude': features,
+           'include': features,
+           'set': settings,
+           'targets': {
+             'exclude': features,
+             'include': features,
+             'features': {
+               str: settings,
+             },
+           },
+        })
+
+        expected = {
+            'set': {
+                'snmp_version': '2c',
+                'snmp_community': 'public',
+            },
+            'targets': {
+                'exclude': ['Ping'],
+                'features': {
+                    'Uptime': {'retries': 3},
+                    'Users': {'snmp_community': 'monkey'},
+                }
+            }
+        }
+
+        self.assertEqual(expected, validate(data2))
+        self.assertRaisesRegexp(InvalidList, "@", validate, data1)

onctuous/tests/functional/test_schema.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
+
+
+import unittest
+
+MSG = "custom msg"
+
+class TestSchema(unittest.TestCase):
+    def test_dict(self):
+        from onctuous import Schema, InvalidList, Coerce, Required
+
+        validate = Schema({'one': 'two', 'three': 'four'})
+
+        # invalid dictionary value
+        self.assertRaisesRegexp(InvalidList, 'not a valid value', validate, {'one': 'three'})
+        # invalid key
+        self.assertRaisesRegexp(InvalidList, 'extra key', validate, {'two': 'three'})
+
+        # validate int type
+        validate = Schema({'one': 'two', 'three': 'four', int: str})
+        self.assertEqual({10: 'twenty'}, validate({10: 'twenty'}))
+        self.assertRaisesRegexp(InvalidList, 'extra key', validate, {'10': 'twenty'})
+
+        # validate with type coercion
+        validate = Schema({'one': 'two', 'three': 'four', Coerce(int): str})
+        self.assertEqual({10: 'twenty'}, validate({'10': 'twenty'}))
+
+        # test required key with defaults
+        validate = Schema({Required(1,default='toto'):str})
+        self.assertEqual({1: 'toto'}, validate({}))
+
+    def test_list(self):
+        from onctuous import Schema, InvalidList
+
+        self.assertEqual([1,2,3], Schema([1,2,3,4,5,6])([1,2,3]))
+        self.assertEqual([1,2,3], Schema([int])([1,2,3]))
+
+        # extra entry
+        self.assertRaisesRegexp(InvalidList, "value", Schema([1,2,3,4,5,6]), [0,1,2,3])
+
+
+    def test_msg(self):
+        from onctuous import Schema, InvalidList, Msg
+
+        # custom message for direct descendants errors
+        validate = Schema(Msg(['one', 'two', int], MSG))
+        self.assertRaisesRegexp(InvalidList, MSG, validate, ['three'])
+
+        # regular message for indirect descendants
+        validate = Schema(Msg([['one', 'two', int]], MSG))
+        self.assertRaisesRegexp(InvalidList, "invalid", validate, [['three']])
+
+    def test_any_all(self):
+        from onctuous import Schema, Any, All, InvalidList, Coerce
+
+        validate = Schema(Any('true', 'false', All(Any(int, bool), Coerce(bool))))
+        self.assertTrue(validate('true'))
+        self.assertTrue(validate(1))
+        self.assertRaisesRegexp(InvalidList, "valid", validate, "toto")
+
+        validate = Schema(Any({int: {int:str}}, bool))
+        self.assertRaises(InvalidList, validate, {1:{"2":"titi"}})
+

onctuous/tests/unit/__init__.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>

onctuous/tests/unit/test_invalid.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
+
+
+import unittest, mock
+
+MSG = "custom msg"
+MSG1 = "msg 1"
+MSG2 = "msg 2"
+PATH = ["path", "to", "error"]
+FULL_MSG = "custom msg @ data['path']['to']['error']"
+ERRORS = [KeyError(MSG1), ValueError(MSG2)]
+
+
+class TestInvalid(unittest.TestCase):
+    def test_invalid_init(self):
+        from onctuous import Invalid
+
+        inv = Invalid(MSG, PATH)
+
+        self.assertEqual((MSG,), inv.args)
+        self.assertEqual(MSG, inv.message)
+        self.assertEqual(PATH, inv.path)
+
+    def test_invalid_msg(self):
+        from onctuous import Invalid
+
+        inv = Invalid(MSG, PATH)
+        self.assertEqual(MSG, inv.msg)
+
+    def test_str(self):
+        from onctuous import Invalid
+
+        self.assertEqual(MSG, str(Invalid(MSG)))
+        self.assertEqual(FULL_MSG, str(Invalid(MSG, PATH)))
+
+
+class TestInvalidList(unittest.TestCase):
+    def test_invalid_list_init(self):
+        from onctuous import InvalidList
+
+        self.assertEqual(ERRORS, InvalidList(ERRORS).errors)
+        self.assertRaises(ValueError, InvalidList, [])
+
+    def test_invalid_list_msg(self):
+        from onctuous import InvalidList, Invalid
+
+        self.assertEqual(MSG1, InvalidList([Invalid(MSG1)]).msg)
+
+    def test_invalid_list_path(self):
+        from onctuous import InvalidList, Invalid
+
+        self.assertEqual([], InvalidList([Invalid(MSG1)]).path)
+        self.assertEqual(PATH, InvalidList([Invalid(MSG1, PATH)]).path)
+
+    def test_invalid_list_add(self):
+        from onctuous import InvalidList, Invalid
+
+        inv1 = Invalid(MSG1)
+        inv2 = Invalid(MSG2)
+
+        invlist = InvalidList([inv1])
+        invlist.add(inv2)
+
+        self.assertEqual([inv1, inv2], invlist.errors)
+

onctuous/tests/unit/test_markers.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
+
+
+import unittest, mock
+
+MSG = "custom msg"
+
+class TestMarkers(unittest.TestCase):
+    def test_undefined(self):
+        from onctuous import Undefined, UNDEFINED
+
+        undef = Undefined()
+
+        self.assertEqual(Undefined, type(UNDEFINED))
+        self.assertEqual("...", repr(undef))
+        self.assertEqual("...", str(undef))
+        self.assertFalse(bool(undef))
+
+    def test_marker_init(self):
+        from onctuous import Marker
+
+        marker = Marker(int, msg=MSG)
+
+        self.assertEqual(int, marker.schema)
+        self.assertEqual(MSG, marker.msg)
+
+    def test_marker_str_repr(self):
+        from onctuous import Marker
+
+        marker = Marker(int, msg=MSG)
+
+        self.assertEqual("<type 'int'>", str(marker))
+        self.assertEqual("<type 'int'>", repr(marker))
+
+    def test_marker_call(self):
+        from onctuous import Marker, Invalid
+
+        marker1 = Marker(int)
+        marker2 = Marker(int, msg=MSG)
+
+        marker1(123)
+        marker2(123)
+
+        self.assertRaisesRegexp(Invalid, "expected", marker1, "toto")
+        self.assertRaisesRegexp(Invalid, MSG, marker2, "toto")
+
+    def test_required_init(self):
+        from onctuous import Required
+
+        marker = Required(int, default="Yeah !", msg=MSG)
+
+        self.assertEqual(int, marker.schema)
+        self.assertEqual(MSG, marker.msg)
+        self.assertEqual("Yeah !", marker.default)
+
+
+

onctuous/tests/unit/test_schema.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
+
+
+import unittest, mock
+
+MSG1 = "msg 1"
+PATH = ["path", "to", "error"]
+
+class TestSchema(unittest.TestCase):
+    def test_schema_init(self):
+        from onctuous import Schema
+
+        schema = Schema(int, required=True, extra=True)
+        self.assertEqual(int, schema.schema)
+        self.assertEqual(True, schema.required)
+        self.assertEqual(True, schema.extra)
+
+        schema = Schema(int)
+        self.assertEqual(int, schema.schema)
+        self.assertEqual(False, schema.required)
+        self.assertEqual(False, schema.extra)
+
+    @mock.patch('onctuous.Schema.validate')
+    def test_schema_call(self, m_validate):
+        from onctuous import Schema
+
+        Schema(int)(123)
+        m_validate.assert_called_with([], int, 123)
+
+    @mock.patch('onctuous.Schema._validate_dict')
+    @mock.patch('onctuous.Schema._validate_list')
+    @mock.patch('onctuous.Schema._validate_scalar')
+    def test_schema_validate_scalar(self, m_val_scalar, m_val_list, m_val_dict):
+        from onctuous import Schema
+
+        Schema(None).validate([], int, 123)
+
+        m_val_scalar.assert_called_once_with([], int, 123)
+        self.assertFalse(m_val_dict.called)
+        self.assertFalse(m_val_list.called)
+
+    @mock.patch('onctuous.Schema._validate_dict')
+    @mock.patch('onctuous.Schema._validate_list')
+    @mock.patch('onctuous.Schema._validate_scalar')
+    def test_schema_validate_dict(self, m_val_scalar, m_val_list, m_val_dict):
+        from onctuous import Schema
+
+        Schema(None).validate([], {'a': 'b'}, {'a': 'b'})
+
+        m_val_dict.assert_called_once_with([], {'a': 'b'}, {'a': 'b'})
+        self.assertFalse(m_val_scalar.called)
+        self.assertFalse(m_val_list.called)
+
+    @mock.patch('onctuous.Schema._validate_dict')
+    @mock.patch('onctuous.Schema._validate_list')
+    @mock.patch('onctuous.Schema._validate_scalar')
+    def test_schema_validate_list(self, m_val_scalar, m_val_list, m_val_dict):
+        from onctuous import Schema
+
+        Schema(None).validate([], ['a', 'b'], ['a', 'b'])
+
+        m_val_list.assert_called_once_with([], ['a', 'b'], ['a', 'b'])
+        self.assertFalse(m_val_scalar.called)
+        self.assertFalse(m_val_dict.called)
+
+
+    @mock.patch('onctuous.Schema._validate_dict')
+    @mock.patch('onctuous.Schema._validate_list')
+    @mock.patch('onctuous.Schema._validate_scalar')
+    def test_schema_validate_scalar_error(self, m_val_scalar, m_val_list, m_val_dict):
+        from onctuous import Schema, InvalidList, Invalid
+
+        m_val_scalar.side_effect = Invalid(MSG1)
+        self.assertRaisesRegexp(InvalidList, MSG1, Schema(None).validate, [], int, 123)
+
+        m_val_scalar.side_effect = InvalidList([Invalid(MSG1)])
+        self.assertRaisesRegexp(InvalidList, MSG1, Schema(None).validate, [], int, 123)
+
+    def test_validate_scalar(self):
+        from onctuous import Schema, Invalid
+
+        # test value specification
+        self.assertEqual(123, Schema._validate_scalar([], 123, 123))
+        self.assertEqual("123", Schema._validate_scalar([], "123", "123"))
+
+        # test type specification
+        self.assertEqual(123, Schema._validate_scalar([], int, 123))
+        self.assertEqual("123", Schema._validate_scalar([], str, "123"))
+
+        # test callable specification
+        spec = mock.Mock()
+        spec.return_value = 123
+        self.assertEqual(123, Schema._validate_scalar([], spec, "123"))
+
+        # errors
+        self.assertRaises(Invalid, Schema._validate_scalar, [], "toto", "123")
+        self.assertRaises(Invalid, Schema._validate_scalar, [], int, "123")
+
+        spec.side_effect = ValueError()
+        self.assertRaises(Invalid, Schema._validate_scalar, [], spec, "123")
+        spec.side_effect = Invalid(MSG1)
+        self.assertRaisesRegexp(Invalid, MSG1, Schema._validate_scalar, [], spec, "123")
+
+    @mock.patch('onctuous.Schema.validate')
+    def test_validate_list(self, m_validate):
+        from onctuous import Schema, InvalidList, Invalid
+
+        # test with empty value
+        self.assertEqual([], Schema(None)._validate_list([], [1,2,3], []))
+
+        # test with empty condition
+        self.assertEqual([1,2,3], Schema(None)._validate_list([], [], [1,2,3]))
+
+        # regular validation path (if number seems awkward, remember: it's a mock)
+        m_validate.return_value = 42
+        self.assertEqual([42], Schema(None)._validate_list([], [1,2,3], [12]))
+        m_validate.assert_called_with([0], 1, 12)
+
+        # test with local error
+        m_validate.side_effect = Invalid(MSG1)
+        self.assertRaises(InvalidList, Schema(None)._validate_list, [], [1,2,3], [12])
+
+        # test with deep error (sub item) (weird logic btw)
+        m_validate.side_effect = Invalid(MSG1, PATH)
+        self.assertRaises(Invalid, Schema(None)._validate_list, [], [1,2,3], [12])
+
+    @mock.patch('onctuous.Schema.validate')
+    def test_validate_dict(self, m_validate):
+        from onctuous import Schema, InvalidList, Invalid, Required, Optional, Extra
+
+        # test with empty schema and extra
+        self.assertEqual({'1':'2'}, Schema(None, extra=True)._validate_dict([], {}, {'1':'2'}))
+        self.assertRaisesRegexp(InvalidList, "extra", Schema(None)._validate_dict, [], {}, {'1':'2'})
+
+        # test per schema extra
+        self.assertEqual({'1':'2'}, Schema(None)._validate_dict([], {Extra: 'whatever'}, {'1':'2'}))
+
+        # no key required
+        self.assertEqual({}, Schema(None)._validate_dict([], {'1':'2'}, {}))
+
+        # all key required
+        m_validate.return_value = 42
+        self.assertEqual({42:42}, Schema(None, required=True)._validate_dict([], {'1':'2'}, {'1':'2'}))
+        self.assertRaisesRegexp(InvalidList, "required", Schema(None, required=True)._validate_dict, [], {'1':'2'}, {})
+
+        # all key required BUT optional (sic)
+        m_validate.return_value = 42
+        self.assertEqual({}, Schema(None, required=True)._validate_dict([], {Optional('1'):'2'}, {}))
+        self.assertEqual({42:42}, Schema(None, required=True)._validate_dict([], {Optional('1'):'2'}, {'1':'2'}))
+
+        # individual key required
+        m_validate.return_value = 42
+        self.assertEqual({42:42}, Schema(None)._validate_dict([], {Required('1'):'2'}, {'1':'2'}))
+        self.assertRaisesRegexp(InvalidList, "required", Schema(None)._validate_dict, [], {Required('1'):'2'}, {})

onctuous/tests/unit/test_validators.py

+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Ludia Inc.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution.
+#
+# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
+
+
+import unittest, mock
+
+MSG = "custom msg"
+
+class TestValidators(unittest.TestCase):
+    def test_extra(self):
+        from onctuous import Extra, SchemaError
+
+        self.assertRaises(SchemaError, Extra, "_")
+
+    def test_msg(self):
+        from onctuous import Msg, Invalid
+
+        self.assertEqual(123, Msg(int, msg=MSG)(123))
+        self.assertRaisesRegexp(Invalid, MSG, Msg(int, msg=MSG), "hello")
+
+    def test_coerce(self):
+        from onctuous import Coerce, Invalid
+
+        self.assertRaisesRegexp(Invalid, "expected", Coerce(int), "hello")
+        self.assertRaisesRegexp(Invalid, MSG, Coerce(int, MSG), "hello")
+
+    def test_is_true(self):
+        from onctuous import IsTrue, Invalid
+
+        self.assertEqual("123", IsTrue()("123"))
+        self.assertEqual(["123"], IsTrue()(["123"]))
+        self.assertEqual(True, IsTrue()(True))
+
+        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), "")
+        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), [])
+        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), {})
+        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), False)
+        self.assertRaisesRegexp(Invalid, "value", IsTrue(), False)
+
+    def test_is_false(self):
+        from onctuous import IsFalse, Invalid
+
+        self.assertEqual("", IsFalse()(""))
+        self.assertEqual([], IsFalse()([]))
+        self.assertEqual(False, IsFalse()(False))
+
+        self.assertRaisesRegexp(Invalid, MSG, IsFalse(MSG), "123")
+        self.assertRaisesRegexp(Invalid, MSG, IsFalse(MSG), ["123"])
+        self.assertRaisesRegexp(Invalid, MSG, IsFalse(MSG), True)
+        self.assertRaisesRegexp(Invalid, "value", IsFalse(), True)
+
+    def test_boolean(self):
+        from onctuous import Boolean, Invalid
+
+        self.assertEqual(True, Boolean()(-42))
+        self.assertEqual(True, Boolean()(True))
+        self.assertEqual(True, Boolean()(['toto']))
+        self.assertEqual(True, Boolean()('1'))
+        self.assertEqual(True, Boolean()('trUe'))
+        self.assertEqual(True, Boolean()('yeS'))
+        self.assertEqual(True, Boolean()('oN'))
+        self.assertEqual(True, Boolean()('eNable'))
+
+        self.assertEqual(False, Boolean()(0))
+        self.assertEqual(False, Boolean()(False))
+        self.assertEqual(False, Boolean()([]))
+        self.assertEqual(False, Boolean()('0'))
+        self.assertEqual(False, Boolean()('fALse'))
+        self.assertEqual(False, Boolean()('nO'))
+        self.assertEqual(False, Boolean()('oFf'))
+        self.assertEqual(False, Boolean()('diSAble'))
+
+        self.assertRaisesRegexp(Invalid, MSG, Boolean(MSG), "toto")
+        self.assertRaisesRegexp(Invalid, "expected", Boolean(), "toto")
+
+    @mock.patch('__builtin__.bool')
+    def test_boolean_error(self, m_bool):
+        from onctuous import Boolean, Invalid
+
+        m_bool.side_effect = ValueError
+        self.assertRaisesRegexp(Invalid, "expected", Boolean(), None)
+
+    def test_match(self):
+        from onctuous import Match, Invalid
+
+        self.assertEqual("0x123bAc", Match("^0x[a-fA-F0-9]+$")("0x123bAc"))
+        self.assertEqual("0x123bAc", Match(r"^0x[a-fA-F0-9]+$")("0x123bAc"))
+
+        self.assertRaisesRegexp(Invalid, MSG, Match("^0x[a-fA-F0-9]+$", MSG), "toto")
+        self.assertRaisesRegexp(Invalid, "match", Match("^0x[a-fA-F0-9]+$"), "toto")
+
+    def test_sub(self):
+        from onctuous import Sub
+
+        self.assertEqual("Hi You!", Sub("toto", "Chuck")("Hi You!"))
+        self.assertEqual("Hi Chuck!", Sub("You", "Chuck")("Hi You!"))
+        self.assertEqual("Hi Chuck!", Sub("[Yy]ou", "Chuck")("Hi you!"))
+        self.assertEqual("Hi Chuck!", Sub(r"[Yy]ou", "Chuck")("Hi you!"))
+
+    def test_url(self):
+        from onctuous import Url, Invalid
+
+        self.assertEqual("www.example.com", Url()("www.example.com"))
+        self.assertEqual("www.example.com/my/resource", Url()("www.example.com/my/resource"))
+        self.assertEqual("www.example.com:42/", Url()("www.example.com:42/"))
+        self.assertEqual("toto://www.example.com:42/", Url()("toto://www.example.com:42/"))
+        self.assertEqual("toto://jt@www.example.com:42/", Url()("toto://jt@www.example.com:42/"))
+        self.assertEqual("toto://jt:pwd@www.example.com:42/", Url()("toto://jt:pwd@www.example.com:42/"))
+
+        self.assertRaisesRegexp(Invalid, MSG, Url(MSG), 123)
+        self.assertRaisesRegexp(Invalid, "URL", Url(), 132)
+
+    def test_is_file(self):
+        import os
+        from onctuous import IsFile, Invalid
+
+        file = os.path.abspath(__file__)
+        dir = os.path.dirname(__file__)
+
+        self.assertEqual(file, IsFile()(file))
+        self.assertRaisesRegexp(Invalid, "file", IsFile(), dir)
+        self.assertRaisesRegexp(Invalid, "file", IsFile(), "/tarata/@==")
+        self.assertRaisesRegexp(Invalid, MSG, IsFile(MSG), "/tarata/@==")
+
+    def test_is_dir(self):
+        import os
+        from onctuous import IsDir, Invalid
+
+        file = os.path.abspath(__file__)
+        dir = os.path.dirname(__file__)
+
+        self.assertEqual(dir, IsDir()(dir))
+        self.assertRaisesRegexp(Invalid, "directory", IsDir(), file)
+        self.assertRaisesRegexp(Invalid, "directory", IsDir(), "/tarata/@==")
+        self.assertRaisesRegexp(Invalid, MSG, IsDir(MSG), "/tarata/@==")
+
+    def test_path_exists(self):
+        import os
+        from onctuous import PathExists, Invalid
+
+        file = os.path.abspath(__file__)
+        dir = os.path.dirname(__file__)
+
+        self.assertEqual(dir, PathExists()(dir))
+        self.assertEqual(file, PathExists()(file))
+        self.assertRaisesRegexp(Invalid, "exist", PathExists(), "/tarata/@==")
+        self.assertRaisesRegexp(Invalid, MSG, PathExists(MSG), "/tarata/@==")
+
+    def test_in_range(self):
+        from onctuous import InRange, Invalid
+
+        self.assertEqual(3, InRange()(3))
+        self.assertEqual(3, InRange(min=1)(3))
+        self.assertEqual(3, InRange(max=4)(3))
+        self.assertEqual(3, InRange(min=1, max=4)(3))
+        self.assertEqual('ab', InRange(min='aaa', max='bbbb')('ab'))
+
+        self.assertRaisesRegexp(Invalid, "least", InRange(min=1), -1)
+        self.assertRaisesRegexp(Invalid, "least", InRange(min=1, max=3), -1)
+        self.assertRaisesRegexp(Invalid, "most", InRange(max=-2), -1)
+        self.assertRaisesRegexp(Invalid, MSG, InRange(max=-2, msg=MSG), -1)
+
+    def test_clamp(self):
+        from onctuous import Clamp
+
+        self.assertEqual(3, Clamp()(3))
+        self.assertEqual(3, Clamp(min=1)(3))
+        self.assertEqual(3, Clamp(max=4)(3))
+        self.assertEqual(3, Clamp(min=1, max=4)(3))
+        self.assertEqual('ab', Clamp(min='aa', max='bbbb')('ab'))
+
+        self.assertEqual(1, Clamp(min=1)(-1))
+        self.assertEqual(4, Clamp(max=4)(12))
+        self.assertEqual(1, Clamp(min=1, max=4)(-1))
+        self.assertEqual('baa', Clamp(min='baa', max='bbbb')('ab'))
+
+    def test_length(self):
+        from onctuous import Length, Invalid
+
+        self.assertEqual("Ludia", Length()("Ludia"))
+        self.assertEqual("Ludia", Length(min=1)("Ludia"))
+        self.assertEqual("Ludia", Length(max=10)("Ludia"))
+        self.assertEqual("Ludia", Length(min=1, max=10)("Ludia"))
+
+        self.assertRaisesRegexp(Invalid, "least", Length(min=10), "Ludia")
+        self.assertRaisesRegexp(Invalid, "least", Length(min=10, max=15), "Ludia")
+        self.assertRaisesRegexp(Invalid, "most", Length(max=4), "Ludia")
+        self.assertRaisesRegexp(Invalid, MSG, Length(max=4, msg=MSG), "Ludia")
+
+    def test_to_lower(self):
+        from onctuous import ToLower
+
+        self.assertEqual("ludia", ToLower("LuDiA"))
+
+    def test_to_upper(self):
+        from onctuous import ToUpper
+
+        self.assertEqual("LUDIA", ToUpper("LuDiA"))
+
+    def test_to_capitalize(self):
+        from onctuous import Capitalize
+
+        self.assertEqual("Ludia is awesome", Capitalize("LuDiA iS AwesOME"))
+
+    def test_to_title(self):
+        from onctuous import Title
+
+        self.assertEqual("Ludia Is Awesome", Title("LuDiA iS AwesOME"))
+
+    # very basic test
+    def test_any(self):
+        from onctuous import Any, Invalid
+
+        self.assertEqual("toto", Any("toto", "titi")("toto"))
+
+        self.assertRaisesRegexp(Invalid, "valid", Any("toto", "titi"), "tete")
+        self.assertRaisesRegexp(Invalid, MSG, Any("toto", "titi", msg=MSG), "tete")
+
+    # very basic test
+    def test_all(self):
+        from onctuous import All, Invalid
+
+        self.assertEqual(u"toto", All(unicode, u"toto")(u"toto"))
+
+        self.assertRaisesRegexp(Invalid, "valid", All(unicode, u"toto"), u"tete")
+        self.assertRaisesRegexp(Invalid, MSG, All(unicode, u"toto", msg=MSG), u"tete")
+
     Sphinx
 
 [nosetests]
-where = tests/
+where = onctuous/tests/
 match = ^test
 nocapture = 1
 cover-package = ddbmock

tests/__init__.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>

tests/functional/__init__.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>

tests/functional/test_global.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
-
-
-import unittest, mock
-
-class TestGlobal(unittest.TestCase):
-    def test_nested_data(self):
-        from onctuous import InvalidList, Schema, All, Coerce, Any
-
-        data1 = {
-            'exclude': ['Users', 'Uptime'],
-            'include': [],
-            'set': {
-                'snmp_community': 'public',
-                'snmp_timeout': 15,
-                'snmp_version': '2c',
-            },
-            'targets': {
-                'localhost': {
-                    'exclude': ['Uptime'],
-                    'features': {
-                        'Uptime': {
-                            'retries': 3,
-                        },
-                        'Users': {
-                            'snmp_community': 'monkey',
-                            'snmp_port': 15,
-                        },
-                    },
-                    'include': ['Users'],
-                    'set': {
-                        'snmp_community': 'monkeys',
-                    },
-                },
-            },
-        }
-
-        data2 = {
-            'set': {
-                'snmp_community': 'public',
-                'snmp_version': '2c',
-            },
-            'targets': {
-                'exclude': ['Ping'],
-                'features': {
-                    'Uptime': {'retries': 3},
-                    'Users': {'snmp_community': 'monkey'},
-                },
-            },
-        }
-
-        settings = {
-          'snmp_community': str,
-          'retries': int,
-          'snmp_version': All(Coerce(str), Any('3', '2c', '1')),
-        }
-        features = ['Ping', 'Uptime', 'Http']
-        validate = Schema({
-           'exclude': features,
-           'include': features,
-           'set': settings,
-           'targets': {
-             'exclude': features,
-             'include': features,
-             'features': {
-               str: settings,
-             },
-           },
-        })
-
-        expected = {
-            'set': {
-                'snmp_version': '2c',
-                'snmp_community': 'public',
-            },
-            'targets': {
-                'exclude': ['Ping'],
-                'features': {
-                    'Uptime': {'retries': 3},
-                    'Users': {'snmp_community': 'monkey'},
-                }
-            }
-        }
-
-        self.assertEqual(expected, validate(data2))
-        self.assertRaisesRegexp(InvalidList, "@", validate, data1)

tests/functional/test_schema.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
-
-
-import unittest
-
-MSG = "custom msg"
-
-class TestSchema(unittest.TestCase):
-    def test_dict(self):
-        from onctuous import Schema, InvalidList, Coerce, Required
-
-        validate = Schema({'one': 'two', 'three': 'four'})
-
-        # invalid dictionary value
-        self.assertRaisesRegexp(InvalidList, 'not a valid value', validate, {'one': 'three'})
-        # invalid key
-        self.assertRaisesRegexp(InvalidList, 'extra key', validate, {'two': 'three'})
-
-        # validate int type
-        validate = Schema({'one': 'two', 'three': 'four', int: str})
-        self.assertEqual({10: 'twenty'}, validate({10: 'twenty'}))
-        self.assertRaisesRegexp(InvalidList, 'extra key', validate, {'10': 'twenty'})
-
-        # validate with type coercion
-        validate = Schema({'one': 'two', 'three': 'four', Coerce(int): str})
-        self.assertEqual({10: 'twenty'}, validate({'10': 'twenty'}))
-
-        # test required key with defaults
-        validate = Schema({Required(1,default='toto'):str})
-        self.assertEqual({1: 'toto'}, validate({}))
-
-    def test_list(self):
-        from onctuous import Schema, InvalidList
-
-        self.assertEqual([1,2,3], Schema([1,2,3,4,5,6])([1,2,3]))
-        self.assertEqual([1,2,3], Schema([int])([1,2,3]))
-
-        # extra entry
-        self.assertRaisesRegexp(InvalidList, "value", Schema([1,2,3,4,5,6]), [0,1,2,3])
-
-
-    def test_msg(self):
-        from onctuous import Schema, InvalidList, Msg
-
-        # custom message for direct descendants errors
-        validate = Schema(Msg(['one', 'two', int], MSG))
-        self.assertRaisesRegexp(InvalidList, MSG, validate, ['three'])
-
-        # regular message for indirect descendants
-        validate = Schema(Msg([['one', 'two', int]], MSG))
-        self.assertRaisesRegexp(InvalidList, "invalid", validate, [['three']])
-
-    def test_any_all(self):
-        from onctuous import Schema, Any, All, InvalidList, Coerce
-
-        validate = Schema(Any('true', 'false', All(Any(int, bool), Coerce(bool))))
-        self.assertTrue(validate('true'))
-        self.assertTrue(validate(1))
-        self.assertRaisesRegexp(InvalidList, "valid", validate, "toto")
-
-        validate = Schema(Any({int: {int:str}}, bool))
-        self.assertRaises(InvalidList, validate, {1:{"2":"titi"}})
-

tests/unit/__init__.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>

tests/unit/test_invalid.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
-
-
-import unittest, mock
-
-MSG = "custom msg"
-MSG1 = "msg 1"
-MSG2 = "msg 2"
-PATH = ["path", "to", "error"]
-FULL_MSG = "custom msg @ data['path']['to']['error']"
-ERRORS = [KeyError(MSG1), ValueError(MSG2)]
-
-
-class TestInvalid(unittest.TestCase):
-    def test_invalid_init(self):
-        from onctuous import Invalid
-
-        inv = Invalid(MSG, PATH)
-
-        self.assertEqual((MSG,), inv.args)
-        self.assertEqual(MSG, inv.message)
-        self.assertEqual(PATH, inv.path)
-
-    def test_invalid_msg(self):
-        from onctuous import Invalid
-
-        inv = Invalid(MSG, PATH)
-        self.assertEqual(MSG, inv.msg)
-
-    def test_str(self):
-        from onctuous import Invalid
-
-        self.assertEqual(MSG, str(Invalid(MSG)))
-        self.assertEqual(FULL_MSG, str(Invalid(MSG, PATH)))
-
-
-class TestInvalidList(unittest.TestCase):
-    def test_invalid_list_init(self):
-        from onctuous import InvalidList
-
-        self.assertEqual(ERRORS, InvalidList(ERRORS).errors)
-        self.assertRaises(ValueError, InvalidList, [])
-
-    def test_invalid_list_msg(self):
-        from onctuous import InvalidList, Invalid
-
-        self.assertEqual(MSG1, InvalidList([Invalid(MSG1)]).msg)
-
-    def test_invalid_list_path(self):
-        from onctuous import InvalidList, Invalid
-
-        self.assertEqual([], InvalidList([Invalid(MSG1)]).path)
-        self.assertEqual(PATH, InvalidList([Invalid(MSG1, PATH)]).path)
-
-    def test_invalid_list_add(self):
-        from onctuous import InvalidList, Invalid
-
-        inv1 = Invalid(MSG1)
-        inv2 = Invalid(MSG2)
-
-        invlist = InvalidList([inv1])
-        invlist.add(inv2)
-
-        self.assertEqual([inv1, inv2], invlist.errors)
-

tests/unit/test_markers.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
-
-
-import unittest, mock
-
-MSG = "custom msg"
-
-class TestMarkers(unittest.TestCase):
-    def test_undefined(self):
-        from onctuous import Undefined, UNDEFINED
-
-        undef = Undefined()
-
-        self.assertEqual(Undefined, type(UNDEFINED))
-        self.assertEqual("...", repr(undef))
-        self.assertEqual("...", str(undef))
-        self.assertFalse(bool(undef))
-
-    def test_marker_init(self):
-        from onctuous import Marker
-
-        marker = Marker(int, msg=MSG)
-
-        self.assertEqual(int, marker.schema)
-        self.assertEqual(MSG, marker.msg)
-
-    def test_marker_str_repr(self):
-        from onctuous import Marker
-
-        marker = Marker(int, msg=MSG)
-
-        self.assertEqual("<type 'int'>", str(marker))
-        self.assertEqual("<type 'int'>", repr(marker))
-
-    def test_marker_call(self):
-        from onctuous import Marker, Invalid
-
-        marker1 = Marker(int)
-        marker2 = Marker(int, msg=MSG)
-
-        marker1(123)
-        marker2(123)
-
-        self.assertRaisesRegexp(Invalid, "expected", marker1, "toto")
-        self.assertRaisesRegexp(Invalid, MSG, marker2, "toto")
-
-    def test_required_init(self):
-        from onctuous import Required
-
-        marker = Required(int, default="Yeah !", msg=MSG)
-
-        self.assertEqual(int, marker.schema)
-        self.assertEqual(MSG, marker.msg)
-        self.assertEqual("Yeah !", marker.default)
-
-
-

tests/unit/test_schema.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
-
-
-import unittest, mock
-
-MSG1 = "msg 1"
-PATH = ["path", "to", "error"]
-
-class TestSchema(unittest.TestCase):
-    def test_schema_init(self):
-        from onctuous import Schema
-
-        schema = Schema(int, required=True, extra=True)
-        self.assertEqual(int, schema.schema)
-        self.assertEqual(True, schema.required)
-        self.assertEqual(True, schema.extra)
-
-        schema = Schema(int)
-        self.assertEqual(int, schema.schema)
-        self.assertEqual(False, schema.required)
-        self.assertEqual(False, schema.extra)
-
-    @mock.patch('onctuous.Schema.validate')
-    def test_schema_call(self, m_validate):
-        from onctuous import Schema
-
-        Schema(int)(123)
-        m_validate.assert_called_with([], int, 123)
-
-    @mock.patch('onctuous.Schema._validate_dict')
-    @mock.patch('onctuous.Schema._validate_list')
-    @mock.patch('onctuous.Schema._validate_scalar')
-    def test_schema_validate_scalar(self, m_val_scalar, m_val_list, m_val_dict):
-        from onctuous import Schema
-
-        Schema(None).validate([], int, 123)
-
-        m_val_scalar.assert_called_once_with([], int, 123)
-        self.assertFalse(m_val_dict.called)
-        self.assertFalse(m_val_list.called)
-
-    @mock.patch('onctuous.Schema._validate_dict')
-    @mock.patch('onctuous.Schema._validate_list')
-    @mock.patch('onctuous.Schema._validate_scalar')
-    def test_schema_validate_dict(self, m_val_scalar, m_val_list, m_val_dict):
-        from onctuous import Schema
-
-        Schema(None).validate([], {'a': 'b'}, {'a': 'b'})
-
-        m_val_dict.assert_called_once_with([], {'a': 'b'}, {'a': 'b'})
-        self.assertFalse(m_val_scalar.called)
-        self.assertFalse(m_val_list.called)
-
-    @mock.patch('onctuous.Schema._validate_dict')
-    @mock.patch('onctuous.Schema._validate_list')
-    @mock.patch('onctuous.Schema._validate_scalar')
-    def test_schema_validate_list(self, m_val_scalar, m_val_list, m_val_dict):
-        from onctuous import Schema
-
-        Schema(None).validate([], ['a', 'b'], ['a', 'b'])
-
-        m_val_list.assert_called_once_with([], ['a', 'b'], ['a', 'b'])
-        self.assertFalse(m_val_scalar.called)
-        self.assertFalse(m_val_dict.called)
-
-
-    @mock.patch('onctuous.Schema._validate_dict')
-    @mock.patch('onctuous.Schema._validate_list')
-    @mock.patch('onctuous.Schema._validate_scalar')
-    def test_schema_validate_scalar_error(self, m_val_scalar, m_val_list, m_val_dict):
-        from onctuous import Schema, InvalidList, Invalid
-
-        m_val_scalar.side_effect = Invalid(MSG1)
-        self.assertRaisesRegexp(InvalidList, MSG1, Schema(None).validate, [], int, 123)
-
-        m_val_scalar.side_effect = InvalidList([Invalid(MSG1)])
-        self.assertRaisesRegexp(InvalidList, MSG1, Schema(None).validate, [], int, 123)
-
-    def test_validate_scalar(self):
-        from onctuous import Schema, Invalid
-
-        # test value specification
-        self.assertEqual(123, Schema._validate_scalar([], 123, 123))
-        self.assertEqual("123", Schema._validate_scalar([], "123", "123"))
-
-        # test type specification
-        self.assertEqual(123, Schema._validate_scalar([], int, 123))
-        self.assertEqual("123", Schema._validate_scalar([], str, "123"))
-
-        # test callable specification
-        spec = mock.Mock()
-        spec.return_value = 123
-        self.assertEqual(123, Schema._validate_scalar([], spec, "123"))
-
-        # errors
-        self.assertRaises(Invalid, Schema._validate_scalar, [], "toto", "123")
-        self.assertRaises(Invalid, Schema._validate_scalar, [], int, "123")
-
-        spec.side_effect = ValueError()
-        self.assertRaises(Invalid, Schema._validate_scalar, [], spec, "123")
-        spec.side_effect = Invalid(MSG1)
-        self.assertRaisesRegexp(Invalid, MSG1, Schema._validate_scalar, [], spec, "123")
-
-    @mock.patch('onctuous.Schema.validate')
-    def test_validate_list(self, m_validate):
-        from onctuous import Schema, InvalidList, Invalid
-
-        # test with empty value
-        self.assertEqual([], Schema(None)._validate_list([], [1,2,3], []))
-
-        # test with empty condition
-        self.assertEqual([1,2,3], Schema(None)._validate_list([], [], [1,2,3]))
-
-        # regular validation path (if number seems awkward, remember: it's a mock)
-        m_validate.return_value = 42
-        self.assertEqual([42], Schema(None)._validate_list([], [1,2,3], [12]))
-        m_validate.assert_called_with([0], 1, 12)
-
-        # test with local error
-        m_validate.side_effect = Invalid(MSG1)
-        self.assertRaises(InvalidList, Schema(None)._validate_list, [], [1,2,3], [12])
-
-        # test with deep error (sub item) (weird logic btw)
-        m_validate.side_effect = Invalid(MSG1, PATH)
-        self.assertRaises(Invalid, Schema(None)._validate_list, [], [1,2,3], [12])
-
-    @mock.patch('onctuous.Schema.validate')
-    def test_validate_dict(self, m_validate):
-        from onctuous import Schema, InvalidList, Invalid, Required, Optional, Extra
-
-        # test with empty schema and extra
-        self.assertEqual({'1':'2'}, Schema(None, extra=True)._validate_dict([], {}, {'1':'2'}))
-        self.assertRaisesRegexp(InvalidList, "extra", Schema(None)._validate_dict, [], {}, {'1':'2'})
-
-        # test per schema extra
-        self.assertEqual({'1':'2'}, Schema(None)._validate_dict([], {Extra: 'whatever'}, {'1':'2'}))
-
-        # no key required
-        self.assertEqual({}, Schema(None)._validate_dict([], {'1':'2'}, {}))
-
-        # all key required
-        m_validate.return_value = 42
-        self.assertEqual({42:42}, Schema(None, required=True)._validate_dict([], {'1':'2'}, {'1':'2'}))
-        self.assertRaisesRegexp(InvalidList, "required", Schema(None, required=True)._validate_dict, [], {'1':'2'}, {})
-
-        # all key required BUT optional (sic)
-        m_validate.return_value = 42
-        self.assertEqual({}, Schema(None, required=True)._validate_dict([], {Optional('1'):'2'}, {}))
-        self.assertEqual({42:42}, Schema(None, required=True)._validate_dict([], {Optional('1'):'2'}, {'1':'2'}))
-
-        # individual key required
-        m_validate.return_value = 42
-        self.assertEqual({42:42}, Schema(None)._validate_dict([], {Required('1'):'2'}, {'1':'2'}))
-        self.assertRaisesRegexp(InvalidList, "required", Schema(None)._validate_dict, [], {Required('1'):'2'}, {})

tests/unit/test_validators.py

-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2012 Ludia Inc.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution.
-#
-# Author: Jean-Tiare Le Bigot <jtlebigot@socialludia.com>
-
-
-import unittest, mock
-
-MSG = "custom msg"
-
-class TestValidators(unittest.TestCase):
-    def test_extra(self):
-        from onctuous import Extra, SchemaError
-
-        self.assertRaises(SchemaError, Extra, "_")
-
-    def test_msg(self):
-        from onctuous import Msg, Invalid
-
-        self.assertEqual(123, Msg(int, msg=MSG)(123))
-        self.assertRaisesRegexp(Invalid, MSG, Msg(int, msg=MSG), "hello")
-
-    def test_coerce(self):
-        from onctuous import Coerce, Invalid
-
-        self.assertRaisesRegexp(Invalid, "expected", Coerce(int), "hello")
-        self.assertRaisesRegexp(Invalid, MSG, Coerce(int, MSG), "hello")
-
-    def test_is_true(self):
-        from onctuous import IsTrue, Invalid
-
-        self.assertEqual("123", IsTrue()("123"))
-        self.assertEqual(["123"], IsTrue()(["123"]))
-        self.assertEqual(True, IsTrue()(True))
-
-        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), "")
-        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), [])
-        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), {})
-        self.assertRaisesRegexp(Invalid, MSG, IsTrue(MSG), False)
-        self.assertRaisesRegexp(Invalid, "value", IsTrue(), False)
-
-    def test_is_false(self):
-        from onctuous import IsFalse, Invalid
-
-        self.assertEqual("", IsFalse()(""))
-        self.assertEqual([], IsFalse()([]))
-        self.assertEqual(False, IsFalse()(False))
-
-        self.assertRaisesRegexp(Invalid, MSG, IsFalse(MSG), "123")
-        self.assertRaisesRegexp(Invalid, MSG, IsFalse(MSG), ["123"])
-        self.assertRaisesRegexp(Invalid, MSG, IsFalse(MSG), True)
-        self.assertRaisesRegexp(Invalid, "value", IsFalse(), True)
-
-    def test_boolean(self):
-        from onctuous import Boolean, Invalid
-
-        self.assertEqual(True, Boolean()(-42))
-        self.assertEqual(True, Boolean()(True))
-        self.assertEqual(True, Boolean()(['toto']))
-        self.assertEqual(True, Boolean()('1'))
-        self.assertEqual(True, Boolean()('trUe'))
-        self.assertEqual(True, Boolean()('yeS'))
-        self.assertEqual(True, Boolean()('oN'))
-        self.assertEqual(True, Boolean()('eNable'))
-
-        self.assertEqual(False, Boolean()(0))
-        self.assertEqual(False, Boolean()(False))
-        self.assertEqual(False, Boolean()([]))
-        self.assertEqual(False, Boolean()('0'))
-        self.assertEqual(False, Boolean()('fALse'))
-        self.assertEqual(False, Boolean()('nO'))
-        self.assertEqual(False, Boolean()('oFf'))
-        self.assertEqual(False, Boolean()('diSAble'))
-
-        self.assertRaisesRegexp(Invalid, MSG, Boolean(MSG), "toto")
-        self.assertRaisesRegexp(Invalid, "expected", Boolean(), "toto")
-
-    @mock.patch('__builtin__.bool')
-    def test_boolean_error(self, m_bool):
-        from onctuous import Boolean, Invalid
-
-        m_bool.side_effect = ValueError
-        self.assertRaisesRegexp(Invalid, "expected", Boolean(), None)
-
-    def test_match(self):
-        from onctuous import Match, Invalid
-
-        self.assertEqual("0x123bAc", Match("^0x[a-fA-F0-9]+$")("0x123bAc"))
-        self.assertEqual("0x123bAc", Match(r"^0x[a-fA-F0-9]+$")("0x123bAc"))
-
-        self.assertRaisesRegexp(Invalid, MSG, Match("^0x[a-fA-F0-9]+$", MSG), "toto")
-        self.assertRaisesRegexp(Invalid, "match", Match("^0x[a-fA-F0-9]+$"), "toto")
-
-    def test_sub(self):
-        from onctuous import Sub
-
-        self.assertEqual("Hi You!", Sub("toto", "Chuck")("Hi You!"))
-        self.assertEqual("Hi Chuck!", Sub("You", "Chuck")("Hi You!"))
-        self.assertEqual("Hi Chuck!", Sub("[Yy]ou", "Chuck")("Hi you!"))
-        self.assertEqual("Hi Chuck!", Sub(r"[Yy]ou", "Chuck")("Hi you!"))
-
-    def test_url(self):
-        from onctuous import Url, Invalid
-
-        self.assertEqual("www.example.com", Url()("www.example.com"))
-        self.assertEqual("www.example.com/my/resource", Url()("www.example.com/my/resource"))
-        self.assertEqual("www.example.com:42/", Url()("www.example.com:42/"))
-        self.assertEqual("toto://www.example.com:42/", Url()("toto://www.example.com:42/"))
-        self.assertEqual("toto://jt@www.example.com:42/", Url()("toto://jt@www.example.com:42/"))
-        self.assertEqual("toto://jt:pwd@www.example.com:42/", Url()("toto://jt:pwd@www.example.com:42/"))
-
-        self.assertRaisesRegexp(Invalid, MSG, Url(MSG), 123)
-        self.assertRaisesRegexp(Invalid, "URL", Url(), 132)
-
-    def test_is_file(self):
-        import os
-        from onctuous import IsFile, Invalid
-
-        file = os.path.abspath(__file__)
-        dir = os.path.dirname(__file__)
-
-        self.assertEqual(file, IsFile()(file))
-        self.assertRaisesRegexp(Invalid, "file", IsFile(), dir)
-        self.assertRaisesRegexp(Invalid, "file", IsFile(), "/tarata/@==")
-        self.assertRaisesRegexp(Invalid, MSG, IsFile(MSG), "/tarata/@==")
-
-    def test_is_dir(self):
-        import os
-        from onctuous import IsDir, Invalid
-
-        file = os.path.abspath(__file__)
-        dir = os.path.dirname(__file__)
-
-        self.assertEqual(dir, IsDir()(dir))
-        self.assertRaisesRegexp(Invalid, "directory", IsDir(), file)
-        self.assertRaisesRegexp(Invalid, "directory", IsDir(), "/tarata/@==")
-        self.assertRaisesRegexp(Invalid, MSG, IsDir(MSG), "/tarata/@==")
-
-    def test_path_exists(self):
-        import os
-        from onctuous import PathExists, Invalid
-
-        file = os.path.abspath(__file__)
-        dir = os.path.dirname(__file__)
-
-        self.assertEqual(dir, PathExists()(dir))
-        self.assertEqual(file, PathExists()(file))
-        self.assertRaisesRegexp(Invalid, "exist", PathExists(), "/tarata/@==")
-        self.assertRaisesRegexp(Invalid, MSG, PathExists(MSG), "/tarata/@==")
-
-    def test_in_range(self):
-        from onctuous import InRange, Invalid
-
-        self.assertEqual(3, InRange()(3))
-        self.assertEqual(3, InRange(min=1)(3))
-        self.assertEqual(3, InRange(max=4)(3))
-        self.assertEqual(3, InRange(min=1, max=4)(3))
-        self.assertEqual('ab', InRange(min='aaa', max='bbbb')('ab'))
-
-        self.assertRaisesRegexp(Invalid, "least", InRange(min=1), -1)
-        self.assertRaisesRegexp(Invalid, "least", InRange(min=1, max=3), -1)
-        self.assertRaisesRegexp(Invalid, "most", InRange(max=-2), -1)
-        self.assertRaisesRegexp(Invalid, MSG, InRange(max=-2, msg=MSG), -1)
-
-    def test_clamp(self):
-        from onctuous import Clamp
-
-        self.assertEqual(3, Clamp()(3))
-        self.assertEqual(3, Clamp(min=1)(3))
-        self.assertEqual(3, Clamp(max=4)(3))
-        self.assertEqual(3, Clamp(min=1, max=4)(3))
-        self.assertEqual('ab', Clamp(min='aa', max='bbbb')('ab'))
-
-        self.assertEqual(1, Clamp(min=1)(-1))
-        self.assertEqual(4, Clamp(max=4)(12))
-        self.assertEqual(1, Clamp(min=1, max=4)(-1))
-        self.assertEqual('baa', Clamp(min='baa', max='bbbb')('ab'))
-
-    def test_length(self):
-        from onctuous import Length, Invalid
-
-        self.assertEqual("Ludia", Length()("Ludia"))
-        self.assertEqual("Ludia", Length(min=1)("Ludia"))
-        self.assertEqual("Ludia", Length(max=10)("Ludia"))
-        self.assertEqual("Ludia", Length(min=1, max=10)("Ludia"))
-
-        self.assertRaisesRegexp(Invalid, "least", Length(min=10), "Ludia")
-        self.assertRaisesRegexp(Invalid, "least", Length(min=10, max=15), "Ludia")
-        self.assertRaisesRegexp(Invalid, "most", Length(max=4), "Ludia")
-        self.assertRaisesRegexp(Invalid, MSG, Length(max=4, msg=MSG), "Ludia")
-
-    def test_to_lower(self):
-        from onctuous import ToLower
-
-        self.assertEqual("ludia", ToLower("LuDiA"))
-
-    def test_to_upper(self):
-        from onctuous import ToUpper
-
-        self.assertEqual("LUDIA", ToUpper("LuDiA"))
-
-    def test_to_capitalize(self):
-        from onctuous import Capitalize
-
-        self.assertEqual("Ludia is awesome", Capitalize("LuDiA iS AwesOME"))
-
-    def test_to_title(self):
-        from onctuous import Title
-
-        self.assertEqual("Ludia Is Awesome", Title("LuDiA iS AwesOME"))
-
-    # very basic test
-    def test_any(self):
-        from onctuous import Any, Invalid
-
-        self.assertEqual("toto", Any("toto", "titi")("toto"))
-
-        self.assertRaisesRegexp(Invalid, "valid", Any("toto", "titi"), "tete")
-        self.assertRaisesRegexp(Invalid, MSG, Any("toto", "titi", msg=MSG), "tete")
-
-    # very basic test
-    def test_all(self):
-        from onctuous import All, Invalid
-
-        self.assertEqual(u"toto", All(unicode, u"toto")(u"toto"))
-
-        self.assertRaisesRegexp(Invalid, "valid", All(unicode, u"toto"), u"tete")
-        self.assertRaisesRegexp(Invalid, MSG, All(unicode, u"toto", msg=MSG), u"tete")
-