coverage for tiramisu/option/option.py
authorEmmanuel Garette <egarette@cadoles.com>
Sat, 4 Feb 2017 09:21:44 +0000 (10:21 +0100)
committerEmmanuel Garette <egarette@cadoles.com>
Sat, 4 Feb 2017 09:21:44 +0000 (10:21 +0100)
test/test_choice_option.py
test/test_config_domain.py
test/test_config_ip.py
test/test_option_type.py
tiramisu/option/option.py

index 8565be9..7469d9b 100644 (file)
@@ -22,6 +22,10 @@ def return_calc_list(val):
     return [val]
 
 
+def return_error():
+    raise Exception('test')
+
+
 def test_choiceoption_function():
     ch = ChoiceOption('ch', '', values=return_list)
     od = OptionDescription('od', '', [ch])
@@ -39,6 +43,14 @@ def test_choiceoption_function():
     assert ch.impl_get_values(cfg) == ['val1', 'val2']
 
 
+def test_choiceoption_function_error():
+    ch = ChoiceOption('ch', '', values=return_error)
+    od = OptionDescription('od', '', [ch])
+    cfg = Config(od)
+    cfg.read_write()
+    raises(Exception, "cfg.ch = 'no'")
+
+
 def test_choiceoption_calc_function():
     ch = ChoiceOption('ch', "", values=return_calc_list, values_params={'': ('val1',)})
     od = OptionDescription('od', '', [ch])
@@ -70,6 +82,15 @@ def test_choiceoption_calc_opt_function():
     assert cfg.getowner(ch) == owners.default
 
 
+def test_choiceoption_calc_opt_function_propertyerror():
+    st = StrOption('st', '', 'val1', properties=('disabled',))
+    ch = ChoiceOption('ch', "", values=return_calc_list, values_params={'': ((st, False),)})
+    od = OptionDescription('od', '', [st, ch])
+    cfg = Config(od)
+    cfg.read_write()
+    raises(ValueError, "cfg.ch='no'")
+
+
 def test_choiceoption_calc_opt_multi_function():
     st = StrOption('st', '', ['val1'], multi=True)
     ch = ChoiceOption('ch', "", default_multi='val2', values=return_val, values_params={'': ((st, False),)}, multi=True)
index 8225187..528efda 100644 (file)
@@ -146,6 +146,7 @@ def test_email():
     c.e = u'foo-bar.baz@example.com'
     c.e = u'root@foo.com'
     c.e = u'root@domain'
+    raises(ValueError, "c.e = 1")
     raises(ValueError, "c.e = u'root'")
     raises(ValueError, "c.e = u'root[]@domain'")
 
@@ -158,6 +159,7 @@ def test_url():
     c.u = 'http://foo.com'
     c.u = 'https://foo.com'
     c.u = 'https://foo.com/'
+    raises(ValueError, "c.u = 1")
     raises(ValueError, "c.u = 'ftp://foo.com'")
     raises(ValueError, "c.u = 'foo.com'")
     raises(ValueError, "c.u = ':/foo.com'")
index dfcb4af..3f15b02 100644 (file)
@@ -5,7 +5,7 @@ import warnings
 from py.test import raises
 from tiramisu.config import Config
 from tiramisu.option import IPOption, NetworkOption, NetmaskOption, \
-    PortOption, OptionDescription
+    PortOption, BroadcastOption, OptionDescription
 from tiramisu.error import ValueWarning
 
 
@@ -26,6 +26,7 @@ def test_ip():
     raises(ValueError, "c.b = '88.88.88.88'")
     c.b = '0.0.0.0'
     raises(ValueError, "c.b = '255.255.255.0'")
+    raises(ValueError, "c.a = '333.0.1.20'")
 
     raises(ValueError, "IPOption('a', 'ip', default='192.000.023.01')")
     with warnings.catch_warnings(record=True) as w:
@@ -64,7 +65,11 @@ def test_network():
     c.a = '192.168.1.0'
     c.a = '88.88.88.88'
     c.a = '0.0.0.0'
+    raises(ValueError, "c.a = 1")
+    raises(ValueError, "c.a = '1.1.1.1.1'")
     raises(ValueError, "c.a = '255.255.255.0'")
+    raises(ValueError, "c.a = '192.168.001.0'")
+    raises(ValueError, "c.a = '333.168.1.1'")
     with warnings.catch_warnings(record=True) as w:
         c.b = '255.255.255.0'
     assert len(w) == 1
@@ -78,9 +83,25 @@ def test_netmask():
     a = NetmaskOption('a', '')
     od = OptionDescription('od', '', [a])
     c = Config(od)
