[{"id":15295,"web_url":"https://patchwork.libcamera.org/comment/15295/","msgid":"<YDQ/zrHyuK2waFP2@pendragon.ideasonboard.com>","date":"2021-02-22T23:35:42","subject":"Re: [libcamera-devel] [PATCH v8 1/4] tests: Add IPADataSerializer\n\ttest","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Paul,\n\nThank you for the patch.\n\nOn Sat, Feb 13, 2021 at 01:23:09PM +0900, Paul Elder wrote:\n> Test the IPADataSerializer for controls, vectors, maps, and PODs of\n> built-in types.\n> \n> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>\n> \n> ---\n> No change in v8\n> \n> Changes in v7:\n> - remove printing values of vectors/maps\n> - simplify map and vector equality check\n> - return immediately on the first failure\n> \n> Changes in v6:\n> - no longer need to initialize rpi ControlInfoMap\n> - no longer need to pass ControlInfoMap to the ControlList serializer\n> \n> Changes in v5:\n> - use ControlInfoMap serializer instead of const ControlInfoMap\n>   serializer\n> \n> Changes in v4:\n> - use RPi::controls instead RPi::Controls\n> \n> Changes in v3:\n> - use re-namespaced RPi::Controls\n> \n> New in v2\n> ---\n>  .../ipa_data_serializer_test.cpp              | 378 ++++++++++++++++++\n>  test/serialization/meson.build                |   1 +\n>  2 files changed, 379 insertions(+)\n>  create mode 100644 test/serialization/ipa_data_serializer_test.cpp\n> \n> diff --git a/test/serialization/ipa_data_serializer_test.cpp b/test/serialization/ipa_data_serializer_test.cpp\n> new file mode 100644\n> index 00000000..024cdf79\n> --- /dev/null\n> +++ b/test/serialization/ipa_data_serializer_test.cpp\n> @@ -0,0 +1,378 @@\n> +/* SPDX-License-Identifier: GPL-2.0-or-later */\n> +/*\n> + * Copyright (C) 2020, Google Inc.\n> + *\n> + * ipa_data_serializer_test.cpp - Test serializing/deserializing with IPADataSerializer\n> + */\n> +\n> +#include <algorithm>\n> +#include <fcntl.h>\n> +#include <iostream>\n> +#include <limits>\n> +#include <string.h>\n> +#include <sys/stat.h>\n> +#include <sys/types.h>\n> +#include <tuple>\n> +#include <unistd.h>\n> +#include <vector>\n> +\n> +#include <libcamera/ipa/raspberrypi.h>\n\nCould we avoid depending on this header ? The only reason we need it is\nfor RPi::Controls, and that will go away. You can create a custom\nControlInfoMap to replace it.\n\n> +\n> +#include \"libcamera/internal/device_enumerator.h\"\n> +#include \"libcamera/internal/ipa_data_serializer.h\"\n> +#include \"libcamera/internal/ipa_manager.h\"\n> +#include \"libcamera/internal/ipa_module.h\"\n> +#include \"libcamera/internal/pipeline_handler.h\"\n> +#include \"libcamera/internal/thread.h\"\n> +#include \"libcamera/internal/timer.h\"\n> +\n> +#include \"serialization_test.h\"\n> +#include \"test.h\"\n> +\n> +using namespace std;\n> +using namespace libcamera;\n> +\n> +template<typename T>\n> +bool isVectorEqual(vector<T> &vecA, vector<T> &vecB)\n> +{\n> +\tif (vecA.size() != vecB.size())\n> +\t\treturn false;\n> +\n> +\tsize_t len = vecA.size();\n> +\tfor (unsigned int i = 0; i < len; i++)\n> +\t\tif (vecA[i] != vecB[i])\n> +\t\t\treturn false;\n> +\n> +\treturn true;\n\nThis can be implemented as\n\n\treturn vecA == vecB;\n\nFurthermore, it's customary, in comparison functions, to name the two\nparameters lhs and rhs.\n\n> +}\n> +\n> +template<>\n> +bool isVectorEqual<ControlInfoMap>(vector<ControlInfoMap> &vecA,\n> +\t\t\t\t   vector<ControlInfoMap> &vecB)\n> +{\n> +\tif (vecA.size() != vecB.size())\n> +\t\treturn false;\n> +\n> +\tsize_t len = vecA.size();\n> +\tfor (unsigned int i = 0; i < len; i++)\n> +\t\tif (!SerializationTest::equals(vecA[i], vecB[i]))\n> +\t\t\treturn false;\n> +\n> +\treturn true;\n> +}\n\nYou could replace those two functions with\n\nnamespace libcamera {\n\nstatic bool operator==(const ControlInfoMap &lhs, const ControlInfoMap &rhs)\n{\n\treturn SerializationTest::equals(lhs, rhs);\n}\n\n} /* namespace libcamera */\n\nand use == below instead of isVectorEqual().\n\n> +\n> +template<typename K, typename V>\n> +bool isMapToCimEqual(map<K, V> &mapA, map<K, V> &mapB)\n> +{\n> +\tif (mapA.size() != mapB.size())\n> +\t\treturn false;\n> +\n> +\tfor (const auto &itA : mapA) {\n> +\t\tauto itB = mapB.find(itA.first);\n> +\n> +\t\tif (itB == mapB.end())\n> +\t\t\treturn false;\n> +\n> +\t\tif (!SerializationTest::equals(itA.second, itB->second))\n> +\t\t\treturn false;\n> +\t}\n> +\n> +\treturn true;\n> +}\n\nAnd you can then drop this function too, and use == as well. Isn't C++\namazing ? ;-)\n\n> +\n> +class IPADataSerializerTest : public CameraTest, public Test\n> +{\n> +public:\n> +\tIPADataSerializerTest()\n> +\t\t: CameraTest(\"platform/vimc.0 Sensor B\")\n> +\t{\n> +\t}\n> +\n> +protected:\n> +\tint init() override\n> +\t{\n> +\t\treturn status_;\n> +\t}\n> +\n> +\tint run() override\n> +\t{\n> +\t\tint ret;\n> +\n> +\t\tret = testControls();\n> +\t\tif (ret != TestPass)\n> +\t\t\treturn ret;\n> +\n> +\t\tret = testVector();\n> +\t\tif (ret != TestPass)\n> +\t\t\treturn ret;\n> +\n> +\t\tret = testMap();\n> +\t\tif (ret != TestPass)\n> +\t\t\treturn ret;\n> +\n> +\t\tret = testPod();\n> +\t\tif (ret != TestPass)\n> +\t\t\treturn ret;\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +private:\n> +\tControlList generateControlList(const ControlInfoMap &infoMap)\n> +\t{\n> +\t\t/* Create a control list with three controls. */\n> +\t\tControlList list(infoMap);\n> +\n> +\t\tlist.set(controls::Brightness, 0.5f);\n> +\t\tlist.set(controls::Contrast, 1.2f);\n> +\t\tlist.set(controls::Saturation, 0.2f);\n> +\n> +\t\treturn list;\n> +\t}\n> +\n> +\tint testControls()\n> +\t{\n> +\t\tControlSerializer cs;\n> +\n> +\t\tconst ControlInfoMap &infoMap = camera_->controls();\n> +\t\tControlList list = generateControlList(infoMap);\n> +\n> +\t\tvector<uint8_t> infoMapBuf;\n> +\t\ttie(infoMapBuf, ignore) =\n> +\t\t\tIPADataSerializer<ControlInfoMap>::serialize(infoMap, &cs);\n\nWe've used the std:: namespace prefix explicitly in tests for anything\nother than cout, cerr and endl. That's mostly historical, and the plan\nis to drop usage for iostream for a more approriate test result\nreporting infrastructure. At that point I'd like to drop the using\nnamespace std. Could we already qualify members of the std namespace\nother than cout, cerr and endl explicitly ?\n\n> +\n> +\t\tvector<uint8_t> listBuf;\n> +\t\ttie(listBuf, ignore) =\n> +\t\t\tIPADataSerializer<ControlList>::serialize(list, &cs);\n> +\n> +\t\tconst ControlInfoMap infoMapOut =\n> +\t\t\tIPADataSerializer<ControlInfoMap>::deserialize(infoMapBuf, &cs);\n> +\n> +\t\tControlList listOut = IPADataSerializer<ControlList>::deserialize(listBuf, &cs);\n> +\n> +\t\tif (!SerializationTest::equals(infoMap, infoMapOut)) {\n> +\t\t\tcerr << \"Deserialized map doesn't match original\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\tif (!SerializationTest::equals(list, listOut)) {\n> +\t\t\tcerr << \"Deserialized list doesn't match original\" << endl;\n> +\t\t\treturn TestFail;\n> +\t\t}\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tint testVector()\n> +\t{\n> +\n> +#define TEST_VEC_SERDES(type, vec, cs)\t\t\t\t\t\\\n> +tie(buf, fds) = IPADataSerializer<vector<type>>::serialize(vec, cs);\t\\\n> +vector<type> vec##Out =\t\t\t\t\t\t\t\\\n> +\tIPADataSerializer<vector<type>>::deserialize(buf, fds, cs);\t\\\n> +ret = isVectorEqual<type>(vec, vec##Out);\t\t\t\t\\\n> +if (!ret) {\t\t\t\t\t\t\t\t\\\n> +\tcerr << \"Deserialized vector \" << #vec << \" doesn't match original\" << endl;\\\n> +\treturn TestFail;\t\t\t\t\t\t\\\n> +}\n\nThis is sooooo plain C :-) Here's the C++ way:\n\n#include <cxxabi.h>\n#include <stdlib.h>\n\n\ttemplate<typename T>\n\tint testVectorSerdes(const std::vector<T> &in,\n\t\t\t     ControlSerializer *cs = nullptr)\n\t{\n\t\tstd::vector<uint8_t> buf;\n\t\tstd::vector<int32_t> fds;\n\n\t\tstd::tie(buf, fds) = IPADataSerializer<std::vector<T>>::serialize(in, cs);\n\t\tstd::vector<T> out = IPADataSerializer<std::vector<T>>::deserialize(buf, fds, cs);\n\t\tif (in == out)\n\t\t\treturn TestPass;\n\n\t\tchar *name = abi::__cxa_demangle(typeid(T).name(), nullptr,\n\t\t\t\t\t\t nullptr, nullptr);\n\t\tcerr << \"Deserialized std::vector<\" << name\n\t\t     << \"> doesn't match original\" << endl;\n\t\tfree(name);\n\t\treturn TestFail;\n\t}\n\nGranted, print the name of T as a string is more complicated than with a\nmacro.\n\n> +\n> +\t\tControlSerializer cs;\n> +\n> +\t\t/*\n> +\t\t * We don't test FileDescriptor serdes because it dup()s, so we\n> +\t\t * can't check for equality.\n> +\t\t */\n> +\t\tvector<uint8_t>  vecUint8  = { 1, 2, 3, 4, 5, 6 };\n> +\t\tvector<uint16_t> vecUint16 = { 1, 2, 3, 4, 5, 6 };\n> +\t\tvector<uint32_t> vecUint32 = { 1, 2, 3, 4, 5, 6 };\n> +\t\tvector<uint64_t> vecUint64 = { 1, 2, 3, 4, 5, 6 };\n> +\t\tvector<int8_t>   vecInt8   = { 1, 2, 3, -4, 5, -6 };\n> +\t\tvector<int16_t>  vecInt16  = { 1, 2, 3, -4, 5, -6 };\n> +\t\tvector<int32_t>  vecInt32  = { 1, 2, 3, -4, 5, -6 };\n> +\t\tvector<int64_t>  vecInt64  = { 1, 2, 3, -4, 5, -6 };\n> +\t\tvector<float>    vecFloat  = { 1.1, 2.2, 3.3, -4.4, 5.5, -6.6 };\n> +\t\tvector<double>   vecDouble = { 1.1, 2.2, 3.3, -4.4, 5.5, -6.6 };\n> +\t\tvector<bool>     vecBool   = { true, true, false, false, true, false };\n> +\t\tvector<string>   vecString = { \"foo\", \"bar\", \"baz\" };\n> +\t\tvector<ControlInfoMap> vecControlInfoMap = {\n> +\t\t\tcamera_->controls(),\n> +\t\t\tRPi::Controls,\n> +\t\t};\n> +\n> +\t\tvector<uint8_t> buf;\n> +\t\tvector<int32_t> fds;\n> +\t\tint ret;\n> +\n> +\t\tTEST_VEC_SERDES(uint8_t,  vecUint8,  nullptr);\n> +\t\tTEST_VEC_SERDES(uint16_t, vecUint16, nullptr);\n> +\t\tTEST_VEC_SERDES(uint32_t, vecUint32, nullptr);\n> +\t\tTEST_VEC_SERDES(uint64_t, vecUint64, nullptr);\n> +\t\tTEST_VEC_SERDES(int8_t,   vecInt8,   nullptr);\n> +\t\tTEST_VEC_SERDES(int16_t,  vecInt16,  nullptr);\n> +\t\tTEST_VEC_SERDES(int32_t,  vecInt32,  nullptr);\n> +\t\tTEST_VEC_SERDES(int64_t,  vecInt64,  nullptr);\n> +\t\tTEST_VEC_SERDES(float,    vecFloat,  nullptr);\n> +\t\tTEST_VEC_SERDES(double,   vecDouble, nullptr);\n> +\t\tTEST_VEC_SERDES(bool,     vecBool,   nullptr);\n> +\t\tTEST_VEC_SERDES(string,   vecString, nullptr);\n> +\t\tTEST_VEC_SERDES(ControlInfoMap, vecControlInfoMap, &cs);\n\nAnd here\n\n\t\tif (testVectorSerdes(vecUint8) != TestPass)\n\t\t\treturn TestFail;\n\t\t...\n\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tint testMap()\n> +\t{\n> +\n> +#define TEST_MAP_SERDES(ktype, vtype, m, cs)\t\t\t\t\\\n> +tie(buf, fds) = IPADataSerializer<map<ktype, vtype>>::serialize(m, cs);\t\\\n> +map<ktype, vtype> m##Out =\t\t\t\t\t\t\\\n> +\tIPADataSerializer<map<ktype, vtype>>::deserialize(buf, fds, cs);\\\n> +ret = m == m##Out;\t\t\t\t\t\t\t\\\n> +if (!ret) {\t\t\t\t\t\t\t\t\\\n> +\tcerr << \"Deserialized map \" << #m << \" doesn't match original\" << endl;\\\n> +\treturn TestFail;\t\t\t\t\t\t\\\n> +}\n> +\n> +#define TEST_MAP_CIM_SERDES(ktype, vtype, m, cs)\t\t\t\\\n> +tie(buf, fds) = IPADataSerializer<map<ktype, vtype>>::serialize(m, cs);\t\\\n> +map<ktype, vtype> m##Out =\t\t\t\t\t\t\\\n> +\tIPADataSerializer<map<ktype, vtype>>::deserialize(buf, fds, cs);\\\n> +ret = isMapToCimEqual<ktype, vtype>(m, m##Out);\t\t\t\t\\\n> +if (!ret) {\t\t\t\t\t\t\t\t\\\n> +\tcerr << \"Deserialized map \" << #m << \" doesn't match original\" << endl;\\\n> +\treturn TestFail;\t\t\t\t\t\t\\\n> +}\n> +\n> +#define TEST_MAP_VEC_SERDES(ktype, vtype, m, cs)\t\t\t\\\n> +tie(buf, fds) = IPADataSerializer<map<ktype, vtype>>::serialize(m, cs);\t\\\n> +map<ktype, vtype> m##Out =\t\t\t\t\t\t\\\n> +\tIPADataSerializer<map<ktype, vtype>>::deserialize(buf, fds, cs);\\\n> +ret = m == m##Out;\t\t\t\t\t\t\t\\\n> +if (!ret) {\t\t\t\t\t\t\t\t\\\n> +\tcerr << \"Deserialized map \" << #m << \" doesn't match original\" << endl;\\\n> +\treturn TestFail;\t\t\t\t\t\t\\\n> +}\n\nHow to use templates instead of macros here is an exercise left to the\nreader :-) (Note that the second macro is identical to the first one after\nreplacing isMapToCimEqual with operator==, and the third macro is\nalready identical to the first one.)\n\n> +\n> +\t\tControlSerializer cs;\n> +\n> +\t\t/*\n> +\t\t * Realistically, only string and integral keys.\n> +\t\t * Test simple, complex, and nested compound value.\n> +\t\t */\n> +\t\tmap<uint64_t, string> mapUintStr =\n> +\t\t\t{ {101, \"foo\"}, {102, \"bar\"}, {103, \"baz\"} };\n\nOur coding style adds a space within the curly braces (I actually\nwouldn't mind dropping that, to match both the cppreference.com style\nand the Google C++ style, but that's a separate topic).\n\n> +\t\tmap<int64_t, string> mapIntStr =\n> +\t\t\t{ {101, \"foo\"}, {-102, \"bar\"}, {-103, \"baz\"} };\n> +\t\tmap<string, string> mapStrStr =\n> +\t\t\t{ {\"a\", \"foo\"}, {\"b\", \"bar\"}, {\"c\", \"baz\"} };\n> +\t\tmap<uint64_t, ControlInfoMap> mapUintCIM =\n> +\t\t\t{ {201, camera_->controls()}, {202, RPi::Controls} };\n> +\t\tmap<int64_t, ControlInfoMap> mapIntCIM =\n> +\t\t\t{ {201, camera_->controls()}, {-202, RPi::Controls} };\n> +\t\tmap<string, ControlInfoMap> mapStrCIM =\n> +\t\t\t{ {\"a\", camera_->controls()}, {\"b\", RPi::Controls} };\n> +\t\tmap<uint64_t, vector<uint8_t>> mapUintBVec =\n> +\t\t\t{ {301, { 1, 2, 3 }}, {302, {4, 5, 6}}, {303, {7, 8, 9}} };\n> +\t\tmap<int64_t, vector<uint8_t>> mapIntBVec =\n> +\t\t\t{ {301, { 1, 2, 3 }}, {-302, {4, 5, 6}}, {-303, {7, 8, 9}} };\n> +\t\tmap<string, vector<uint8_t>> mapStrBVec =\n> +\t\t\t{ {\"a\", { 1, 2, 3 }}, {\"b\", {4, 5, 6}}, {\"c\", {7, 8, 9}} };\n> +\n> +\t\tvector<uint8_t> buf;\n> +\t\tvector<int32_t> fds;\n> +\t\tint ret;\n> +\n> +\t\tTEST_MAP_SERDES(uint64_t, string,          mapUintStr, nullptr);\n> +\t\tTEST_MAP_SERDES(int64_t,  string,          mapIntStr,  nullptr);\n> +\t\tTEST_MAP_SERDES(string,   string,          mapStrStr,  nullptr);\n> +\t\tTEST_MAP_CIM_SERDES(uint64_t, ControlInfoMap,  mapUintCIM, &cs);\n> +\t\tTEST_MAP_CIM_SERDES(int64_t,  ControlInfoMap,  mapIntCIM,  &cs);\n> +\t\tTEST_MAP_CIM_SERDES(string,   ControlInfoMap,  mapStrCIM,  &cs);\n> +\t\tTEST_MAP_VEC_SERDES(uint64_t, vector<uint8_t>, mapUintBVec, nullptr);\n> +\t\tTEST_MAP_VEC_SERDES(int64_t,  vector<uint8_t>, mapIntBVec,  nullptr);\n> +\t\tTEST_MAP_VEC_SERDES(string,   vector<uint8_t>, mapStrBVec,  nullptr);\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +\n> +\tint testPod()\n> +\t{\n> +\n> +#define TEST_POD_SERDES(type, var)\t\t\t\t\\\n> +tie(buf, fds) = IPADataSerializer<type>::serialize(var);\t\\\n> +type var##Out =\t\t\t\t\t\t\t\\\n> +\tIPADataSerializer<type>::deserialize(buf, fds);\t\t\\\n> +ret = (var == var##Out);\t\t\t\t\t\\\n> +if (!ret) {\t\t\t\t\t\t\t\\\n> +\tcerr << \"Deserialized \" << #var << \" as \" << var##Out\t\\\n> +\t     << \", expected \" << var << endl;\t\t\t\\\n> +\treturn TestFail;\t\t\t\t\t\\\n> +}\n> +\n> +\t\tuint32_t u32min = numeric_limits<uint32_t>::min();\n> +\t\tuint32_t u32max = numeric_limits<uint32_t>::max();\n> +\t\tuint32_t u32one = 1;\n> +\t\tint32_t  i32min = numeric_limits<int32_t>::min();\n> +\t\tint32_t  i32max = numeric_limits<int32_t>::max();\n> +\t\tint32_t  i32one = 1;\n> +\n> +\t\tuint64_t u64min = numeric_limits<uint64_t>::min();\n> +\t\tuint64_t u64max = numeric_limits<uint64_t>::max();\n> +\t\tuint64_t u64one = 1;\n> +\t\tint64_t  i64min = numeric_limits<int64_t>::min();\n> +\t\tint64_t  i64max = numeric_limits<int64_t>::max();\n> +\t\tint64_t  i64one = 1;\n> +\n> +\t\tfloat  flow = numeric_limits<float>::lowest();\n> +\t\tfloat  fmin = numeric_limits<float>::min();\n> +\t\tfloat  fmax = numeric_limits<float>::max();\n> +\t\tfloat  falmostOne = 1 + 1.0e-37;\n> +\t\tdouble dlow = numeric_limits<double>::lowest();\n> +\t\tdouble dmin = numeric_limits<double>::min();\n> +\t\tdouble dmax = numeric_limits<double>::max();\n> +\t\tdouble dalmostOne = 1 + 1.0e-307;\n> +\n> +\t\tbool t = true;\n> +\t\tbool f = false;\n> +\n> +\t\tstringstream ss;\n> +\t\tfor (unsigned int i = 0; i < (1 << 21); i++)\n> +\t\t\tss << \"0123456789\";\n\nWow, that's a very long string, 20MB. Maybe we could keep it a bit\nshorter or reduce the test running time ?\n\n> +\n> +\t\tstring strLong = ss.str();\n> +\t\tstring strEmpty = \"\";\n> +\n> +\t\tvector<uint8_t> buf;\n> +\t\tvector<int32_t> fds;\n> +\t\tint ret;\n> +\n> +\t\tTEST_POD_SERDES(uint32_t, u32min);\n> +\t\tTEST_POD_SERDES(uint32_t, u32max);\n> +\t\tTEST_POD_SERDES(uint32_t, u32one);\n> +\t\tTEST_POD_SERDES(int32_t,  i32min);\n> +\t\tTEST_POD_SERDES(int32_t,  i32max);\n> +\t\tTEST_POD_SERDES(int32_t,  i32one);\n> +\t\tTEST_POD_SERDES(uint64_t, u64min);\n> +\t\tTEST_POD_SERDES(uint64_t, u64max);\n> +\t\tTEST_POD_SERDES(uint64_t, u64one);\n> +\t\tTEST_POD_SERDES(int64_t,  i64min);\n> +\t\tTEST_POD_SERDES(int64_t,  i64max);\n> +\t\tTEST_POD_SERDES(int64_t,  i64one);\n> +\t\tTEST_POD_SERDES(float,    flow);\n> +\t\tTEST_POD_SERDES(float,    fmin);\n> +\t\tTEST_POD_SERDES(float,    fmax);\n> +\t\tTEST_POD_SERDES(float,    falmostOne);\n> +\t\tTEST_POD_SERDES(double,   dlow);\n> +\t\tTEST_POD_SERDES(double,   dmin);\n> +\t\tTEST_POD_SERDES(double,   dmax);\n> +\t\tTEST_POD_SERDES(double,   dalmostOne);\n> +\t\tTEST_POD_SERDES(bool,     t);\n> +\t\tTEST_POD_SERDES(bool,     f);\n> +\t\tTEST_POD_SERDES(string,   strLong);\n> +\t\tTEST_POD_SERDES(string,   strEmpty);\n> +\n> +\t\treturn TestPass;\n> +\t}\n> +};\n> +\n> +TEST_REGISTER(IPADataSerializerTest)\n> diff --git a/test/serialization/meson.build b/test/serialization/meson.build\n> index 6fc54f6b..a4636337 100644\n> --- a/test/serialization/meson.build\n> +++ b/test/serialization/meson.build\n> @@ -2,6 +2,7 @@\n>  \n>  serialization_tests = [\n>      ['control_serialization',     'control_serialization.cpp'],\n> +    ['ipa_data_serializer_test',  'ipa_data_serializer_test.cpp'],\n>  ]\n>  \n>  foreach t : serialization_tests","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 4AD48BD1F1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 22 Feb 2021 23:36:13 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 9AE8568A23;\n\tTue, 23 Feb 2021 00:36:12 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3DC5260106\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 23 Feb 2021 00:36:10 +0100 (CET)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A986F66;\n\tTue, 23 Feb 2021 00:36:09 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"rrl+c7FR\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1614036969;\n\tbh=hhfVBYFJJi/wpnKhGTkCK9Jd2IykBjKErGM8FODxg3c=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=rrl+c7FRM0CizD2SiSypXlISRe7kd6Gi0dIV+7Fonbk0TLDybb5s+PKcI9LnrpCRr\n\tpNWsKjJ0J7NDGeltrTska+5a6RlLSp0rXUAbdNDM47wsk352U6F5kVhp5Zz9Bq6vVO\n\to3tRRNOfWFpqZaaBCjDUabb8C8N5kj/um0RIVfSU=","Date":"Tue, 23 Feb 2021 01:35:42 +0200","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Paul Elder <paul.elder@ideasonboard.com>","Message-ID":"<YDQ/zrHyuK2waFP2@pendragon.ideasonboard.com>","References":"<20210213042312.112572-1-paul.elder@ideasonboard.com>\n\t<20210213042312.112572-2-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<20210213042312.112572-2-paul.elder@ideasonboard.com>","Subject":"Re: [libcamera-devel] [PATCH v8 1/4] tests: Add IPADataSerializer\n\ttest","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]