summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--test/meson.build1
-rw-r--r--test/object-invoke.cpp137
2 files changed, 138 insertions, 0 deletions
diff --git a/test/meson.build b/test/meson.build
index b2f809e6..7c9abc63 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -24,6 +24,7 @@ public_tests = [
internal_tests = [
['camera-sensor', 'camera-sensor.cpp'],
['message', 'message.cpp'],
+ ['object-invoke', 'object-invoke.cpp'],
['signal-threads', 'signal-threads.cpp'],
['threads', 'threads.cpp'],
]
diff --git a/test/object-invoke.cpp b/test/object-invoke.cpp
new file mode 100644
index 00000000..7221930f
--- /dev/null
+++ b/test/object-invoke.cpp
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * object-invoke.cpp - Cross-thread Object method invocation test
+ */
+
+#include <chrono>
+#include <iostream>
+#include <thread>
+
+#include <libcamera/camera_manager.h>
+#include <libcamera/event_dispatcher.h>
+#include <libcamera/object.h>
+
+#include "thread.h"
+#include "test.h"
+
+using namespace std;
+using namespace libcamera;
+
+class InvokedObject : public Object
+{
+public:
+ enum Status {
+ NoCall,
+ InvalidThread,
+ CallReceived,
+ };
+
+ InvokedObject()
+ : status_(NoCall)
+ {
+ }
+
+ Status status() const { return status_; }
+ int value() const { return value_; }
+ void reset()
+ {
+ status_ = NoCall;
+ value_ = 0;
+ }
+
+ void method(int value)
+ {
+ if (Thread::current() != thread())
+ status_ = InvalidThread;
+ else
+ status_ = CallReceived;
+
+ value_ = value;
+ }
+
+private:
+ Status status_;
+ int value_;
+};
+
+class ObjectInvokeTest : public Test
+{
+protected:
+ int run()
+ {
+ EventDispatcher *dispatcher = CameraManager::instance()->eventDispatcher();
+ InvokedObject object;
+
+ /*
+ * Test that method invocation in the same thread goes through
+ * the event dispatcher.
+ */
+ object.invokeMethod(&InvokedObject::method, 42);
+
+ if (object.status() != InvokedObject::NoCall) {
+ cerr << "Method not invoked asynchronously" << endl;
+ return TestFail;
+ }
+
+ dispatcher->processEvents();
+
+ switch (object.status()) {
+ case InvokedObject::NoCall:
+ cout << "Method not invoked for main thread" << endl;
+ return TestFail;
+ case InvokedObject::InvalidThread:
+ cout << "Method invoked in incorrect thread for main thread" << endl;
+ return TestFail;
+ default:
+ break;
+ }
+
+ if (object.value() != 42) {
+ cout << "Method invoked with incorrect value for main thread" << endl;
+ return TestFail;
+ }
+
+ /*
+ * Move the object to a thread and verify that the method is
+ * delivered in the correct thread.
+ */
+ object.reset();
+ object.moveToThread(&thread_);
+
+ thread_.start();
+
+ object.invokeMethod(&InvokedObject::method, 42);
+ this_thread::sleep_for(chrono::milliseconds(100));
+
+ switch (object.status()) {
+ case InvokedObject::NoCall:
+ cout << "Method not invoked for custom thread" << endl;
+ return TestFail;
+ case InvokedObject::InvalidThread:
+ cout << "Method invoked in incorrect thread for custom thread" << endl;
+ return TestFail;
+ default:
+ break;
+ }
+
+ if (object.value() != 42) {
+ cout << "Method invoked with incorrect value for custom thread" << endl;
+ return TestFail;
+ }
+
+ return TestPass;
+ }
+
+ void cleanup()
+ {
+ thread_.exit(0);
+ thread_.wait();
+ }
+
+private:
+ Thread thread_;
+};
+
+TEST_REGISTER(ObjectInvokeTest)