[libcamera-devel,13/21] test: serialization: Add control info serialization test

Message ID 20190924172503.30864-14-jacopo@jmondi.org
State Superseded
Headers show
Series
  • Implement control serialization
Related show

Commit Message

Jacopo Mondi Sept. 24, 2019, 5:24 p.m. UTC
Test the serialization procedure of a ControlInfoMap by manually
unwrapping a serialized data blob containing control info and validate
them against the sensor subdevice reported ones.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 test/serialization/control_info_list.cpp  | 122 ++++++++++++++++++++++
 test/serialization/meson.build            |   1 +
 test/serialization/serialization_test.cpp | 103 ++++++++++++++++++
 test/serialization/serialization_test.h   |  21 ++++
 4 files changed, 247 insertions(+)
 create mode 100644 test/serialization/control_info_list.cpp

Patch

diff --git a/test/serialization/control_info_list.cpp b/test/serialization/control_info_list.cpp
new file mode 100644
index 000000000000..270f84cf7422
--- /dev/null
+++ b/test/serialization/control_info_list.cpp
@@ -0,0 +1,122 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * control_info.cpp - Serialize and de-serialize a list of control info
+ */
+
+#include <iostream>
+
+#include <libcamera/camera.h>
+#include <libcamera/camera_manager.h>
+#include <libcamera/controls.h>
+
+#include "device_enumerator.h"
+#include "media_device.h"
+#include "serializer.h"
+#include "test.h"
+#include "v4l2_subdevice.h"
+
+#include "serialization_test.h"
+
+using namespace std;
+using namespace libcamera;
+
+class ControlInfoListSerializeTest : public SerializationTest
+{
+public:
+	ControlInfoListSerializeTest()
+		: SerializationTest()
+	{
+	}
+
+private:
+	void initValidationMatrix()
+	{
+		const V4L2ControlInfoMap &controls = sensor_->controls();
+
+		unsigned int i = 0;
+		for (const auto &ctrl : controls) {
+			unsigned int v4l2Id = ctrl.first;
+			const V4L2ControlInfo &info = ctrl.second;
+			ControlId id;
+
+			switch (v4l2Id) {
+			case V4L2_CID_BRIGHTNESS:
+				id = Brightness;
+				break;
+			case V4L2_CID_CONTRAST:
+				id = Contrast;
+				break;
+			case V4L2_CID_SATURATION:
+				id = Saturation;
+				break;
+			default:
+				continue;
+			}
+
+			infoValidationMatrix[i][INFO_CTRL_ID] = id;
+			/* \todo Assume all controls have integers values. */
+			infoValidationMatrix[i][INFO_CTRL_MIN] = info.min().getInt();
+			infoValidationMatrix[i][INFO_CTRL_MAX] = info.max().getInt();
+			infoValidationMatrix[i][INFO_CTRL_FLAG] = 0;
+
+			numCtrls_++;
+			i++;
+		}
+	}
+
+	int init()
+	{
+		int ret = SerializationTest::init();
+		if (ret != TestPass)
+			return ret;
+
+		ret = initSubdevice();
+		if (ret < 0)
+			return ret;
+
+		initValidationMatrix();
+
+		return TestPass;
+	}
+
+	int run()
+	{
+		const ControlInfoMap &controls = camera_->controls();
+
+		std::unique_ptr<DataBlob> blob = controls.serialize();
+		if (!blob) {
+			cerr << "Failed to serialize the control info" << endl;
+			return TestFail;
+		}
+
+		int ret = validateInfoBlobSize(blob.get());
+		if (ret != TestPass)
+			return ret;
+
+		/* Validate each serialized info data. */
+		uint8_t *b = blob->data();
+		for (unsigned int i = 0; i < numCtrls_; ++i) {
+			if (!validateInfoBlob(b))
+				return TestFail;
+
+			b += INFO_BLOB_SIZE;
+		}
+
+		/* De-serialize a control info list and re-validate it. */
+		ControlInfoMap newInfoMap;
+		newInfoMap.deserialize(blob->data(), blob->size());
+		for (auto it : newInfoMap) {
+			ControlId id = it.first;
+			ControlInfo &info = it.second;
+
+			if (!validateInfoValue(id, info))
+				return TestFail;
+		}
+
+		return TestPass;
+	}
+};
+
+TEST_REGISTER(ControlInfoListSerializeTest)
diff --git a/test/serialization/meson.build b/test/serialization/meson.build
index 511f05cbbd1f..510bd8c30d38 100644
--- a/test/serialization/meson.build
+++ b/test/serialization/meson.build
@@ -1,5 +1,6 @@ 
 serialization_tests = [
     [ 'control_list',              'control_list.cpp' ],
+    [ 'control_info_list',         'control_info_list.cpp' ],
 ]
 
 foreach t : serialization_tests
diff --git a/test/serialization/serialization_test.cpp b/test/serialization/serialization_test.cpp
index 8db70bb1de02..f0a9427d7b79 100644
--- a/test/serialization/serialization_test.cpp
+++ b/test/serialization/serialization_test.cpp
@@ -187,3 +187,106 @@  bool SerializationTest::validateDataValue(unsigned int id, const DataValue &data
 
 	return true;
 }
