papi: fix default handling 27/22927/3
authorOle Troan <ot@cisco.com>
Tue, 22 Oct 2019 12:01:53 +0000 (14:01 +0200)
committerDamjan Marion <dmarion@me.com>
Wed, 23 Oct 2019 07:47:19 +0000 (07:47 +0000)
The BaseTypers object were reused, so a default for anyother mesage
would be inherited in new messages.

Type: fix
Fixes: 85465588b18fef9c4712f864f512e00741e2d4f2
Change-Id: Ie1efb85a76b088653eb9ea4b88540c98b6b0aad0
Signed-off-by: Ole Troan <ot@cisco.com>
src/vpp-api/python/vpp_papi/tests/test_vpp_serializer.py
src/vpp-api/python/vpp_papi/vpp_serializer.py

index 9ac3e78..5221034 100755 (executable)
@@ -66,14 +66,43 @@ class TestDefaults(unittest.TestCase):
     def test_defaults(self):
         default_type = VPPType('default_type_t',
                                [['u16', 'mtu', {'default': 1500, 'limit': 0}]])
+        without_default_type = VPPType('without_default_type_t',
+                                       [['u16', 'mtu']])
 
         b = default_type.pack({})
         self.assertEqual(len(b), 2)
-
         nt, size = default_type.unpack(b)
         self.assertEqual(len(b), size)
         self.assertEqual(nt.mtu, 1500)
 
+        # distinguish between parameter 0 and parameter not passed
+        b = default_type.pack({'mtu': 0})
+        self.assertEqual(len(b), 2)
+        nt, size = default_type.unpack(b)
+        self.assertEqual(len(b), size)
+        self.assertEqual(nt.mtu, 0)
+
+        # Ensure that basetypes does not inherit default
+        b = without_default_type.pack({})
+        self.assertEqual(len(b), 2)
+        nt, size = default_type.unpack(b)
+        self.assertEqual(len(b), size)
+        self.assertEqual(nt.mtu, 0)
+
+        # default enum type
+        VPPEnumType('vl_api_enum_t', [["ADDRESS_IP4", 0],
+                                      ["ADDRESS_IP6", 1],
+                                      {"enumtype": "u32"}])
+
+        default_with_enum = VPPType('default_enum_type_t',
+                                    [['u16', 'mtu'], ['vl_api_enum_t',
+                                                      'e', {'default': 1}]])
+
+        b = default_with_enum.pack({})
+        self.assertEqual(len(b), 6)
+        nt, size = default_with_enum.unpack(b)
+        self.assertEqual(len(b), size)
+        self.assertEqual(nt.e, 1)
 
 class TestAddType(unittest.TestCase):
 
index 8ae46fe..b04530c 100644 (file)
@@ -88,12 +88,8 @@ class BaseTypes(object):
         self.size = self.packer.size
         self.options = options
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     def pack(self, data, kwargs=None):
-        if not data:  # Default to zero if not specified
+        if data is None:  # Default to zero if not specified
             if self.options and 'default' in self.options:
                 data = self.options['default']
             else:
@@ -152,6 +148,7 @@ types = {'u8': BaseTypes('u8'), 'u16': BaseTypes('u16'),
          'u64': BaseTypes('u64'), 'f64': BaseTypes('f64'),
          'bool': BaseTypes('bool'), 'string': String}
 
+class_types = {}
 
 def vpp_get_type(name):
     try:
@@ -172,10 +169,6 @@ class FixedList_u8(object):
         self.size = self.packer.size
         self.field_type = field_type
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     def pack(self, data, kwargs=None):
         """Packs a fixed length bytestring. Left-pads with zeros
         if input data is too short."""
@@ -211,10 +204,6 @@ class FixedList(object):
         self.name = name
         self.field_type = field_type
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     def pack(self, list, kwargs):
         if len(list) != self.num:
             raise VPPSerializerValueError(
@@ -246,10 +235,6 @@ class VLAList(object):
         self.size = self.packer.size
         self.length_field = len_field_name
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     def pack(self, lst, kwargs=None):
         if not lst:
             return b""
@@ -294,10 +279,6 @@ class VLAList_legacy():
         self.packer = types[field_type]
         self.size = self.packer.size
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     def pack(self, list, kwargs=None):
         if self.packer.size == 1:
             return bytes(list)
@@ -324,9 +305,11 @@ class VLAList_legacy():
 
 
 class VPPEnumType(object):
-    def __init__(self, name, msgdef):
+    def __init__(self, name, msgdef, options=None):
         self.size = types['u32'].size
+        self.name = name
         self.enumtype = 'u32'
+        self.msgdef = msgdef
         e_hash = {}
         for f in msgdef:
             if type(f) is dict and 'enumtype' in f:
@@ -338,10 +321,8 @@ class VPPEnumType(object):
             e_hash[ename] = evalue
         self.enum = IntFlag(name, e_hash)
         types[name] = self
-
-    def __call__(self, args):
-        self.options = args
-        return self
+        class_types[name] = VPPEnumType
+        self.options = options
 
     def __getattr__(self, name):
         return self.enum[name]
@@ -353,6 +334,12 @@ class VPPEnumType(object):
         __nonzero__ = __bool__
 
     def pack(self, data, kwargs=None):
+        if data is None:  # Default to zero if not specified
+            if self.options and 'default' in self.options:
+                data = self.options['default']
+            else:
+                data = 0
+
         return types[self.enumtype].pack(data)
 
     def unpack(self, data, offset=0, result=None, ntc=False):
@@ -386,10 +373,6 @@ class VPPUnionType(object):
         types[name] = self
         self.tuple = collections.namedtuple(name, fields, rename=True)
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     # Union of variable length?
     def pack(self, data, kwargs=None):
         if not data:
@@ -436,10 +419,6 @@ class VPPTypeAlias(object):
         types[name] = self
         self.toplevelconversion = False
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     def pack(self, data, kwargs=None):
         if data and conversion_required(data, self.name):
             try:
@@ -517,7 +496,14 @@ class VPPType(object):
                 p = VLAList(f_name, f_type, f[3], length_index)
                 self.packers.append(p)
             else:
-                p = types[f_type](self.options)
+                # Support default for basetypes and enums
+                if 'default' in self.options:
+                    try:
+                        p = BaseTypes(f_type, 0, self.options)
+                    except KeyError:
+                        p = class_types[f_type](f_name, types[f_type].msgdef, self.options)
+                else:
+                    p = types[f_type]
                 self.packers.append(p)
                 size += p.size
 
@@ -526,10 +512,6 @@ class VPPType(object):
         types[name] = self
         self.toplevelconversion = False
 
-    def __call__(self, args):
-        self.options = args
-        return self
-
     def pack(self, data, kwargs=None):
         if not kwargs:
             kwargs = data