blob: 5c6b304dac0b04574717030af3bb1ac7282eaf3f [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* signal.cpp - 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)