mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-14 20:58:09 +00:00
In the c++ api, methods like chdr_packet#set_payload() and chdr_packet#get_payload() are templated over the payload type (payload_t). For methods like set_payload, they are overloaded by the type of an argument, so in pybind we can just explicitly instaniate the template for each payload_t and register it with pybind under the same name. At runtime, pybind looks at the type of the argument and decides which to call. The problem arose with methods like get_payload, which are overloaded by return type. In C++, the compiler can infer the template type by the type of the target at the call site. In python, there is no way for the pybind to determine which variant of get_payload to call, and it would crash. Previously, the workaround for this was to declare get_payload_ctrl, get_payload_mgmt, etc, but this was rather anti-pythonic. This commit utilizes the fact that python methods don't have a constrained return type to resolve this. Now, get_payload will call a python method which looks at the chdr_packet#header#pkt_type field to determine which variant of get_payload to call and returns that type of payload_t. Signed-off-by: Samuel O'Brien <sam.obrien@ni.com>
68 lines
2.4 KiB
Python
68 lines
2.4 KiB
Python
#
|
|
# Copyright 2020 Ettus Research, a National Instruments Brand
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
"""
|
|
Unit test for libpyuhd.chdr (CHDR Parsing API)
|
|
"""
|
|
|
|
import unittest
|
|
from uhd import chdr
|
|
from chdr_resource import hardcoded_packets
|
|
from chdr_resource import rfnoc_packets_data
|
|
from chdr_resource import rfnoc_packets_ctrl_mgmt
|
|
|
|
# unittest doesn't support parameterized tests natively,
|
|
# rather than add another dependency just for testing, we use this
|
|
class parameterize:
|
|
"""Decorate a class with this. It deletes the method named by
|
|
func_name and adds methods for every test case, appending _{name}
|
|
to the name of the function
|
|
"""
|
|
def __init__(self, func_name, names, cases):
|
|
self.func_name = func_name
|
|
self.cases = cases
|
|
self.names = names
|
|
|
|
def __call__(self, cls):
|
|
func = getattr(cls, self.func_name)
|
|
# First remove the function
|
|
delattr(cls, self.func_name)
|
|
for case, name in zip(self.cases, self.names):
|
|
# Add a new test function for every case
|
|
def new_func(self, this_case=case):
|
|
return func(self, *this_case)
|
|
setattr(cls, self.func_name + "_" + name, new_func)
|
|
return cls
|
|
|
|
|
|
@parameterize("test_serialize_deserialize_eq", hardcoded_packets.names, hardcoded_packets.packets)
|
|
class CHDRParseTest(unittest.TestCase):
|
|
""" Test Python-wrapped CHDR Parser classes """
|
|
|
|
def test_parse_no_errors(self):
|
|
"""Parse every packet in the trace we have.
|
|
This test is just looking for errors
|
|
"""
|
|
packets = [packet_data for peer in [
|
|
rfnoc_packets_ctrl_mgmt.peer0,
|
|
rfnoc_packets_ctrl_mgmt.peer1,
|
|
rfnoc_packets_data.peer0,
|
|
rfnoc_packets_data.peer1
|
|
] for packet_data in peer]
|
|
for packet_data in packets:
|
|
_packet = chdr.ChdrPacket.deserialize(
|
|
chdr.ChdrWidth.W64, packet_data)
|
|
|
|
def test_serialize_deserialize_eq(self, packet, data):
|
|
"""This test serializes and then deserializes a few packets to
|
|
make sure that they survive a round trip without changing
|
|
"""
|
|
generated_data = bytes(packet.serialize())
|
|
self.assertEqual(generated_data, data)
|
|
|
|
generated_packet = chdr.ChdrPacket.deserialize(
|
|
chdr.ChdrWidth.W64, data)
|
|
generated_data = bytes(generated_packet.serialize())
|
|
self.assertEqual(generated_data, data)
|