+    raises(ValueError, "c.a = '192.168.1.1.1'")
     raises(ValueError, "c.a = '192.168.1.1'")
     raises(ValueError, "c.a = '192.168.1.0'")
     raises(ValueError, "c.a = '88.88.88.88'")
+    raises(ValueError, "c.a = '255.255.255.000'")
+    raises(ValueError, "c.a = 2")
+    c.a = '0.0.0.0'
+    c.a = '255.255.255.0'
+
+
+def test_broadcast():
+    a = BroadcastOption('a', '')
+    od = OptionDescription('od', '', [a])
+    c = Config(od)
+    raises(ValueError, "c.a = '192.168.1.255.1'")
+    raises(ValueError, "c.a = '192.168.001.255'")
+    raises(ValueError, "c.a = '192.168.0.300'")
+    raises(ValueError, "c.a = 1")
+    raises(ValueError, "c.a = 2")
     c.a = '0.0.0.0'
     c.a = '255.255.255.0'
 
index c80cc83..2da3e92 100644 (file)
@@ -7,7 +7,7 @@ from py.test import raises
 
 from tiramisu.config import Config
 from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
-    StrOption, OptionDescription
+    PasswordOption, StrOption, DateOption, OptionDescription
 from tiramisu.error import PropertiesOptionError
 
 
@@ -133,3 +133,28 @@ def test_with_many_subgroups():
     assert name == "booltwo"
     getattr(homeconfig.cfgimpl_get_description(), name)
     assert 'hidden' in setting[booltwo]
+
+
+def test_password_option():
+    o = PasswordOption('o', '')
+    d = OptionDescription('d', '', [o])
+    c = Config(d)
+
+    c.o = u'a_valid_password'
+    raises(ValueError, "c.o = 1")
+
+
+def test_date_option():
+    o = DateOption('o', '')
+    d = OptionDescription('d', '', [o])
+    c = Config(d)
+
+    c.o = u'2017-02-04'
+    c.o = u'2017-2-4'
+    raises(ValueError, "c.o = 1")
+    raises(ValueError, "c.o = u'2017-13-20'")
+    raises(ValueError, "c.o = u'2017-11-31'")
+    raises(ValueError, "c.o = u'2017-12-32'")
+    raises(ValueError, "c.o = u'2017-2-29'")
+    raises(ValueError, "c.o = u'2-2-2017'")
+    raises(ValueError, "c.o = u'2017/2/2'")
index 5b72236..600cf2a 100644 (file)
@@ -53,7 +53,7 @@ class ChoiceOption(Option):
         else:
             if values_params is not None:
                 raise ValueError(_('values is not a function, so values_params must be None'))
-            if not isinstance(values, tuple):  # pragma: optional cover
+            if not isinstance(values, tuple):
                 raise TypeError(_('values must be a tuple or a function for {0}'
                                   ).format(name))
         session = self.getsession()
@@ -74,23 +74,18 @@ class ChoiceOption(Option):
     def impl_get_values(self, context, current_opt=undefined):
         if current_opt is undefined:
             current_opt = self
-        params = undefined
         #FIXME cache? but in context...
         values = self._choice_values
         if isinstance(values, FunctionType):
             if context is None:
                 values = []
             else:
-                if params is not undefined:
-                    values_params = params
-                else:
-                    values_params = self.impl_get_choice_values_params()
                 values = carry_out_calculation(current_opt, context=context,
                                                callback=values,
-                                               callback_params=values_params)
+                                               callback_params=self.impl_get_choice_values_params())
                 if isinstance(values, Exception):
                     return values
-                if values is not undefined and not isinstance(values, list):  # pragma: optional cover
+                if values is not undefined and not isinstance(values, list):
                     raise ConfigError(_('calculated values for {0} is not a list'
                                         '').format(self.impl_getname()))
         return values
@@ -100,7 +95,7 @@ class ChoiceOption(Option):
         values = self.impl_get_values(context, current_opt=current_opt)
         if isinstance(values, Exception):
             return values
-        if values is not undefined and not value in values:  # pragma: optional cover
+        if values is not undefined and not value in values:
             if len(values) == 1:
                 return ValueError(_('only {0} is allowed'
                                     '').format(values[0]))
@@ -116,7 +111,7 @@ class BoolOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, bool):
-            return ValueError()  # pragma: optional cover
+            return ValueError()
 
 
 class IntOption(Option):
@@ -126,7 +121,7 @@ class IntOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, int):
-            return ValueError()  # pragma: optional cover
+            return ValueError()
 
 
 class FloatOption(Option):
@@ -136,7 +131,7 @@ class FloatOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, float):
-            return ValueError()  # pragma: optional cover
+            return ValueError()
 
 
 class StrOption(Option):
