[libcamera-devel] [PATCH v9 1/3] tests: Add IPADataSerializer test
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Tue Mar 2 02:12:32 CET 2021
Hi Paul,
Thank you for the patch.
On Mon, Mar 01, 2021 at 03:52:24PM +0900, Paul Elder wrote:
> Test the IPADataSerializer for controls, vectors, maps, and PODs of
> built-in types.
>
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
>
> ---
> Changes in v9:
> - convert C-style macros to C++ templates
> - simplify (aka remove) the custom map/vector comparators
> - remove dependency on the raspberrypi header, and create our own
> testing ControlInfoMap
> - reduce the size of the string for testing serializing big objects
>
> No change in v8
>
> Changes in v7:
> - remove printing values of vectors/maps
> - simplify map and vector equality check
> - return immediately on the first failure
>
> Changes in v6:
> - no longer need to initialize rpi ControlInfoMap
> - no longer need to pass ControlInfoMap to the ControlList serializer
>
> Changes in v5:
> - use ControlInfoMap serializer instead of const ControlInfoMap
> serializer
>
> Changes in v4:
> - use RPi::controls instead RPi::Controls
>
> Changes in v3:
> - use re-namespaced RPi::Controls
>
> New in v2
> ---
> .../ipa_data_serializer_test.cpp | 440 ++++++++++++++++++
> test/serialization/meson.build | 1 +
> 2 files changed, 441 insertions(+)
> create mode 100644 test/serialization/ipa_data_serializer_test.cpp
>
> diff --git a/test/serialization/ipa_data_serializer_test.cpp b/test/serialization/ipa_data_serializer_test.cpp
> new file mode 100644
> index 00000000..5e9e2bea
> --- /dev/null
> +++ b/test/serialization/ipa_data_serializer_test.cpp
> @@ -0,0 +1,440 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * ipa_data_serializer_test.cpp - Test serializing/deserializing with IPADataSerializer
> + */
> +
> +#include <algorithm>
> +#include <cxxabi.h>
> +#include <fcntl.h>
> +#include <iostream>
> +#include <limits>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <tuple>
> +#include <unistd.h>
> +#include <vector>
> +
> +#include "libcamera/internal/device_enumerator.h"
> +#include "libcamera/internal/ipa_data_serializer.h"
> +#include "libcamera/internal/ipa_manager.h"
> +#include "libcamera/internal/ipa_module.h"
> +#include "libcamera/internal/pipeline_handler.h"
> +#include "libcamera/internal/thread.h"
> +#include "libcamera/internal/timer.h"
> +
> +#include "serialization_test.h"
> +#include "test.h"
> +
> +using namespace std;
> +using namespace libcamera;
> +
> +static const ControlInfoMap Controls = {
> + { &controls::AeEnable, ControlInfo(false, true) },
> + { &controls::ExposureTime, ControlInfo(0, 999999) },
> + { &controls::AnalogueGain, ControlInfo(1.0f, 32.0f) },
> + { &controls::ColourGains, ControlInfo(0.0f, 32.0f) },
> + { &controls::Brightness, ControlInfo(-1.0f, 1.0f) },
> +};
> +
> +namespace libcamera {
> +
> +static bool operator==(const ControlInfoMap &lhs, const ControlInfoMap &rhs)
> +{
> + return SerializationTest::equals(lhs, rhs);
> +}
> +
> +} /* namespace libcamera */
> +
> +template<typename T>
> +int testPodSerdes(T in)
> +{
> + std::vector<uint8_t> buf;
> + std::vector<int32_t> fds;
> +
> + std::tie(buf, fds) = IPADataSerializer<T>::serialize(in);
> + T out = IPADataSerializer<T>::deserialize(buf, fds);
> + if (in == out)
> + return TestPass;
> +
> + char *name = abi::__cxa_demangle(typeid(T).name(), nullptr,
> + nullptr, nullptr);
> + cerr << "Deserialized " << name << " doesn't match original" << endl;
> + free(name);
> + return TestFail;
> +}
> +
> +template<typename T>
> +int testVectorSerdes(const std::vector<T> &in,
> + ControlSerializer *cs = nullptr)
> +{
> + std::vector<uint8_t> buf;
> + std::vector<int32_t> fds;
> +
> + std::tie(buf, fds) = IPADataSerializer<std::vector<T>>::serialize(in, cs);
> + std::vector<T> out = IPADataSerializer<std::vector<T>>::deserialize(buf, fds, cs);
> + if (in == out)
> + return TestPass;
> +
> + char *name = abi::__cxa_demangle(typeid(T).name(), nullptr,
> + nullptr, nullptr);
> + cerr << "Deserialized std::vector<" << name
> + << "> doesn't match original" << endl;
> + free(name);
> + return TestFail;
> +}
> +
> +template<typename K, typename V>
> +int testMapSerdes(const std::map<K, V> &in,
> + ControlSerializer *cs = nullptr)
> +{
> + std::vector<uint8_t> buf;
> + std::vector<int32_t> fds;
> +
> + std::tie(buf, fds) = IPADataSerializer<std::map<K, V>>::serialize(in, cs);
> + std::map<K, V> out = IPADataSerializer<std::map<K, V>>::deserialize(buf, fds, cs);
> + if (in == out)
> + return TestPass;
> +
> + char *nameK = abi::__cxa_demangle(typeid(K).name(), nullptr,
> + nullptr, nullptr);
> + char *nameV = abi::__cxa_demangle(typeid(V).name(), nullptr,
> + nullptr, nullptr);
> + cerr << "Deserialized std::map<" << nameK << ", " << nameV
> + << "> doesn't match original" << endl;
> + free(nameK);
> + free(nameV);
> + return TestFail;
> +}
> +
> +class IPADataSerializerTest : public CameraTest, public Test
> +{
> +public:
> + IPADataSerializerTest()
> + : CameraTest("platform/vimc.0 Sensor B")
> + {
> + }
> +
> +protected:
> + int init() override
> + {
> + return status_;
> + }
> +
> + int run() override
> + {
> + int ret;
> +
> + ret = testControls();
> + if (ret != TestPass)
> + return ret;
> +
> + ret = testVector();
> + if (ret != TestPass)
> + return ret;
> +
> + ret = testMap();
> + if (ret != TestPass)
> + return ret;
> +
> + ret = testPod();
> + if (ret != TestPass)
> + return ret;
> +
> + return TestPass;
> + }
> +
> +private:
> + ControlList generateControlList(const ControlInfoMap &infoMap)
> + {
> + /* Create a control list with three controls. */
> + ControlList list(infoMap);
> +
> + list.set(controls::Brightness, 0.5f);
> + list.set(controls::Contrast, 1.2f);
> + list.set(controls::Saturation, 0.2f);
> +
> + return list;
> + }
> +
> + int testControls()
> + {
> + ControlSerializer cs;
> +
> + const ControlInfoMap &infoMap = camera_->controls();
> + ControlList list = generateControlList(infoMap);
> +
> + std::vector<uint8_t> infoMapBuf;
> + std::tie(infoMapBuf, std::ignore) =
> + IPADataSerializer<ControlInfoMap>::serialize(infoMap, &cs);
> +
> + std::vector<uint8_t> listBuf;
> + std::tie(listBuf, std::ignore) =
> + IPADataSerializer<ControlList>::serialize(list, &cs);
> +
> + const ControlInfoMap infoMapOut =
> + IPADataSerializer<ControlInfoMap>::deserialize(infoMapBuf, &cs);
> +
> + ControlList listOut = IPADataSerializer<ControlList>::deserialize(listBuf, &cs);
> +
> + if (!SerializationTest::equals(infoMap, infoMapOut)) {
> + cerr << "Deserialized map doesn't match original" << endl;
> + return TestFail;
> + }
> +
> + if (!SerializationTest::equals(list, listOut)) {
> + cerr << "Deserialized list doesn't match original" << endl;
> + return TestFail;
> + }
> +
> + return TestPass;
> + }
> +
> + int testVector()
> + {
> + ControlSerializer cs;
> +
> + /*
> + * We don't test FileDescriptor serdes because it dup()s, so we
> + * can't check for equality.
> + */
> + std::vector<uint8_t> vecUint8 = { 1, 2, 3, 4, 5, 6 };
> + std::vector<uint16_t> vecUint16 = { 1, 2, 3, 4, 5, 6 };
> + std::vector<uint32_t> vecUint32 = { 1, 2, 3, 4, 5, 6 };
> + std::vector<uint64_t> vecUint64 = { 1, 2, 3, 4, 5, 6 };
> + std::vector<int8_t> vecInt8 = { 1, 2, 3, -4, 5, -6 };
> + std::vector<int16_t> vecInt16 = { 1, 2, 3, -4, 5, -6 };
> + std::vector<int32_t> vecInt32 = { 1, 2, 3, -4, 5, -6 };
> + std::vector<int64_t> vecInt64 = { 1, 2, 3, -4, 5, -6 };
> + std::vector<float> vecFloat = { 1.1, 2.2, 3.3, -4.4, 5.5, -6.6 };
> + std::vector<double> vecDouble = { 1.1, 2.2, 3.3, -4.4, 5.5, -6.6 };
> + std::vector<bool> vecBool = { true, true, false, false, true, false };
> + std::vector<string> vecString = { "foo", "bar", "baz" };
s/string/std::string/
> + std::vector<ControlInfoMap> vecControlInfoMap = {
> + camera_->controls(),
> + Controls,
> + };
> +
> + std::vector<uint8_t> buf;
> + std::vector<int32_t> fds;
> +
> + if (testVectorSerdes(vecUint8) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecUint16) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecUint32) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecUint64) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecInt8) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecInt16) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecInt32) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecInt64) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecFloat) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecDouble) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecBool) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecString) != TestPass)
> + return TestFail;
> +
> + if (testVectorSerdes(vecControlInfoMap, &cs) != TestPass)
> + return TestFail;
> +
> + return TestPass;
> + }
> +
> + int testMap()
> + {
> + ControlSerializer cs;
> +
> + /*
> + * Realistically, only string and integral keys.
> + * Test simple, complex, and nested compound value.
> + */
> + std::map<uint64_t, string> mapUintStr =
Here and below too (same for vector).
> + { { 101, "foo" }, { 102, "bar" }, { 103, "baz" } };
> + std::map<int64_t, string> mapIntStr =
> + { { 101, "foo" }, { -102, "bar" }, { -103, "baz" } };
> + std::map<string, string> mapStrStr =
> + { { "a", "foo" }, { "b", "bar" }, { "c", "baz" } };
> + std::map<uint64_t, ControlInfoMap> mapUintCIM =
> + { { 201, camera_->controls() }, { 202, Controls } };
> + std::map<int64_t, ControlInfoMap> mapIntCIM =
> + { { 201, camera_->controls() }, { -202, Controls } };
> + std::map<string, ControlInfoMap> mapStrCIM =
> + { { "a", camera_->controls() }, { "b", Controls } };
> + std::map<uint64_t, vector<uint8_t>> mapUintBVec =
> + { { 301, { 1, 2, 3 } }, { 302, { 4, 5, 6 } }, { 303, { 7, 8, 9 } } };
> + std::map<int64_t, vector<uint8_t>> mapIntBVec =
> + { { 301, { 1, 2, 3 } }, { -302, { 4, 5, 6} }, { -303, { 7, 8, 9 } } };
> + std::map<string, vector<uint8_t>> mapStrBVec =
> + { { "a", { 1, 2, 3 } }, { "b", { 4, 5, 6 } }, { "c", { 7, 8, 9 } } };
> +
> + std::vector<uint8_t> buf;
> + std::vector<int32_t> fds;
> +
> + if (testMapSerdes(mapUintStr) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapIntStr) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapStrStr) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapUintCIM, &cs) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapIntCIM, &cs) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapStrCIM, &cs) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapUintBVec) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapIntBVec) != TestPass)
> + return TestFail;
> +
> + if (testMapSerdes(mapStrBVec) != TestPass)
> + return TestFail;
> +
> + return TestPass;
> + }
> +
> + int testPod()
> + {
> + uint32_t u32min = numeric_limits<uint32_t>::min();
std::numeric_limits
> + uint32_t u32max = numeric_limits<uint32_t>::max();
> + uint32_t u32one = 1;
> + int32_t i32min = numeric_limits<int32_t>::min();
> + int32_t i32max = numeric_limits<int32_t>::max();
> + int32_t i32one = 1;
> +
> + uint64_t u64min = numeric_limits<uint64_t>::min();
> + uint64_t u64max = numeric_limits<uint64_t>::max();
> + uint64_t u64one = 1;
> + int64_t i64min = numeric_limits<int64_t>::min();
> + int64_t i64max = numeric_limits<int64_t>::max();
> + int64_t i64one = 1;
> +
> + float flow = numeric_limits<float>::lowest();
> + float fmin = numeric_limits<float>::min();
> + float fmax = numeric_limits<float>::max();
> + float falmostOne = 1 + 1.0e-37;
> + double dlow = numeric_limits<double>::lowest();
> + double dmin = numeric_limits<double>::min();
> + double dmax = numeric_limits<double>::max();
> + double dalmostOne = 1 + 1.0e-307;
> +
> + bool t = true;
> + bool f = false;
> +
> + stringstream ss;
std::
> + for (unsigned int i = 0; i < (1 << 11); i++)
> + ss << "0123456789";
> +
> + string strLong = ss.str();
> + string strEmpty = "";
Here too.
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> +
> + std::vector<uint8_t> buf;
> + std::vector<int32_t> fds;
> +
> + if (testPodSerdes(u32min) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(u32max) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(u32one) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(i32min) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(i32max) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(i32one) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(u64min) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(u64max) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(u64one) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(i64min) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(i64max) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(i64one) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(flow) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(fmin) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(fmax) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(falmostOne) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(dlow) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(dmin) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(dmax) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(dalmostOne) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(t) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(f) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(strLong) != TestPass)
> + return TestFail;
> +
> + if (testPodSerdes(strEmpty) != TestPass)
> + return TestFail;
> +
> + return TestPass;
> + }
> +};
> +
> +TEST_REGISTER(IPADataSerializerTest)
> diff --git a/test/serialization/meson.build b/test/serialization/meson.build
> index 6fc54f6b..a4636337 100644
> --- a/test/serialization/meson.build
> +++ b/test/serialization/meson.build
> @@ -2,6 +2,7 @@
>
> serialization_tests = [
> ['control_serialization', 'control_serialization.cpp'],
> + ['ipa_data_serializer_test', 'ipa_data_serializer_test.cpp'],
> ]
>
> foreach t : serialization_tests
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list