summaryrefslogtreecommitdiff
path: root/src/gstreamer
AgeCommit message (Expand)Author
2020-08-25meson: Remove -Wno-unused-parameterLaurent Pinchart
2020-08-25libcamera: Remove void specifier for functions that take no argumentsLaurent Pinchart
2020-08-05libcamera: camera: Rename name() to id()Niklas Söderlund
2020-06-18gst: Replace explicit DRM FourCCs with libcamera formatsLaurent Pinchart
2020-05-13licenses: License all meson files under CC0-1.0Laurent Pinchart
2020-03-18libcamera: framebuffer_allocator: Lift camera restrictions on allocatorLaurent Pinchart
2020-03-18libcamera: PixelFormat: Make constructor explicitLaurent Pinchart
2020-03-18libcamera: Use PixelFormat instead of unsigned int where appropriateNiklas Söderlund
2020-03-07gst: Fix GLib detectionLaurent Pinchart
2020-03-07gst: Turn the top-level plugin file gstlibcamera.c into a C++ fileLaurent Pinchart
2020-03-07gst: libcamerasrc: Prevent src task deadlock on exhausted buffer poolJakub Adam
2020-03-07gst: utils: Factor-out the task resume helperJakub Adam
2020-03-07gst: libcamerasrc: Add a TODO commentNicolas Dufresne
2020-03-07gst: libcamerasrc: Implement timestamp supportNicolas Dufresne
2020-03-07gst: libcamerasrc: Implement initial streamingNicolas Dufresne
2020-03-07gst: pad: Add method to store retrieve pending buffersNicolas Dufresne
2020-03-07gst: Add getters for Stream and FrameBufferNicolas Dufresne
2020-03-07gst: libcamerasrc: Allocate and release buffersNicolas Dufresne
2020-03-07gst: libcamerapad: Allow storing a poolNicolas Dufresne
2020-03-07gst: Add a pool and an allocator implementationNicolas Dufresne
2020-03-07gst: libcamerasrc: Push segment eventNicolas Dufresne
2020-03-07gst: libcamerasrc: Implement minimal caps negotiationNicolas Dufresne
2020-03-07gst: utils: Add StreamConfiguration helpersNicolas Dufresne
2020-03-07gst: libcamerasrc: Send stream start eventNicolas Dufresne
2020-03-07gst: libcamerasrc: Store the srcpad in a vectorNicolas Dufresne
2020-03-07gst: libcamerapad: Add a method to access the roleNicolas Dufresne
2020-03-07gst: libcamerasrc: Add a task for the streaming threadNicolas Dufresne
2020-03-07gst: libcamerasrc: Implement selection and acquisitionNicolas Dufresne
2020-03-07gst: libcamerasrc: Add a debug categoryNicolas Dufresne
2020-03-07gst: libcamerasrc: Add camera-name propertyNicolas Dufresne
2020-03-07gst: libcamerasrc: Allocate and add static padNicolas Dufresne
2020-03-07gst: Add pads to the sourceNicolas Dufresne
2020-03-07gst: utils: Add simple scoped lockers for GMutex and GRectMutexNicolas Dufresne
2020-03-07gst: Add initial device providerNicolas Dufresne
2020-03-07gst: Add utility to convert StreamFormats to GstCapsNicolas Dufresne
2020-03-07Add GStreamer plugin and element skeletonNicolas Dufresne
href='#n309'>309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
/* 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 the
		 * slot twice to ensure all instances are disconnected.
		 */
		signalVoid_.disconnect();

		SlotObject *slotObject = new SlotObject();
		signalVoid_.connect(slotObject, &SlotObject::slot);
		signalVoid_.connect(slotObject, &SlotObject::slot);
		delete slotObject;
		valueStatic_ = 0;
		signalVoid_.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 the
		 * slot twice to ensure all instances are disconnected.
		 */
		signalVoid_.disconnect();

		SlotMulti *slotMulti = new SlotMulti();
		signalVoid_.connect(slotMulti, &SlotMulti::slot);
		signalVoid_.connect(slotMulti, &SlotMulti::slot);
		delete slotMulti;
		valueStatic_ = 0;
		signalVoid_.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<int> signalInt_;
	Signal<int, const std::string &> signalMultiArgs_;

	bool called_;
	int values_[3];
	std::string name_;
};

TEST_REGISTER(SignalTest)