@@ -146,10 +141,10 @@ class StrOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if not isinstance(value, str):
-            return ValueError()  # pragma: optional cover
+            return ValueError()
 
 
-if sys.version_info[0] >= 3:  # pragma: optional cover
+if sys.version_info[0] >= 3:  # pragma: no cover
     #UnicodeOption is same as StrOption in python 3+
     class UnicodeOption(StrOption):
         __slots__ = tuple()
@@ -163,7 +158,7 @@ else:
 
         def _validate(self, value, context=undefined, current_opt=undefined):
             if not isinstance(value, unicode):
-                return ValueError()  # pragma: optional cover
+                return ValueError()
 
 
 class PasswordOption(Option):
@@ -211,22 +206,22 @@ class IPOption(Option):
             return ValueError()
         for val in value.split('.'):
             if val.startswith("0") and len(val) > 1:
-                return ValueError()  # pragma: optional cover
+                return ValueError()
         # 'standard' validation
         try:
             IP('{0}/32'.format(value))
-        except ValueError:  # pragma: optional cover
+        except ValueError:
             return ValueError()
 
     def _second_level_validation(self, value, warnings_only):
         ip = IP('{0}/32'.format(value))
-        if not self._get_extra('_allow_reserved') and ip.iptype() == 'RESERVED':  # pragma: optional cover
+        if not self._get_extra('_allow_reserved') and ip.iptype() == 'RESERVED':
             if warnings_only:
                 msg = _("shouldn't in reserved class")
             else:
                 msg = _("mustn't be in reserved class")
             return ValueError(msg)
-        if self._get_extra('_private_only') and not ip.iptype() == 'PRIVATE':  # pragma: optional cover
+        if self._get_extra('_private_only') and not ip.iptype() == 'PRIVATE':
             if warnings_only:
                 msg = _("should be in private class")
             else:
@@ -235,11 +230,11 @@ class IPOption(Option):
 
     def _cons_in_network(self, current_opt, opts, vals, warnings_only):
         if len(vals) != 3:
-            raise ConfigError(_('invalid len for vals'))  # pragma: optional cover
+            raise ConfigError(_('invalid len for vals'))
         if None in vals:
             return
         ip, network, netmask = vals
-        if IP(ip) not in IP('{0}/{1}'.format(network, netmask)):  # pragma: optional cover
+        if IP(ip) not in IP('{0}/{1}'.format(network, netmask)):
             if warnings_only:
                 msg = _('should be in network {0}/{1} ({2}/{3})')
             else:
@@ -286,12 +281,12 @@ class PortOption(Option):
             elif not allowed:
                 is_finally = True
             elif allowed and is_finally:
-                raise ValueError(_('inconsistency in allowed range'))  # pragma: optional cover
+                raise ValueError(_('inconsistency in allowed range'))
             if allowed:
                 extra['_max_value'] = ports_max[index]
 
         if extra['_max_value'] is None:
-            raise ValueError(_('max value is empty'))  # pragma: optional cover
+            raise ValueError(_('max value is empty'))
 
         super(PortOption, self).__init__(name, doc, default=default,
                                          default_multi=default_multi,
@@ -307,14 +302,14 @@ class PortOption(Option):
 
     def _validate(self, value, context=undefined, current_opt=undefined):
         if isinstance(value, int):
-            if sys.version_info[0] >= 3:  # pragma: optional cover
+            if sys.version_info[0] >= 3:  # pragma: no cover
                 value = str(value)
             else:
                 value = unicode(value)
         err = self._impl_valid_unicode(value)
         if err:
             return err
-        if self._get_extra('_allow_range') and ":" in str(value):  # pragma: optional cover
+        if self._get_extra('_allow_range') and ":" in str(value):
             value = str(value).split(':')
             if len(value) != 2:
                 return ValueError(_('range must have two values only'))
@@ -328,7 +323,7 @@ class PortOption(Option):
             if not self.port_re.search(val):
                 return ValueError()
             val = int(val)
-            if not self._get_extra('_min_value') <= val <= self._get_extra('_max_value'):  # pragma: optional cover
+            if not self._get_extra('_min_value') <= val <= self._get_extra('_max_value'):
                 return ValueError(_('must be an integer between {0} '
                                     'and {1}').format(self._get_extra('_min_value'),
                                                       self._get_extra('_max_value')))
@@ -350,12 +345,12 @@ class NetworkOption(Option):
                 return ValueError()
         try:
             IP(value)
-        except ValueError:  # pragma: optional cover
+        except ValueError:
             return ValueError()
 
     def _second_level_validation(self, value, warnings_only):
         ip = IP(value)
-        if ip.iptype() == 'RESERVED':  # pragma: optional cover
+        if ip.iptype() == 'RESERVED':
             if warnings_only:
                 msg = _("shouldn't be in reserved class")
             else:
@@ -379,7 +374,7 @@ class NetmaskOption(Option):
                 return ValueError()
         try:
             IP('0.0.0.0/{0}'.format(value))
-        except ValueError:  # pragma: optional cover
+        except ValueError:
             return ValueError()
 
     def _cons_network_netmask(self, current_opt, opts, vals, warnings_only):
@@ -397,7 +392,7 @@ class NetmaskOption(Option):
     def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net,
                        warnings_only):
         if len(opts) != 2:
