summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/camera-sensor.cpp7
-rw-r--r--test/controls/control_value.cpp80
-rw-r--r--test/geometry.cpp25
-rw-r--r--test/gstreamer/gstreamer_device_provider_test.cpp11
-rw-r--r--test/ipa/libipa/fixedpoint.cpp (renamed from test/ipa/rkisp1/rkisp1-utils.cpp)16
-rw-r--r--test/ipa/libipa/histogram.cpp66
-rw-r--r--test/ipa/libipa/interpolator.cpp54
-rw-r--r--test/ipa/libipa/meson.build19
-rw-r--r--test/ipa/meson.build2
-rw-r--r--test/ipa/rkisp1/meson.build15
-rw-r--r--test/meson.build1
-rw-r--r--test/py/meson.build14
-rwxr-xr-xtest/py/unittests.py2
-rw-r--r--test/serialization/generated_serializer/generated_serializer_test.cpp1
-rw-r--r--test/serialization/generated_serializer/include/libcamera/ipa/meson.build9
-rw-r--r--test/serialization/ipa_data_serializer_test.cpp2
-rw-r--r--test/span.cpp6
-rw-r--r--test/threads.cpp48
-rw-r--r--test/v4l2_videodevice/v4l2_videodevice_test.cpp5
-rw-r--r--test/v4l2_videodevice/v4l2_videodevice_test.h2
-rw-r--r--test/vector.cpp100
-rw-r--r--test/yaml-parser.cpp52
22 files changed, 476 insertions, 61 deletions
diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp
index 1d402c43..869c7889 100644
--- a/test/camera-sensor.cpp
+++ b/test/camera-sensor.cpp
@@ -52,8 +52,8 @@ protected:
return TestFail;
}
- sensor_ = new CameraSensor(entity);
- if (sensor_->init() < 0) {
+ sensor_ = CameraSensorFactoryBase::create(entity);
+ if (!sensor_) {
cerr << "Unable to initialise camera sensor" << endl;
return TestFail;
}
@@ -118,13 +118,12 @@ protected:
void cleanup()
{
- delete sensor_;
}
private:
std::unique_ptr<DeviceEnumerator> enumerator_;
std::shared_ptr<MediaDevice> media_;
- CameraSensor *sensor_;
+ std::unique_ptr<CameraSensor> sensor_;
CameraLens *lens_;
};
diff --git a/test/controls/control_value.cpp b/test/controls/control_value.cpp
index 344107fa..5084fd0c 100644
--- a/test/controls/control_value.cpp
+++ b/test/controls/control_value.cpp
@@ -110,6 +110,86 @@ protected:
}
/*
+ * Unsigned Integer16 type.
+ */
+ value.set(static_cast<uint16_t>(42));
+ if (value.isNone() || value.isArray() ||
+ value.type() != ControlTypeUnsigned16) {
+ cerr << "Control type mismatch after setting to uint16_t" << endl;
+ return TestFail;
+ }
+
+ if (value.get<uint16_t>() != 42) {
+ cerr << "Control value mismatch after setting to uint16_t" << endl;
+ return TestFail;
+ }
+
+ if (value.toString() != "42") {
+ cerr << "Control string mismatch after setting to uint16_t" << endl;
+ return TestFail;
+ }
+
+ std::array<uint16_t, 4> uint16s{ 3, 14, 15, 9 };
+ value.set(Span<uint16_t>(uint16s));
+ if (value.isNone() || !value.isArray() ||
+ value.type() != ControlTypeUnsigned16) {
+ cerr << "Control type mismatch after setting to uint16_t array" << endl;
+ return TestFail;
+ }
+
+ Span<const uint16_t> uint16sResult = value.get<Span<const uint16_t>>();
+ if (uint16s.size() != uint16sResult.size() ||
+ !std::equal(uint16s.begin(), uint16s.end(), uint16sResult.begin())) {
+ cerr << "Control value mismatch after setting to uint16_t array" << endl;
+ return TestFail;
+ }
+
+ if (value.toString() != "[ 3, 14, 15, 9 ]") {
+ cerr << "Control string mismatch after setting to uint16_t array" << endl;
+ return TestFail;
+ }
+
+ /*
+ * Unsigned Integer32 type.
+ */
+ value.set(static_cast<uint32_t>(42));
+ if (value.isNone() || value.isArray() ||
+ value.type() != ControlTypeUnsigned32) {
+ cerr << "Control type mismatch after setting to uint32_t" << endl;
+ return TestFail;
+ }
+
+ if (value.get<uint32_t>() != 42) {
+ cerr << "Control value mismatch after setting to uint32_t" << endl;
+ return TestFail;
+ }
+
+ if (value.toString() != "42") {
+ cerr << "Control string mismatch after setting to uint32_t" << endl;
+ return TestFail;
+ }
+
+ std::array<uint32_t, 4> uint32s{ 3, 14, 15, 9 };
+ value.set(Span<uint32_t>(uint32s));
+ if (value.isNone() || !value.isArray() ||
+ value.type() != ControlTypeUnsigned32) {
+ cerr << "Control type mismatch after setting to uint32_t array" << endl;
+ return TestFail;
+ }
+
+ Span<const uint32_t> uint32sResult = value.get<Span<const uint32_t>>();
+ if (uint32s.size() != uint32sResult.size() ||
+ !std::equal(uint32s.begin(), uint32s.end(), uint32sResult.begin())) {
+ cerr << "Control value mismatch after setting to uint32_t array" << endl;
+ return TestFail;
+ }
+
+ if (value.toString() != "[ 3, 14, 15, 9 ]") {
+ cerr << "Control string mismatch after setting to uint32_t array" << endl;
+ return TestFail;
+ }
+
+ /*
* Integer32 type.
*/
value.set(0x42000000);
diff --git a/test/geometry.cpp b/test/geometry.cpp
index 64169206..11df043b 100644
--- a/test/geometry.cpp
+++ b/test/geometry.cpp
@@ -481,6 +481,31 @@ protected:
return TestFail;
}
+ Point topLeft(3, 3);
+ Point bottomRight(30, 30);
+ Point topRight(30, 3);
+ Point bottomLeft(3, 30);
+ Rectangle rect1(topLeft, bottomRight);
+ Rectangle rect2(topRight, bottomLeft);
+ Rectangle rect3(bottomRight, topLeft);
+ Rectangle rect4(bottomLeft, topRight);
+
+ if (rect1 != rect2 || rect1 != rect3 || rect1 != rect4) {
+ cout << "Point-to-point construction failed" << endl;
+ return TestFail;
+ }
+
+ Rectangle f1 = Rectangle(100, 200, 3000, 2000);
+ Rectangle f2 = Rectangle(200, 300, 1500, 1000);
+ /* Bottom right quarter of the corresponding frames. */
+ Rectangle r1 = Rectangle(100 + 1500, 200 + 1000, 1500, 1000);
+ Rectangle r2 = Rectangle(200 + 750, 300 + 500, 750, 500);
+ if (r1.transformedBetween(f1, f2) != r2 ||
+ r2.transformedBetween(f2, f1) != r1) {
+ cout << "Rectangle::transformedBetween() test failed" << endl;
+ return TestFail;
+ }
+
return TestPass;
}
};
diff --git a/test/gstreamer/gstreamer_device_provider_test.cpp b/test/gstreamer/gstreamer_device_provider_test.cpp
index 8b8e7cba..521c60b8 100644
--- a/test/gstreamer/gstreamer_device_provider_test.cpp
+++ b/test/gstreamer/gstreamer_device_provider_test.cpp
@@ -52,19 +52,12 @@ protected:
for (l = devices; l != NULL; l = g_list_next(l)) {
GstDevice *device = GST_DEVICE(l->data);
g_autofree gchar *gst_name;
- bool matched = false;
g_autoptr(GstElement) element = gst_device_create_element(device, NULL);
g_object_get(element, "camera-name", &gst_name, NULL);
- for (auto name : cameraNames) {
- if (strcmp(name.c_str(), gst_name) == 0) {
- matched = true;
- break;
- }
- }
-
- if (!matched)
+ if (std::find(cameraNames.begin(), cameraNames.end(), gst_name) ==
+ cameraNames.end())
return TestFail;
}
diff --git a/test/ipa/rkisp1/rkisp1-utils.cpp b/test/ipa/libipa/fixedpoint.cpp
index b1863894..99eb662d 100644
--- a/test/ipa/rkisp1/rkisp1-utils.cpp
+++ b/test/ipa/libipa/fixedpoint.cpp
@@ -2,7 +2,7 @@
/*
* Copyright (C) 2024, Paul Elder <paul.elder@ideasonboard.com>
*
- * Miscellaneous utility tests
+ * Fixed / Floating point utility tests
*/
#include <cmath>
@@ -10,22 +10,22 @@
#include <map>
#include <stdint.h>
-#include "../src/ipa/rkisp1/utils.h"
+#include "../src/ipa/libipa/fixedpoint.h"
#include "test.h"
using namespace std;
using namespace libcamera;
-using namespace ipa::rkisp1;
+using namespace ipa;
-class RkISP1UtilsTest : public Test
+class FixedPointUtilsTest : public Test
{
protected:
/* R for real, I for integer */
template<unsigned int IntPrec, unsigned int FracPrec, typename I, typename R>
int testFixedToFloat(I input, R expected)
{
- R out = utils::fixedToFloatingPoint<IntPrec, FracPrec, R>(input);
+ R out = fixedToFloatingPoint<IntPrec, FracPrec, R>(input);
R prec = 1.0 / (1 << FracPrec);
if (std::abs(out - expected) > prec) {
cerr << "Reverse conversion expected " << input
@@ -40,7 +40,7 @@ protected:
template<unsigned int IntPrec, unsigned int FracPrec, typename T>
int testSingleFixedPoint(double input, T expected)
{
- T ret = utils::floatingToFixedPoint<IntPrec, FracPrec, T>(input);
+ T ret = floatingToFixedPoint<IntPrec, FracPrec, T>(input);
if (ret != expected) {
cerr << "Expected " << input << " to convert to "
<< expected << ", got " << ret << std::endl;
@@ -51,7 +51,7 @@ protected:
* The precision check is fairly arbitrary but is based on what
* the rkisp1 is capable of in the crosstalk module.
*/
- double f = utils::fixedToFloatingPoint<IntPrec, FracPrec, double>(ret);
+ double f = fixedToFloatingPoint<IntPrec, FracPrec, double>(ret);
if (std::abs(f - input) > 0.005) {
cerr << "Reverse conversion expected " << ret
<< " to convert to " << input
@@ -105,4 +105,4 @@ protected:
}
};
-TEST_REGISTER(RkISP1UtilsTest)
+TEST_REGISTER(FixedPointUtilsTest)
diff --git a/test/ipa/libipa/histogram.cpp b/test/ipa/libipa/histogram.cpp
new file mode 100644
index 00000000..77ff31a6
--- /dev/null
+++ b/test/ipa/libipa/histogram.cpp
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024, Ideas on Board Oy
+ *
+ * Histogram tests
+ */
+
+#include "../src/ipa/libipa/histogram.h"
+
+#include <cmath>
+#include <iostream>
+#include <map>
+#include <stdint.h>
+
+#include "test.h"
+
+using namespace std;
+using namespace libcamera;
+using namespace ipa;
+
+#define ASSERT_EQ(a, b) \
+ if (!((a) == (b))) { \
+ std::cout << #a " != " #b << std::endl; \
+ return TestFail; \
+ }
+
+class HistogramTest : public Test
+{
+protected:
+ int run()
+ {
+ auto hist = Histogram({ { 50, 50 } });
+
+ ASSERT_EQ(hist.bins(), 2);
+ ASSERT_EQ(hist.total(), 100);
+
+ ASSERT_EQ(hist.cumulativeFrequency(1.0), 50);
+ ASSERT_EQ(hist.cumulativeFrequency(1.5), 75);
+ ASSERT_EQ(hist.cumulativeFrequency(2.0), 100);
+
+ ASSERT_EQ(hist.quantile(0.0), 0.0);
+ ASSERT_EQ(hist.quantile(1.0), 2.0);
+ ASSERT_EQ(hist.quantile(0.5), 1.0);
+
+ /* Test quantile in the middle of a bin. */
+ ASSERT_EQ(hist.quantile(0.75), 1.5);
+
+ /* Test quantile smaller than the smallest histogram step. */
+ ASSERT_EQ(hist.quantile(0.001), 0.002);
+
+ ASSERT_EQ(hist.interQuantileMean(0.0, 1.0), 1.0);
+ ASSERT_EQ(hist.interQuantileMean(0.0, 0.5), 0.5);
+ ASSERT_EQ(hist.interQuantileMean(0.5, 1.0), 1.5);
+
+ /* Test interquantile mean that starts and ends in the middle of a bin. */
+ ASSERT_EQ(hist.interQuantileMean(0.25, 0.75), 1.0);
+
+ /* Test small ranges at the borders of the histogram. */
+ ASSERT_EQ(hist.interQuantileMean(0.0, 0.1), 0.1);
+ ASSERT_EQ(hist.interQuantileMean(0.9, 1.0), 1.9);
+
+ return TestPass;
+ }
+};
+
+TEST_REGISTER(HistogramTest)
diff --git a/test/ipa/libipa/interpolator.cpp b/test/ipa/libipa/interpolator.cpp
new file mode 100644
index 00000000..6abb7760
--- /dev/null
+++ b/test/ipa/libipa/interpolator.cpp
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024, Ideas on Board Oy
+ *
+ * Interpolator tests
+ */
+
+#include "../src/ipa/libipa/interpolator.h"
+
+#include <cmath>
+#include <iostream>
+#include <map>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "test.h"
+
+using namespace std;
+using namespace libcamera;
+using namespace ipa;
+
+#define ASSERT_EQ(a, b) \
+ if ((a) != (b)) { \
+ printf(#a " != " #b "\n"); \
+ return TestFail; \
+ }
+
+class InterpolatorTest : public Test
+{
+protected:
+ int run()
+ {
+ Interpolator<int> interpolator;
+ interpolator.setData({ { 10, 100 }, { 20, 200 }, { 30, 300 } });
+
+ ASSERT_EQ(interpolator.getInterpolated(0), 100);
+ ASSERT_EQ(interpolator.getInterpolated(10), 100);
+ ASSERT_EQ(interpolator.getInterpolated(20), 200);
+ ASSERT_EQ(interpolator.getInterpolated(25), 250);
+ ASSERT_EQ(interpolator.getInterpolated(30), 300);
+ ASSERT_EQ(interpolator.getInterpolated(40), 300);
+
+ interpolator.setQuantization(10);
+ unsigned int q = 0;
+ ASSERT_EQ(interpolator.getInterpolated(25, &q), 300);
+ ASSERT_EQ(q, 30);
+ ASSERT_EQ(interpolator.getInterpolated(24, &q), 200);
+ ASSERT_EQ(q, 20);
+
+ return TestPass;
+ }
+};
+
+TEST_REGISTER(InterpolatorTest)
diff --git a/test/ipa/libipa/meson.build b/test/ipa/libipa/meson.build
new file mode 100644
index 00000000..8c63ebd8
--- /dev/null
+++ b/test/ipa/libipa/meson.build
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: CC0-1.0
+
+libipa_test = [
+ {'name': 'fixedpoint', 'sources': ['fixedpoint.cpp']},
+ {'name': 'histogram', 'sources': ['histogram.cpp']},
+ {'name': 'interpolator', 'sources': ['interpolator.cpp']},
+]
+
+foreach test : libipa_test
+ exe = executable(test['name'], test['sources'],
+ dependencies : [libcamera_private, libipa_dep],
+ implicit_include_directories : false,
+ link_with : [test_libraries],
+ include_directories : [test_includes_internal,
+ '../../../src/ipa/libipa/'])
+
+ test(test['name'], exe, suite : 'ipa',
+ should_fail : test.get('should_fail', false))
+endforeach
diff --git a/test/ipa/meson.build b/test/ipa/meson.build
index e9871aba..ceed15ba 100644
--- a/test/ipa/meson.build
+++ b/test/ipa/meson.build
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: CC0-1.0
-subdir('rkisp1')
+subdir('libipa')
ipa_test = [
{'name': 'ipa_module_test', 'sources': ['ipa_module_test.cpp']},
diff --git a/test/ipa/rkisp1/meson.build b/test/ipa/rkisp1/meson.build
deleted file mode 100644
index 894523da..00000000
--- a/test/ipa/rkisp1/meson.build
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: CC0-1.0
-
-rkisp1_ipa_test = [
- {'name': 'rkisp1-utils', 'sources': ['rkisp1-utils.cpp']},
-]
-
-foreach test : rkisp1_ipa_test
- exe = executable(test['name'], test['sources'],
- dependencies : [libcamera_private, libipa_dep],
- link_with : [test_libraries],
- include_directories : [test_includes_internal,
- '../../../src/ipa/rkisp1/'])
-
- test(test['name'], exe, suite : 'ipa')
-endforeach
diff --git a/test/meson.build b/test/meson.build
index 5ed052ed..40956649 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -73,6 +73,7 @@ internal_tests = [
{'name': 'timer-thread', 'sources': ['timer-thread.cpp']},
{'name': 'unique-fd', 'sources': ['unique-fd.cpp']},
{'name': 'utils', 'sources': ['utils.cpp']},
+ {'name': 'vector', 'sources': ['vector.cpp']},
{'name': 'yaml-parser', 'sources': ['yaml-parser.cpp']},
]
diff --git a/test/py/meson.build b/test/py/meson.build
index 0b679d31..b922e857 100644
--- a/test/py/meson.build
+++ b/test/py/meson.build
@@ -13,15 +13,25 @@ if asan_runtime_missing
subdir_done()
endif
+py_env = environment()
+
pymod = import('python')
py3 = pymod.find_installation('python3')
pypathdir = meson.project_build_root() / 'src' / 'py'
-py_env = ['PYTHONPATH=' + pypathdir]
+py_env.append('PYTHONPATH', pypathdir)
if asan_enabled
+ py_env.append('LD_PRELOAD', asan_runtime)
+
+ # Preload the C++ standard library to work around a bug in ASan when
+ # dynamically loading C++ .so modules.
+ stdlib = run_command(cxx, '-print-file-name=' + cxx_stdlib + '.so',
+ check : true).stdout().strip()
+ py_env.append('LD_PRELOAD', stdlib)
+
# Disable leak detection as the Python interpreter is full of leaks.
- py_env += ['LD_PRELOAD=' + asan_runtime, 'ASAN_OPTIONS=detect_leaks=0']
+ py_env.append('ASAN_OPTIONS', 'detect_leaks=0')
endif
test('pyunittests',
diff --git a/test/py/unittests.py b/test/py/unittests.py
index 1caea98e..8cb850d4 100755
--- a/test/py/unittests.py
+++ b/test/py/unittests.py
@@ -66,7 +66,7 @@ class SimpleTestMethods(BaseTestCase):
libcam.log_set_level('Camera', 'FATAL')
with self.assertRaises(RuntimeError):
cam.acquire()
- libcam.log_set_level('Camera', 'ERROR')
+ libcam.log_set_level('Camera', 'INFO')
cam.release()
diff --git a/test/serialization/generated_serializer/generated_serializer_test.cpp b/test/serialization/generated_serializer/generated_serializer_test.cpp
index 4b11d67f..dd696885 100644
--- a/test/serialization/generated_serializer/generated_serializer_test.cpp
+++ b/test/serialization/generated_serializer/generated_serializer_test.cpp
@@ -6,6 +6,7 @@
*/
#include <algorithm>
+#include <iostream>
#include <tuple>
#include <vector>
diff --git a/test/serialization/generated_serializer/include/libcamera/ipa/meson.build b/test/serialization/generated_serializer/include/libcamera/ipa/meson.build
index 6f8794c1..ae08e9be 100644
--- a/test/serialization/generated_serializer/include/libcamera/ipa/meson.build
+++ b/test/serialization/generated_serializer/include/libcamera/ipa/meson.build
@@ -9,7 +9,8 @@ mojom = custom_target('test_mojom_module',
'--output-root', meson.project_build_root(),
'--input-root', meson.project_source_root(),
'--mojoms', '@INPUT@'
- ])
+ ],
+ env : py_build_env)
# test_ipa_interface.h
generated_test_header = custom_target('test_ipa_interface_h',
@@ -23,7 +24,8 @@ generated_test_header = custom_target('test_ipa_interface_h',
'--libcamera_generate_header',
'--libcamera_output_path=@OUTPUT@',
'./' +'@INPUT@'
- ])
+ ],
+ env : py_build_env)
# test_ipa_serializer.h
generated_test_serializer = custom_target('test_ipa_serializer_h',
@@ -37,4 +39,5 @@ generated_test_serializer = custom_target('test_ipa_serializer_h',
'--libcamera_generate_serializer',
'--libcamera_output_path=@OUTPUT@',
'./' +'@INPUT@'
- ])
+ ],
+ env : py_build_env)
diff --git a/test/serialization/ipa_data_serializer_test.cpp b/test/serialization/ipa_data_serializer_test.cpp
index aea63c73..afea93a6 100644
--- a/test/serialization/ipa_data_serializer_test.cpp
+++ b/test/serialization/ipa_data_serializer_test.cpp
@@ -29,7 +29,7 @@ using namespace std;
using namespace libcamera;
static const ControlInfoMap Controls = ControlInfoMap({
- { &controls::AeEnable, ControlInfo(false, true) },
+ { &controls::DebugMetadataEnable, ControlInfo(false, true) },
{ &controls::ExposureTime, ControlInfo(0, 999999) },
{ &controls::AnalogueGain, ControlInfo(1.0f, 32.0f) },
{ &controls::ColourGains, ControlInfo(0.0f, 32.0f) },
diff --git a/test/span.cpp b/test/span.cpp
index 5452967d..4b9f3279 100644
--- a/test/span.cpp
+++ b/test/span.cpp
@@ -143,9 +143,9 @@ protected:
Span<const int>{ v };
/* Span<float>{ v }; */
- Span<const int>{ v };
- /* Span<int>{ v }; */
- /* Span<const float>{ v }; */
+ Span<const int>{ cv };
+ /* Span<int>{ cv }; */
+ /* Span<const float>{ cv }; */
Span<int> dynamicSpan{ i };
Span<int>{ dynamicSpan };
diff --git a/test/threads.cpp b/test/threads.cpp
index ceb4fa0f..c00d95a4 100644
--- a/test/threads.cpp
+++ b/test/threads.cpp
@@ -9,9 +9,11 @@
#include <iostream>
#include <memory>
#include <pthread.h>
+#include <sched.h>
#include <thread>
#include <time.h>
+#include <libcamera/base/object.h>
#include <libcamera/base/thread.h>
#include "test.h"
@@ -50,14 +52,8 @@ protected:
{
cancelled_ = true;
- /*
- * Cancel the thread and call a guaranteed cancellation point
- * (nanosleep).
- */
pthread_cancel(pthread_self());
-
- struct timespec req{ 0, 100*000*000 };
- nanosleep(&req, nullptr);
+ pthread_testcancel();
cancelled_ = false;
}
@@ -66,6 +62,27 @@ private:
bool &cancelled_;
};
+class CpuSetTester : public Object
+{
+public:
+ CpuSetTester(unsigned int cpuset)
+ : cpuset_(cpuset) {}
+
+ bool testCpuSet()
+ {
+ int ret = sched_getcpu();
+ if (static_cast<int>(cpuset_) != ret) {
+ cout << "Invalid cpuset: " << ret << ", expecting: " << cpuset_ << endl;
+ return false;
+ }
+
+ return true;
+ }
+
+private:
+ const unsigned int cpuset_;
+};
+
class ThreadTest : public Test
{
protected:
@@ -165,6 +182,23 @@ protected:
return TestFail;
}
+ const unsigned int numCpus = std::thread::hardware_concurrency();
+ for (unsigned int i = 0; i < numCpus; ++i) {
+ thread = std::make_unique<Thread>();
+ const std::array<const unsigned int, 1> cpus{ i };
+ thread->setThreadAffinity(cpus);
+ thread->start();
+
+ CpuSetTester tester(i);
+ tester.moveToThread(thread.get());
+
+ if (!tester.invokeMethod(&CpuSetTester::testCpuSet, ConnectionTypeBlocking))
+ return TestFail;
+
+ thread->exit(0);
+ thread->wait();
+ }
+
return TestPass;
}
diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
index 1113cf5b..9fbd24cc 100644
--- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp
+++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp
@@ -64,8 +64,8 @@ int V4L2VideoDeviceTest::init()
format.size.height = 480;
if (driver_ == "vimc") {
- sensor_ = new CameraSensor(media_->getEntityByName("Sensor A"));
- if (sensor_->init())
+ sensor_ = CameraSensorFactoryBase::create(media_->getEntityByName("Sensor A"));
+ if (!sensor_)
return TestFail;
debayer_ = new V4L2Subdevice(media_->getEntityByName("Debayer A"));
@@ -98,6 +98,5 @@ void V4L2VideoDeviceTest::cleanup()
capture_->close();
delete debayer_;
- delete sensor_;
delete capture_;
}
diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.h b/test/v4l2_videodevice/v4l2_videodevice_test.h
index b5871ce6..7c9003ec 100644
--- a/test/v4l2_videodevice/v4l2_videodevice_test.h
+++ b/test/v4l2_videodevice/v4l2_videodevice_test.h
@@ -36,7 +36,7 @@ protected:
std::string entity_;
std::unique_ptr<libcamera::DeviceEnumerator> enumerator_;
std::shared_ptr<libcamera::MediaDevice> media_;
- libcamera::CameraSensor *sensor_;
+ std::unique_ptr<libcamera::CameraSensor> sensor_;
libcamera::V4L2Subdevice *debayer_;
libcamera::V4L2VideoDevice *capture_;
std::vector<std::unique_ptr<libcamera::FrameBuffer>> buffers_;
diff --git a/test/vector.cpp b/test/vector.cpp
new file mode 100644
index 00000000..4fae960d
--- /dev/null
+++ b/test/vector.cpp
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2024, Ideas on Board Oy
+ *
+ * Vector tests
+ */
+
+#include "libcamera/internal/vector.h"
+
+#include <cmath>
+#include <iostream>
+
+#include "test.h"
+
+using namespace libcamera;
+
+#define ASSERT_EQ(a, b) \
+if ((a) != (b)) { \
+ std::cout << #a " != " #b << " (line " << __LINE__ << ")" \
+ << std::endl; \
+ return TestFail; \
+}
+
+class VectorTest : public Test
+{
+protected:
+ int run()
+ {
+ Vector<double, 3> v1{ 0.0 };
+
+ ASSERT_EQ(v1[0], 0.0);
+ ASSERT_EQ(v1[1], 0.0);
+ ASSERT_EQ(v1[2], 0.0);
+
+ ASSERT_EQ(v1.length(), 0.0);
+ ASSERT_EQ(v1.length2(), 0.0);
+
+ Vector<double, 3> v2{{ 1.0, 4.0, 8.0 }};
+
+ ASSERT_EQ(v2[0], 1.0);
+ ASSERT_EQ(v2[1], 4.0);
+ ASSERT_EQ(v2[2], 8.0);
+
+ ASSERT_EQ(v2.x(), 1.0);
+ ASSERT_EQ(v2.y(), 4.0);
+ ASSERT_EQ(v2.z(), 8.0);
+
+ ASSERT_EQ(v2.r(), 1.0);
+ ASSERT_EQ(v2.g(), 4.0);
+ ASSERT_EQ(v2.b(), 8.0);
+
+ ASSERT_EQ(v2.length2(), 81.0);
+ ASSERT_EQ(v2.length(), 9.0);
+ ASSERT_EQ(v2.sum(), 13.0);
+
+ Vector<double, 3> v3{ v2 };
+
+ ASSERT_EQ(v2, v3);
+
+ v3 = Vector<double, 3>{{ 4.0, 4.0, 4.0 }};
+
+ ASSERT_EQ(v2 + v3, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }}));
+ ASSERT_EQ(v2 + 4.0, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }}));
+ ASSERT_EQ(v2 - v3, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }}));
+ ASSERT_EQ(v2 - 4.0, (Vector<double, 3>{{ -3.0, 0.0, 4.0 }}));
+ ASSERT_EQ(v2 * v3, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }}));
+ ASSERT_EQ(v2 * 4.0, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }}));
+ ASSERT_EQ(v2 / v3, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }}));
+ ASSERT_EQ(v2 / 4.0, (Vector<double, 3>{{ 0.25, 1.0, 2.0 }}));
+
+ ASSERT_EQ(v2.min(v3), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }}));
+ ASSERT_EQ(v2.min(4.0), (Vector<double, 3>{{ 1.0, 4.0, 4.0 }}));
+ ASSERT_EQ(v2.max(v3), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }}));
+ ASSERT_EQ(v2.max(4.0), (Vector<double, 3>{{ 4.0, 4.0, 8.0 }}));
+
+ ASSERT_EQ(v2.dot(v3), 52.0);
+
+ v2 += v3;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }}));
+ v2 -= v3;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }}));
+ v2 *= v3;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }}));
+ v2 /= v3;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }}));
+
+ v2 += 4.0;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 5.0, 8.0, 12.0 }}));
+ v2 -= 4.0;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }}));
+ v2 *= 4.0;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 4.0, 16.0, 32.0 }}));
+ v2 /= 4.0;
+ ASSERT_EQ(v2, (Vector<double, 3>{{ 1.0, 4.0, 8.0 }}));
+
+ return TestPass;
+ }
+};
+
+TEST_REGISTER(VectorTest)
diff --git a/test/yaml-parser.cpp b/test/yaml-parser.cpp
index 81c82983..1b22c87b 100644
--- a/test/yaml-parser.cpp
+++ b/test/yaml-parser.cpp
@@ -34,10 +34,12 @@ static const string testYaml =
"list:\n"
" - James\n"
" - Mary\n"
+ " - \n"
"dictionary:\n"
" a: 1\n"
" c: 3\n"
" b: 2\n"
+ " empty:\n"
"level1:\n"
" level2:\n"
" - [1, 2]\n"
@@ -430,9 +432,10 @@ protected:
if (testObjectType(listObj, "list", Type::List) != TestPass)
return TestFail;
- static constexpr std::array<const char *, 2> listValues{
+ static constexpr std::array<const char *, 3> listValues{
"James",
"Mary",
+ "",
};
if (listObj.size() != listValues.size()) {
@@ -465,16 +468,23 @@ protected:
i++;
}
+ /* Ensure that empty objects get parsed as empty strings. */
+ if (!listObj[2].isValue()) {
+ cerr << "Empty object is not a value" << std::endl;
+ return TestFail;
+ }
+
/* Test dictionary object */
auto &dictObj = (*root)["dictionary"];
if (testObjectType(dictObj, "dictionary", Type::Dictionary) != TestPass)
return TestFail;
- static constexpr std::array<std::pair<const char *, int>, 3> dictValues{ {
+ static constexpr std::array<std::pair<const char *, int>, 4> dictValues{ {
{ "a", 1 },
{ "c", 3 },
{ "b", 2 },
+ { "empty", -100 },
} };
size_t dictSize = dictValues.size();
@@ -505,7 +515,7 @@ protected:
return TestFail;
}
- if (elem.get<int32_t>(0) != item.second) {
+ if (elem.get<int32_t>(-100) != item.second) {
std::cerr << "Dictionary element " << i << " has wrong value"
<< std::endl;
return TestFail;
@@ -514,6 +524,42 @@ protected:
i++;
}
+ /* Ensure that empty objects get parsed as empty strings. */
+ if (!dictObj["empty"].isValue()) {
+ cerr << "Empty object is not of type value" << std::endl;
+ return TestFail;
+ }
+
+ /* Ensure that keys without values are added to a dict. */
+ if (!dictObj.contains("empty")) {
+ cerr << "Empty element is missing in dict" << std::endl;
+ return TestFail;
+ }
+
+ /* Test access to nonexistent member. */
+ if (dictObj["nonexistent"].get<std::string>("default") != "default") {
+ cerr << "Accessing nonexistent dict entry fails to return default" << std::endl;
+ return TestFail;
+ }
+
+ /* Test nonexistent object has value type empty. */
+ if (!dictObj["nonexistent"].isEmpty()) {
+ cerr << "Accessing nonexistent object returns non-empty object" << std::endl;
+ return TestFail;
+ }
+
+ /* Test explicit cast to bool on an empty object returns true. */
+ if (!!dictObj["empty"] != true) {
+ cerr << "Casting empty entry to bool returns false" << std::endl;
+ return TestFail;
+ }
+
+ /* Test explicit cast to bool on nonexistent object returns false. */
+ if (!!dictObj["nonexistent"] != false) {
+ cerr << "Casting nonexistent dict entry to bool returns true" << std::endl;
+ return TestFail;
+ }
+
/* Make sure utils::map_keys() works on the adapter. */
(void)utils::map_keys(dictObj.asDict());