+
+int SerializationTest::validateInfoBlobSize(DataBlob *blob)
+{
+	size_t blobSize = blob->size();
+	if (blobSize % Serializer::BLOB_ALIGN_BYTES) {
+		cerr << "Serialized control info has incorrect alignement"
+		     << endl;
+		return TestFail;
+	}
+
+	size_t expectedSize = INFO_BLOB_SIZE * numCtrls_;
+	if (blobSize != expectedSize) {
+		cerr << "Serialized info list has incorrect size: "
+		     << " expected size " << expectedSize
+		     << " got " << blobSize << endl;
+		return TestFail;
+	}
+
+	return TestPass;
+}
+
+bool SerializationTest::validateInfoBlob(uint8_t *info)
+{
+	uint32_t id = *(reinterpret_cast<uint32_t *>(info));
+	uint32_t size = *(reinterpret_cast<uint32_t *>(Serializer::INFO_BLOB_SIZE(info)));
+
+	/* Manually access min and max assuming they're 32-bits integers. */
+	uint32_t min = *(reinterpret_cast<uint32_t *>(info + 16));
+	uint32_t max = *(reinterpret_cast<uint32_t *>(info + 24));
+	bool found = false;
+
+	cout << "Testing serialized info:  " << id << " - "
+	     << size << " - " << min << " - " << max << endl;
+
+	for (unsigned int i = 0; i < numCtrls_; ++i) {
+		if (infoValidationMatrix[i][INFO_CTRL_ID] != id)
+			continue;
+
+		found = true;
+
+		unsigned int *entry = infoValidationMatrix[i];
+		if (entry[INFO_CTRL_FLAG]) {
+			cerr << "The info with id " << id
+			     << " has been serialized twice" << endl;
+			return false;
+		}
+		entry[INFO_CTRL_FLAG] = true;
+
+		if (entry[INFO_CTRL_MIN] != min ||
+		    entry[INFO_CTRL_MAX] != max ||
+		    size != INFO_BLOB_DATA_SIZE) {
+			cerr << "The info with id " << id
+			     << " has been wrongly serialized" << endl;
+			return false;
+		}
+	}
+
+	if (!found) {
+		cerr << "Non-existing info with id " << id << endl;
+		return false;
+	}
+
+	cout << "Serialization of info:  " << id << " = Success."
+	     << endl;
+
+	return true;
+}
+
+bool SerializationTest::validateInfoValue(unsigned int id,
+					  const DataInfo &info)
+{
+	bool found = false;
+	uint32_t min = info.min().getInt();
+	uint32_t max = info.max().getInt();
+
+	cout << "Testing de-serialized info:  " << id
+	     << " - " << min << " - " << max << endl;
+
+	for (unsigned int i = 0; i < numCtrls_; ++i) {
+		if (infoValidationMatrix[i][INFO_CTRL_ID] != id)
+			continue;
+
+		found = true;
+
+		unsigned int *controlValidation = infoValidationMatrix[i];
+		if (controlValidation[INFO_CTRL_MIN] != min ||
+		    controlValidation[INFO_CTRL_MAX] != max) {
+			cerr << "The info with id " << id
+			     << " has been wrongly serialized" << endl;
+			return false;
+		}
+	}
+
+	if (!found) {
+		cerr << "Non-existing info with id " << id << endl;
+		return false;
+	}
+
+	cout << "De-serialization of info:  " << id << " = Success."
+	     << endl;
+
+	return true;
+}
diff --git a/test/serialization/serialization_test.h b/test/serialization/serialization_test.h
index 87dc5a84a505..7085f79ac0a7 100644
--- a/test/serialization/serialization_test.h
+++ b/test/serialization/serialization_test.h
@@ -45,6 +45,23 @@  protected:
 	static constexpr unsigned int VALUE_BLOB_DATA_SIZE	= 8;
 	static constexpr unsigned int VALUE_BLOB_SIZE		= 24;
 
+	/* Info validation matrix */
+	unsigned int infoValidationMatrix[CTRL_MAX][4];
+
+	/* Indices on the info validation matrix fields. */
+	static constexpr unsigned int INFO_CTRL_ID		= 0;
+	static constexpr unsigned int INFO_CTRL_MIN		= 1;
+	static constexpr unsigned int INFO_CTRL_MAX		= 2;
+	static constexpr unsigned int INFO_CTRL_FLAG		= 3;
+
+	/*
+	 * Serialized info sizes.
+	 * \todo Assume a serialized info is 32 bytes in total (header +
+	 * DataInfo), as values are simple integers.
+	 */
+	static constexpr unsigned int INFO_BLOB_DATA_SIZE	= 16;
+	static constexpr unsigned int INFO_BLOB_SIZE		= 32;
+
 	int init();
 	void cleanup();
 
@@ -54,6 +71,10 @@  protected:
 	bool validateValueBlob(uint8_t *dataBlob);
 	bool validateDataValue(unsigned int id, const DataValue &dataValue);
 
+	int validateInfoBlobSize(DataBlob *blob);
+	bool validateInfoBlob(uint8_t *infoBlob);
+	bool validateInfoValue(unsigned int id, const DataInfo &dataInfo);
+
 	std::unique_ptr<DeviceEnumerator> enumerator_;
 	std::shared_ptr<MediaDevice> media_;
 	std::shared_ptr<Camera> camera_;