362 lines
8.0 KiB
C++
362 lines
8.0 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (C) 2019, Google Inc.
|
|
*
|
|
* Signal test
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <string.h>
|
|
|
|
#include <libcamera/base/object.h>
|
|
#include <libcamera/base/signal.h>
|
|
|
|
#include "test.h"
|
|
|
|
using namespace std;
|
|
using namespace libcamera;
|
|
|
|
static int valueStatic_ = 0;
|
|
|
|
static void slotStatic(int value)
|
|
{
|
|
valueStatic_ = value;
|
|
}
|
|
|
|
static int slotStaticReturn()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
class SlotObject : public Object
|
|
{
|
|
public:
|
|
void slot()
|
|
{
|
|
valueStatic_ = 1;
|
|
}
|
|
};
|
|
|
|
class BaseClass
|
|
{
|
|
public:
|
|
/*
|
|
* A virtual function is required in the base class, otherwise the
|
|
* compiler will always store Object before BaseClass in memory.
|
|
*/
|
|
virtual ~BaseClass()
|
|
{
|
|
}
|
|
|
|
unsigned int data_[32];
|
|
};
|
|
|
|
class SlotMulti : public BaseClass, public Object
|
|
{
|
|
public:
|
|
void slot()
|
|
{
|
|
valueStatic_ = 1;
|
|
}
|
|
};
|
|
|
|
class SignalTest : public Test
|
|
{
|
|
protected:
|
|
void slotVoid()
|
|
{
|
|
called_ = true;
|
|
}
|
|
|
|
void slotDisconnect()
|
|
{
|
|
called_ = true;
|
|
signalVoid_.disconnect(this, &SignalTest::slotDisconnect);
|
|
}
|
|
|
|
void slotInteger1(int value)
|
|
{
|
|
values_[0] = value;
|
|
}
|
|
|
|
void slotInteger2(int value)
|
|
{
|
|
values_[1] = value;
|
|
}
|
|
|
|
void slotMultiArgs(int value, const std::string &name)
|
|
{
|
|
values_[2] = value;
|
|
name_ = name;
|
|
}
|
|
|
|
int slotReturn()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int init()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int run()
|
|
{
|
|
/* ----------------- Signal -> !Object tests ---------------- */
|
|
|
|
/* Test signal emission and reception. */
|
|
called_ = false;
|
|
signalVoid_.connect(this, &SignalTest::slotVoid);
|
|
signalVoid_.emit();
|
|
|
|
if (!called_) {
|
|
cout << "Signal emission test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/* Test signal with parameters. */
|
|
values_[2] = 0;
|
|
name_.clear();
|
|
signalMultiArgs_.connect(this, &SignalTest::slotMultiArgs);
|
|
signalMultiArgs_.emit(42, "H2G2");
|
|
|
|
if (values_[2] != 42 || name_ != "H2G2") {
|
|
cout << "Signal parameters test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/* Test signal connected to multiple slots. */
|
|
memset(values_, 0, sizeof(values_));
|
|
valueStatic_ = 0;
|
|
signalInt_.connect(this, &SignalTest::slotInteger1);
|
|
signalInt_.connect(this, &SignalTest::slotInteger2);
|
|
signalInt_.connect(&slotStatic);
|
|
signalInt_.emit(42);
|
|
|
|
if (values_[0] != 42 || values_[1] != 42 || values_[2] != 0 ||
|
|
valueStatic_ != 42) {
|
|
cout << "Signal multi slot test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/* Test disconnection of a single slot. */
|
|
memset(values_, 0, sizeof(values_));
|
|
signalInt_.disconnect(this, &SignalTest::slotInteger2);
|
|
signalInt_.emit(42);
|
|
|
|
if (values_[0] != 42 || values_[1] != 0 || values_[2] != 0) {
|
|
cout << "Signal slot disconnection test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/* Test disconnection of a whole object. */
|
|
memset(values_, 0, sizeof(values_));
|
|
signalInt_.disconnect(this);
|
|
signalInt_.emit(42);
|
|
|
|
if (values_[0] != 0 || values_[1] != 0 || values_[2] != 0) {
|
|
cout << "Signal object disconnection test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/* Test disconnection of a whole signal. */
|
|
memset(values_, 0, sizeof(values_));
|
|
signalInt_.connect(this, &SignalTest::slotInteger1);
|
|
signalInt_.connect(this, &SignalTest::slotInteger2);
|
|
signalInt_.disconnect();
|
|
signalInt_.emit(42);
|
|
|
|
if (values_[0] != 0 || values_[1] != 0 || values_[2] != 0) {
|
|
cout << "Signal object disconnection test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/* Test disconnection from slot. */
|
|
signalVoid_.disconnect();
|
|
signalVoid_.connect(this, &SignalTest::slotDisconnect);
|
|
|
|
signalVoid_.emit();
|
|
called_ = false;
|
|
signalVoid_.emit();
|
|
|
|
if (called_) {
|
|
cout << "Signal disconnection from slot test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/*
|
|
* Test connecting to slots that return a value. This targets
|
|
* compilation, there's no need to check runtime results.
|
|
*/
|
|
signalVoid_.connect(slotStaticReturn);
|
|
signalVoid_.connect(this, &SignalTest::slotReturn);
|
|
|
|
/* Test signal connection to a lambda. */
|
|
int value = 0;
|
|
signalInt_.connect(this, [&](int v) { value = v; });
|
|
signalInt_.emit(42);
|
|
|
|
if (value != 42) {
|
|
cout << "Signal connection to lambda failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
signalInt_.disconnect(this);
|
|
signalInt_.emit(0);
|
|
|
|
if (value != 42) {
|
|
cout << "Signal disconnection from lambda failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/* ----------------- Signal -> Object tests ----------------- */
|
|
|
|
/*
|
|
* Test automatic disconnection on object deletion. Connect two
|
|
* signals to ensure all instances are disconnected.
|
|
*/
|
|
signalVoid_.disconnect();
|
|
signalVoid2_.disconnect();
|
|
|
|
SlotObject *slotObject = new SlotObject();
|
|
signalVoid_.connect(slotObject, &SlotObject::slot);
|
|
signalVoid2_.connect(slotObject, &SlotObject::slot);
|
|
delete slotObject;
|
|
valueStatic_ = 0;
|
|
signalVoid_.emit();
|
|
signalVoid2_.emit();
|
|
if (valueStatic_ != 0) {
|
|
cout << "Signal disconnection on object deletion test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/*
|
|
* Test that signal deletion disconnects objects. This shall
|
|
* not generate any valgrind warning.
|
|
*/
|
|
Signal<> *dynamicSignal = new Signal<>();
|
|
slotObject = new SlotObject();
|
|
dynamicSignal->connect(slotObject, &SlotObject::slot);
|
|
delete dynamicSignal;
|
|
delete slotObject;
|
|
|
|
/*
|
|
* Test that signal manual disconnection from Object removes
|
|
* the signal for the object. This shall not generate any
|
|
* valgrind warning.
|
|
*/
|
|
dynamicSignal = new Signal<>();
|
|
slotObject = new SlotObject();
|
|
dynamicSignal->connect(slotObject, &SlotObject::slot);
|
|
dynamicSignal->disconnect(slotObject);
|
|
delete dynamicSignal;
|
|
delete slotObject;
|
|
|
|
/*
|
|
* Test that signal manual disconnection from all slots removes
|
|
* the signal for the object. This shall not generate any
|
|
* valgrind warning.
|
|
*/
|
|
dynamicSignal = new Signal<>();
|
|
slotObject = new SlotObject();
|
|
dynamicSignal->connect(slotObject, &SlotObject::slot);
|
|
dynamicSignal->disconnect();
|
|
delete dynamicSignal;
|
|
delete slotObject;
|
|
|
|
/* Exercise the Object slot code paths. */
|
|
slotObject = new SlotObject();
|
|
signalVoid_.connect(slotObject, &SlotObject::slot);
|
|
valueStatic_ = 0;
|
|
signalVoid_.emit();
|
|
if (valueStatic_ == 0) {
|
|
cout << "Signal delivery for Object test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
delete slotObject;
|
|
|
|
/* Test signal connection to a lambda. */
|
|
slotObject = new SlotObject();
|
|
value = 0;
|
|
signalInt_.connect(slotObject, [&](int v) { value = v; });
|
|
signalInt_.emit(42);
|
|
|
|
if (value != 42) {
|
|
cout << "Signal connection to Object lambda failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
signalInt_.disconnect(slotObject);
|
|
signalInt_.emit(0);
|
|
|
|
if (value != 42) {
|
|
cout << "Signal disconnection from Object lambda failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
delete slotObject;
|
|
|
|
/* --------- Signal -> Object (multiple inheritance) -------- */
|
|
|
|
/*
|
|
* Test automatic disconnection on object deletion. Connect two
|
|
* signals to ensure all instances are disconnected.
|
|
*/
|
|
signalVoid_.disconnect();
|
|
signalVoid2_.disconnect();
|
|
|
|
SlotMulti *slotMulti = new SlotMulti();
|
|
signalVoid_.connect(slotMulti, &SlotMulti::slot);
|
|
signalVoid2_.connect(slotMulti, &SlotMulti::slot);
|
|
delete slotMulti;
|
|
valueStatic_ = 0;
|
|
signalVoid_.emit();
|
|
signalVoid2_.emit();
|
|
if (valueStatic_ != 0) {
|
|
cout << "Signal disconnection on object deletion test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
/*
|
|
* Test that signal deletion disconnects objects. This shall
|
|
* not generate any valgrind warning.
|
|
*/
|
|
dynamicSignal = new Signal<>();
|
|
slotMulti = new SlotMulti();
|
|
dynamicSignal->connect(slotMulti, &SlotMulti::slot);
|
|
delete dynamicSignal;
|
|
delete slotMulti;
|
|
|
|
/* Exercise the Object slot code paths. */
|
|
slotMulti = new SlotMulti();
|
|
signalVoid_.connect(slotMulti, &SlotMulti::slot);
|
|
valueStatic_ = 0;
|
|
signalVoid_.emit();
|
|
if (valueStatic_ == 0) {
|
|
cout << "Signal delivery for Object test failed" << endl;
|
|
return TestFail;
|
|
}
|
|
|
|
delete slotMulti;
|
|
|
|
return TestPass;
|
|
}
|
|
|
|
void cleanup()
|
|
{
|
|
}
|
|
|
|
private:
|
|
Signal<> signalVoid_;
|
|
Signal<> signalVoid2_;
|
|
Signal<int> signalInt_;
|
|
Signal<int, const std::string &> signalMultiArgs_;
|
|
|
|
bool called_;
|
|
int values_[3];
|
|
std::string name_;
|
|
};
|
|
|
|
TEST_REGISTER(SignalTest)
|