-            return ConfigError(_('invalid len for opts'))  # pragma: optional cover
+            return ConfigError(_('invalid len for opts'))
         msg = None
         try:
             ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask),
@@ -410,10 +405,10 @@ class NetmaskOption(Option):
                 if ip.broadcast() == val_ip:
                     msg = _("this is a broadcast with netmask {0} ({1})")
 
-        except ValueError:  # pragma: optional cover
+        except ValueError:
             if not make_net:
                 msg = _('with netmask {0} ({1})')
-        if msg is not None:  # pragma: optional cover
+        if msg is not None:
             return ValueError(msg.format(val_netmask, opts[1].impl_getname()))
 
 
@@ -425,20 +420,25 @@ class BroadcastOption(Option):
         err = self._impl_valid_unicode(value)
         if err:
             return err
+        if value.count('.') != 3:
+            return ValueError()
+        for val in value.split('.'):
+            if val.startswith("0") and len(val) > 1:
+                return ValueError()
         try:
             IP('{0}/32'.format(value))
-        except ValueError:  # pragma: optional cover
+        except ValueError:
             return ValueError()
 
     def _cons_broadcast(self, current_opt, opts, vals, warnings_only):
         if len(vals) != 3:
-            raise ConfigError(_('invalid len for vals'))  # pragma: optional cover
+            raise ConfigError(_('invalid len for vals'))
         if None in vals:
             return
         broadcast, network, netmask = vals
         if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast):
             return ValueError(_('with network {0}/{1} ({2}/{3})').format(
-                network, netmask, opts[1].impl_getname(), opts[2].impl_getname()))  # pragma: optional cover
+                network, netmask, opts[1].impl_getname(), opts[2].impl_getname()))
 
 
 class DomainnameOption(Option):
@@ -457,12 +457,12 @@ class DomainnameOption(Option):
                  properties=None, allow_ip=False, type_='domainname',
                  warnings_only=False, allow_without_dot=False):
         if type_ not in ['netbios', 'hostname', 'domainname']:
-            raise ValueError(_('unknown type_ {0} for hostname').format(type_))  # pragma: optional cover
+            raise ValueError(_('unknown type_ {0} for hostname').format(type_))
         extra = {'_dom_type': type_}
         if allow_ip not in [True, False]:
-            raise ValueError(_('allow_ip must be a boolean'))  # pragma: optional cover
+            raise ValueError(_('allow_ip must be a boolean'))
         if allow_without_dot not in [True, False]:
-            raise ValueError(_('allow_without_dot must be a boolean'))  # pragma: optional cover
+            raise ValueError(_('allow_without_dot must be a boolean'))
         extra['_allow_ip'] = allow_ip
         extra['_allow_without_dot'] = allow_without_dot
         extra['_domain_re'] = re.compile(r'^[a-z\d][a-z\d\-]*$')
@@ -492,7 +492,7 @@ class DomainnameOption(Option):
                 return ValueError(_("invalid length (max {0})"
                                     "").format(part_name_length))
 
-        if self._get_extra('_allow_ip') is True:  # pragma: optional cover
+        if self._get_extra('_allow_ip') is True:
             try:
                 IP('{0}/32'.format(value))
                 return
@@ -555,7 +555,7 @@ class URLOption(DomainnameOption):
         if err:
             return err
         match = self.proto_re.search(value)
-        if not match:  # pragma: optional cover
+        if not match:
             return ValueError(_('must start with http:// or '
                                 'https://'))
         value = value[len(match.group(0)):]
@@ -575,7 +575,7 @@ class URLOption(DomainnameOption):
             domain, port = splitted
         if not 0 <= int(port) <= 65535:
             return ValueError(_('port must be an between 0 and '
-                                '65536'))  # pragma: optional cover
+                                '65536'))
         # validate domainname
         err = super(URLOption, self)._validate(domain)
         if err:
@@ -585,7 +585,7 @@ class URLOption(DomainnameOption):
             return err
         # validate file
         if files is not None and files != '' and not self.path_re.search(files):
-            return ValueError(_('must ends with a valid resource name'))  # pragma: optional cover
+            return ValueError(_('must ends with a valid resource name'))
 
     def _second_level_validation(self, value, warnings_only):
         pass