From patchwork Tue Sep 22 13:35:36 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 9741 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 0CD3BBF01C for ; Tue, 22 Sep 2020 13:40:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C93AD62FDC; Tue, 22 Sep 2020 15:40:20 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Rz1Q0J8A"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 10D9562FD6 for ; Tue, 22 Sep 2020 15:40:20 +0200 (CEST) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A7D912D7; Tue, 22 Sep 2020 15:40:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1600782016; bh=m1HuvIkqzCb63g46a3vn5CeLSQW9BALOinXYlpsh7/M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Rz1Q0J8Amq5iG5NwkzE8HYGwEj6ZrbXIXpO2QNK7Gbw6//Tqj4kvstZ6a81m/yaXk Z00WFq02c9W77qEcGn+m2Vd8TuMgvCjczr5znEfIgo4agAwtPoh66f1/Bs4d6GR5yc bgCq/Ue0mRXzZ+s3CGBgmhaWJYSddcZsaU8ffd6U= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Tue, 22 Sep 2020 22:35:36 +0900 Message-Id: <20200922133537.258098-38-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20200922133537.258098-1-paul.elder@ideasonboard.com> References: <20200922133537.258098-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 37/38] tests: Add IPADataSerializer test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Test the IPADataSerializer for controls, vectors, maps, and PODs of built-in types. Signed-off-by: Paul Elder --- New in v2 --- .../ipa_data_serializer_test.cpp | 463 ++++++++++++++++++ test/serialization/meson.build | 3 +- 2 files changed, 465 insertions(+), 1 deletion(-) 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..deeb754a --- /dev/null +++ b/test/serialization/ipa_data_serializer_test.cpp @@ -0,0 +1,463 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * ipa_data_serializer_test.cpp - Test serializing/deserializing with IPADataSerializer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 "serialization_test.h" +#include "test.h" + +using namespace std; +using namespace libcamera; + +template +bool isVectorEqual(vector &vecA, vector &vecB) +{ + if (vecA.size() != vecB.size()) + return false; + + size_t len = vecA.size(); + for (unsigned int i = 0; i < len; i++) + if (vecA[i] != vecB[i]) + goto nequal; + + return true; + +nequal: + cerr << "lhs: { "; + for (const auto &value : vecA) + cerr << value << ", "; + cerr << "}" << endl; + + cerr << "rhs: { "; + for (const auto &value : vecB) + cerr << value << ", "; + cerr << "}" << endl; + + return false; +} + +template<> +bool isVectorEqual(vector &vecA, + vector &vecB) +{ + if (vecA.size() != vecB.size()) + return false; + + size_t len = vecA.size(); + for (unsigned int i = 0; i < len; i++) + if (!SerializationTest::equals(vecA[i], vecB[i])) + return false; + + return true; +} + +template +bool isMapEqual(map &mapA, map &mapB) +{ + if (mapA == mapB) + return true; + + cerr << "lhs: { "; + for (const auto &value : mapA) + cerr << value.first << " : " << value.second << ", "; + cerr << "}" << endl; + + cerr << "rhs: { "; + for (const auto &value : mapB) + cerr << value.first << " : " << value.second << ", "; + cerr << "}" << endl; + + return false; +} + +template +bool isMapToCimEqual(map &mapA, map &mapB) +{ + bool isEqual = true; + + auto itA = mapA.begin(); + auto itB = mapB.begin(); + while (true) { + bool endA = (itA == mapA.end()); + bool endB = (itB == mapB.end()); + + if (endA and endB) + break; + + if (!endA && (endB || itA->first < itB->first)) { + cerr << "key: " << itA->first << " not in mapB" << endl; + isEqual = false; + itA++; + continue; + } + + if (endA || itB->first < itA->first) { + cerr << "key: " << itB->first << " not in mapA" << endl; + isEqual = false; + itB++; + continue; + } + + if (!SerializationTest::equals(itA->second, itB->second)) { + cerr << "key " << itA->first + << " has different values" << endl; + isEqual = false; + } + + itA++; + itB++; + } + + return isEqual; +} + +template +bool isMapToVecEqual(map &mapA, map &mapB) +{ + if (mapA == mapB) + return true; + + cerr << "lhs: { "; + for (const auto &value : mapA) { + cerr << value.first << " : { "; + for (const auto &v : value.second) + cerr << v << ", "; + cerr << "}" << endl; + } + cerr << "}" << endl; + + cerr << "rhs: { "; + for (const auto &value : mapB) { + cerr << value.first << " : { "; + for (const auto &v : value.second) + cerr << v << ", "; + cerr << "}" << endl; + } + cerr << "}" << endl; + + return false; +} + +class IPADataSerializerTest : public CameraTest, public Test +{ +public: + IPADataSerializerTest() + : CameraTest("platform/vimc.0 Sensor B") + { + } + +protected: + int init() override + { + return status_; + } + + int run() override + { + int finalRet = TestPass; + int ret; + + ret = testControls(); + if (ret != TestPass) + finalRet = ret; + + ret = testVector(); + if (ret != TestPass) + finalRet = ret; + + ret = testMap(); + if (ret != TestPass) + finalRet = ret; + + ret = testPod(); + if (ret != TestPass) + finalRet = ret; + + return finalRet; + } + +private: + ControlList generateControlListA() + { + /* Create a control list with three controls. */ + const ControlInfoMap &infoMap = camera_->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 = generateControlListA(); + + vector infoMapBuf; + tie(infoMapBuf, ignore) = IPADataSerializer::serialize(infoMap, &cs); + + vector listBuf; + tie(listBuf, ignore) = IPADataSerializer::serialize(list, *list.infoMap(), &cs); + + + const ControlInfoMap infoMapOut = IPADataSerializer::deserialize(infoMapBuf, &cs); + + ControlList listOut = IPADataSerializer::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() + { + +#define TEST_VEC_SERDES(type, vec, cs) \ +tie(buf, fds) = IPADataSerializer>::serialize(vec, cs); \ +vector vec##Out = \ + IPADataSerializer>::deserialize(buf, fds, cs); \ +ret = isVectorEqual(vec, vec##Out); \ +if (!ret) { \ + cerr << "Deserialized vector " << #vec << " doesn't match original" << endl;\ + finalRet = TestFail; \ +} + + ControlSerializer cs; + + /* + * We don't test FileDescriptor serdes because it dup()s, so we + * can't check for equality. + */ + vector vecUint8 = {1, 2, 3, 4, 5, 6}; + vector vecUint16 = {1, 2, 3, 4, 5, 6}; + vector vecUint32 = {1, 2, 3, 4, 5, 6}; + vector vecUint64 = {1, 2, 3, 4, 5, 6}; + vector vecInt8 = {1, 2, 3, -4, 5, -6}; + vector vecInt16 = {1, 2, 3, -4, 5, -6}; + vector vecInt32 = {1, 2, 3, -4, 5, -6}; + vector vecInt64 = {1, 2, 3, -4, 5, -6}; + vector vecFloat = {1.1, 2.2, 3.3, -4.4, 5.5, -6.6}; + vector vecDouble = {1.1, 2.2, 3.3, -4.4, 5.5, -6.6}; + vector vecBool = {true, true, false, false, true, false}; + vector vecString = {"foo", "bar", "baz"}; + vector vecControlInfoMap = { + camera_->controls(), + RPiControls, + }; + + vector buf; + vector fds; + int finalRet = TestPass; + int ret; + + TEST_VEC_SERDES(uint8_t, vecUint8, nullptr); + TEST_VEC_SERDES(uint16_t, vecUint16, nullptr); + TEST_VEC_SERDES(uint32_t, vecUint32, nullptr); + TEST_VEC_SERDES(uint64_t, vecUint64, nullptr); + TEST_VEC_SERDES(int8_t, vecInt8, nullptr); + TEST_VEC_SERDES(int16_t, vecInt16, nullptr); + TEST_VEC_SERDES(int32_t, vecInt32, nullptr); + TEST_VEC_SERDES(int64_t, vecInt64, nullptr); + TEST_VEC_SERDES(float, vecFloat, nullptr); + TEST_VEC_SERDES(double, vecDouble, nullptr); + TEST_VEC_SERDES(bool, vecBool, nullptr); + TEST_VEC_SERDES(string, vecString, nullptr); + TEST_VEC_SERDES(ControlInfoMap, vecControlInfoMap, &cs); + + return finalRet; + } + + int testMap() + { + +#define TEST_MAP_SERDES(ktype, vtype, m, cs) \ +tie(buf, fds) = IPADataSerializer>::serialize(m, cs); \ +map m##Out = \ + IPADataSerializer>::deserialize(buf, fds, cs);\ +ret = isMapEqual(m, m##Out); \ +if (!ret) { \ + cerr << "Deserialized map " << #m << " doesn't match original" << endl;\ + finalRet = TestFail; \ +} + +#define TEST_MAP_CIM_SERDES(ktype, vtype, m, cs) \ +tie(buf, fds) = IPADataSerializer>::serialize(m, cs); \ +map m##Out = \ + IPADataSerializer>::deserialize(buf, fds, cs);\ +ret = isMapToCimEqual(m, m##Out); \ +if (!ret) { \ + cerr << "Deserialized map " << #m << " doesn't match original" << endl;\ + finalRet = TestFail; \ +} + +#define TEST_MAP_VEC_SERDES(ktype, vtype, m, cs) \ +tie(buf, fds) = IPADataSerializer>::serialize(m, cs); \ +map m##Out = \ + IPADataSerializer>::deserialize(buf, fds, cs);\ +ret = isMapToVecEqual(m, m##Out); \ +if (!ret) { \ + cerr << "Deserialized map " << #m << " doesn't match original" << endl;\ + finalRet = TestFail; \ +} + + ControlSerializer cs; + + /* + * Realistically, only string and integral keys. + * Test simple, complex, and nested compound value. + */ + map mapUintStr = + { {101, "foo"}, {102, "bar"}, {103, "baz"} }; + map mapIntStr = + { {101, "foo"}, {-102, "bar"}, {-103, "baz"} }; + map mapStrStr = + { {"a", "foo"}, {"b", "bar"}, {"c", "baz"} }; + map mapUintCIM = + { {201, camera_->controls()}, {202, RPiControls} }; + map mapIntCIM = + { {201, camera_->controls()}, {-202, RPiControls} }; + map mapStrCIM = + { {"a", camera_->controls()}, {"b", RPiControls} }; + map> mapUintBVec = + { {301, { 1, 2, 3 }}, {302, {4, 5, 6}}, {303, {7, 8, 9}} }; + map> mapIntBVec = + { {301, { 1, 2, 3 }}, {-302, {4, 5, 6}}, {-303, {7, 8, 9}} }; + map> mapStrBVec = + { {"a", { 1, 2, 3 }}, {"b", {4, 5, 6}}, {"c", {7, 8, 9}} }; + + vector buf; + vector fds; + int finalRet = TestPass; + int ret; + + TEST_MAP_SERDES(uint64_t, string, mapUintStr, nullptr); + TEST_MAP_SERDES(int64_t, string, mapIntStr, nullptr); + TEST_MAP_SERDES(string, string, mapStrStr, nullptr); + TEST_MAP_CIM_SERDES(uint64_t, ControlInfoMap, mapUintCIM, &cs); + TEST_MAP_CIM_SERDES(int64_t, ControlInfoMap, mapIntCIM, &cs); + TEST_MAP_CIM_SERDES(string, ControlInfoMap, mapStrCIM, &cs); + TEST_MAP_VEC_SERDES(uint64_t, vector, mapUintBVec, nullptr); + TEST_MAP_VEC_SERDES(int64_t, vector, mapIntBVec, nullptr); + TEST_MAP_VEC_SERDES(string, vector, mapStrBVec, nullptr); + + return finalRet; + } + + int testPod() + { + +#define TEST_POD_SERDES(type, var) \ +tie(buf, fds) = IPADataSerializer::serialize(var); \ +type var##Out = \ + IPADataSerializer::deserialize(buf, fds); \ +ret = (var == var##Out); \ +if (!ret) { \ + cerr << "Deserialized " << #var << " as " << var##Out \ + << ", expected " << var << endl; \ + finalRet = TestFail; \ +} + + uint32_t u32min = numeric_limits::min(); + uint32_t u32max = numeric_limits::max(); + uint32_t u32one = 1; + int32_t i32min = numeric_limits::min(); + int32_t i32max = numeric_limits::max(); + int32_t i32one = 1; + + uint64_t u64min = numeric_limits::min(); + uint64_t u64max = numeric_limits::max(); + uint64_t u64one = 1; + int64_t i64min = numeric_limits::min(); + int64_t i64max = numeric_limits::max(); + int64_t i64one = 1; + + float flow = numeric_limits::lowest(); + float fmin = numeric_limits::min(); + float fmax = numeric_limits::max(); + float falmostOne = 1 + 1.0e-37; + double dlow = numeric_limits::lowest(); + double dmin = numeric_limits::min(); + double dmax = numeric_limits::max(); + double dalmostOne = 1 + 1.0e-307; + + bool t = true; + bool f = false; + + stringstream ss; + for (unsigned int i = 0; i < (1 << 21); i++) + ss << "0123456789"; + + string strLong = ss.str(); + string strEmpty = ""; + + vector buf; + vector fds; + int finalRet = TestPass; + int ret; + + TEST_POD_SERDES(uint32_t, u32min); + TEST_POD_SERDES(uint32_t, u32max); + TEST_POD_SERDES(uint32_t, u32one); + TEST_POD_SERDES(int32_t, i32min); + TEST_POD_SERDES(int32_t, i32max); + TEST_POD_SERDES(int32_t, i32one); + TEST_POD_SERDES(uint64_t, u64min); + TEST_POD_SERDES(uint64_t, u64max); + TEST_POD_SERDES(uint64_t, u64one); + TEST_POD_SERDES(int64_t, i64min); + TEST_POD_SERDES(int64_t, i64max); + TEST_POD_SERDES(int64_t, i64one); + TEST_POD_SERDES(float, flow); + TEST_POD_SERDES(float, fmin); + TEST_POD_SERDES(float, fmax); + TEST_POD_SERDES(float, falmostOne); + TEST_POD_SERDES(double, dlow); + TEST_POD_SERDES(double, dmin); + TEST_POD_SERDES(double, dmax); + TEST_POD_SERDES(double, dalmostOne); + TEST_POD_SERDES(bool, t); + TEST_POD_SERDES(bool, f); + TEST_POD_SERDES(string, strLong); + TEST_POD_SERDES(string, strEmpty); + + return finalRet; + } +}; + +TEST_REGISTER(IPADataSerializerTest) diff --git a/test/serialization/meson.build b/test/serialization/meson.build index a9d9cbcb..c140a31c 100644 --- a/test/serialization/meson.build +++ b/test/serialization/meson.build @@ -1,7 +1,8 @@ # SPDX-License-Identifier: CC0-1.0 serialization_tests = [ - [ 'control_serialization', 'control_serialization.cpp' ], + [ 'control_serialization', 'control_serialization.cpp' ], + [ 'ipa_data_serializer_test', 'ipa_data_serializer_test.cpp' ], ] foreach t : serialization_tests