summaryrefslogtreecommitdiff
path: root/test/object-invoke.cpp
blob: 1ae11bb11e165a684df1b735129993dda0707422 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
</* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * camera_controls.cpp - Camera controls
 */

#include "libcamera/internal/camera_controls.h"

#include <libcamera/camera.h>
#include <libcamera/controls.h>

/**
 * \file camera_controls.h
 * \brief Controls for Camera instances
 */

namespace libcamera {

/**
 * \class CameraControlValidator
 * \brief A control validator for Camera instances
 *
 * This ControlValidator specialisation validates that controls exist in the
 * Camera associated with the validator.
 */

/**
 * \brief Construst a CameraControlValidator for the \a camera
 * \param[in] camera The camera
 */
CameraControlValidator::CameraControlValidator(Camera *camera)
	: camera_(camera)
{
}

const std::string &CameraControlValidator::name() const
{
	return camera_->name();
}

/**
 * \brief Validate a control
 * \param[in] id The control ID
 * \return True if the control is valid, false otherwise
 */
bool CameraControlValidator::validate(unsigned int id) const
{
	const ControlInfoMap &controls = camera_->controls();
	return controls.find(id) != controls.end();
}

} /* namespace libcamera */
7'>187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * object-invoke.cpp - Cross-thread Object method invocation test
 */

#include <iostream>
#include <thread>

#include <libcamera/event_dispatcher.h>
#include <libcamera/object.h>

#include "libcamera/internal/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;
	}

	void methodWithReference(const int &value)
	{
	}

	int methodWithReturn()
	{
		return 42;
	}

private:
	Status status_;
	int value_;
};

class ObjectInvokeTest : public Test
{
protected:
	int run()
	{
		EventDispatcher *dispatcher = Thread::current()->eventDispatcher();

		/*
		 * Test that queued method invocation in the same thread goes
		 * through the event dispatcher.
		 */
		object_.invokeMethod(&InvokedObject::method,
				     ConnectionTypeQueued, 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;
		}

		/*
		 * Test that blocking invocation is delivered directly when the
		 * caller and callee live in the same thread.
		 */
		object_.reset();

		object_.invokeMethod(&InvokedObject::method,
				     ConnectionTypeBlocking, 42);

		switch (object_.status()) {
		case InvokedObject::NoCall:
			cout << "Method not invoked for main thread (blocking)" << endl;
			return TestFail;
		case InvokedObject::InvalidThread:
			cout << "Method invoked in incorrect thread for main thread (blocking)" << endl;
			return TestFail;
		default:
			break;
		}

		/*
		 * Move the object to a thread and verify that auto method
		 * invocation is delivered in the correct thread.
		 */
		object_.reset();
		object_.moveToThread(&thread_);

		thread_.start();

		object_.invokeMethod(&InvokedObject::method,
				     ConnectionTypeBlocking, 42);

		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;
		}

		/* Test that direct method invocation bypasses threads. */
		object_.reset();
		object_.invokeMethod(&InvokedObject::method,
				     ConnectionTypeDirect, 42);

		switch (object_.status()) {
		case InvokedObject::NoCall:
			cout << "Method not invoked for custom thread" << endl;
			return TestFail;
		case InvokedObject::CallReceived:
			cout << "Method invoked in incorrect thread for direct call" << endl;
			return TestFail;
		default:
			break;
		}

		if (object_.value() != 42) {
			cout << "Method invoked with incorrect value for direct call" << endl;
			return TestFail;
		}

		/*
		 * Test invoking a method that takes reference arguments. This
		 * targets compilation, there's no need to check runtime
		 * results.
		 */
		object_.invokeMethod(&InvokedObject::methodWithReference,
				     ConnectionTypeBlocking, 42);

		/* Test invoking a method that returns a value. */
		int ret = object_.invokeMethod(&InvokedObject::methodWithReturn,
					       ConnectionTypeBlocking);
		if (ret != 42) {
			cout << "Method invoked return incorrect value (" << ret
			     << ")" << endl;
			return TestFail;
		}

		return TestPass;
	}

	void cleanup()
	{
		thread_.exit(0);
		thread_.wait();
	}

private:
	Thread thread_;
	InvokedObject object_;
};

TEST_REGISTER(ObjectInvokeTest)