tests: Add IPADataSerializer test
Test the IPADataSerializer for controls, vectors, maps, and PODs of built-in types. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
cc22d2206d
commit
01fd806b9a
2 changed files with 440 additions and 0 deletions
439
test/serialization/ipa_data_serializer_test.cpp
Normal file
439
test/serialization/ipa_data_serializer_test.cpp
Normal file
|
@ -0,0 +1,439 @@
|
|||
/* 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 <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<std::string> vecString = { "foo", "bar", "baz" };
|
||||
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, std::string> mapUintStr =
|
||||
{ { 101, "foo" }, { 102, "bar" }, { 103, "baz" } };
|
||||
std::map<int64_t, std::string> mapIntStr =
|
||||
{ { 101, "foo" }, { -102, "bar" }, { -103, "baz" } };
|
||||
std::map<std::string, std::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<std::string, ControlInfoMap> mapStrCIM =
|
||||
{ { "a", camera_->controls() }, { "b", Controls } };
|
||||
std::map<uint64_t, std::vector<uint8_t>> mapUintBVec =
|
||||
{ { 301, { 1, 2, 3 } }, { 302, { 4, 5, 6 } }, { 303, { 7, 8, 9 } } };
|
||||
std::map<int64_t, std::vector<uint8_t>> mapIntBVec =
|
||||
{ { 301, { 1, 2, 3 } }, { -302, { 4, 5, 6} }, { -303, { 7, 8, 9 } } };
|
||||
std::map<std::string, std::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 = std::numeric_limits<uint32_t>::min();
|
||||
uint32_t u32max = std::numeric_limits<uint32_t>::max();
|
||||
uint32_t u32one = 1;
|
||||
int32_t i32min = std::numeric_limits<int32_t>::min();
|
||||
int32_t i32max = std::numeric_limits<int32_t>::max();
|
||||
int32_t i32one = 1;
|
||||
|
||||
uint64_t u64min = std::numeric_limits<uint64_t>::min();
|
||||
uint64_t u64max = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t u64one = 1;
|
||||
int64_t i64min = std::numeric_limits<int64_t>::min();
|
||||
int64_t i64max = std::numeric_limits<int64_t>::max();
|
||||
int64_t i64one = 1;
|
||||
|
||||
float flow = std::numeric_limits<float>::lowest();
|
||||
float fmin = std::numeric_limits<float>::min();
|
||||
float fmax = std::numeric_limits<float>::max();
|
||||
float falmostOne = 1 + 1.0e-37;
|
||||
double dlow = std::numeric_limits<double>::lowest();
|
||||
double dmin = std::numeric_limits<double>::min();
|
||||
double dmax = std::numeric_limits<double>::max();
|
||||
double dalmostOne = 1 + 1.0e-307;
|
||||
|
||||
bool t = true;
|
||||
bool f = false;
|
||||
|
||||
std::stringstream ss;
|
||||
for (unsigned int i = 0; i < (1 << 11); i++)
|
||||
ss << "0123456789";
|
||||
|
||||
std::string strLong = ss.str();
|
||||
std::string strEmpty = "";
|
||||
|
||||
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)
|
Loading…
Add table
Add a link
Reference in a new issue