summaryrefslogtreecommitdiff
path: root/test/object-delete.cpp
blob: eabefe935974a19e77dd83bdc277f5aaaeaca250 (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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2020, Google Inc.
 *
 * object.cpp - Object deletion tests
 */

#include <iostream>

#include <libcamera/base/object.h>
#include <libcamera/base/thread.h>

#include "test.h"

using namespace std;
using namespace libcamera;

class TestObject : public Object
{
public:
	TestObject(unsigned int *count)
		: deleteCount_(count)
	{
	}

	~TestObject()
	{
		/* Count the deletions from the correct thread. */
		if (thread() == Thread::current())
			(*deleteCount_)++;
	}

	unsigned int *deleteCount_;
};

class NewThread : public Thread
{
public:
	NewThread(Object *obj)
		: object_(obj)
	{
	}

protected:
	void run()
	{
		object_->deleteLater();
	}

private:
	Object *object_;
};

class ObjectDeleteTest : public Test
{
protected:
	int run()
	{
		/*
		 * Test that deferred deletion is executed from the object's
		 * thread, not the caller's thread.
		 */
		unsigned int count = 0;
		TestObject *obj = new TestObject(&count);

		NewThread thread(obj);
		thread.start();
		thread.wait();

		Thread::current()->dispatchMessages(Message::Type::DeferredDelete);

		if (count != 1) {
			cout << "Failed to dispatch DeferredDelete (" << count << ")" << endl;
			return TestFail;
		}

		/*
		 * Test that multiple calls to deleteLater() delete the object
		 * once only.
		 */
		count = 0;
		obj = new TestObject(&count);
		obj->deleteLater();
		obj->deleteLater();

		Thread::current()->dispatchMessages(Message::Type::DeferredDelete);
		if (count != 1) {
			cout << "Multiple deleteLater() failed (" << count << ")" << endl;
			return TestFail;
		}

		return TestPass;
	}
};

TEST_REGISTER(ObjectDeleteTest)
ass="hl kwc">std::literals::chrono_literals; class UtilsTest : public Test { protected: int testDirname() { static const std::vector<std::string> paths = { "", "///", "/bin", "/usr/bin", "//etc////", "//tmp//d//", "current_file", "./current_file", "./current_dir/", "current_dir/", }; static const std::vector<std::string> expected = { ".", "/", "/", "/usr", "/", "//tmp", ".", ".", ".", ".", }; std::vector<std::string> results; for (const auto &path : paths) results.push_back(utils::dirname(path)); if (results != expected) { cerr << "utils::dirname() tests failed" << endl; cerr << "expected: " << endl; for (const auto &path : expected) cerr << "\t" << path << endl; cerr << "results: " << endl; for (const auto &path : results) cerr << "\t" << path << endl; return TestFail; } return TestPass; } int testEnumerate() { std::vector<unsigned int> integers{ 1, 2, 3, 4, 5 }; unsigned int i = 0; for (auto [index, value] : utils::enumerate(integers)) { if (index != i || value != i + 1) { cerr << "utils::enumerate(<vector>) test failed: i=" << i << ", index=" << index << ", value=" << value << std::endl; return TestFail; } /* Verify that we can modify the value. */ --value; ++i; } if (integers != std::vector<unsigned int>{ 0, 1, 2, 3, 4 }) { cerr << "Failed to modify container in enumerated range loop" << endl; return TestFail; } Span<const unsigned int> span{ integers }; i = 0; for (auto [index, value] : utils::enumerate(span)) { if (index != i || value != i) { cerr << "utils::enumerate(<span>) test failed: i=" << i << ", index=" << index << ", value=" << value << std::endl; return TestFail; } ++i; } const unsigned int array[] = { 0, 2, 4, 6, 8 }; i = 0; for (auto [index, value] : utils::enumerate(array)) { if (index != i || value != i * 2) { cerr << "utils::enumerate(<array>) test failed: i=" << i << ", index=" << index << ", value=" << value << std::endl; return TestFail; } ++i; } return TestPass; } int testDuration() { std::ostringstream os; utils::Duration exposure; double ratio; exposure = 25ms + 25ms; if (exposure.get<std::micro>() != 50000.0) { cerr << "utils::Duration failed to return microsecond count"; return TestFail; } exposure = 1.0s / 4; if (exposure != 250ms) { cerr << "utils::Duration failed scalar divide test"; return TestFail; } exposure = 5000.5us; if (!exposure) { cerr << "utils::Duration failed boolean test"; return TestFail; } os << exposure; if (os.str() != "5000.50us") { cerr << "utils::Duration operator << failed"; return TestFail; } exposure = 100ms; ratio = exposure / 25ms; if (ratio != 4.0) { cerr << "utils::Duration failed ratio test"; return TestFail; } return TestPass; } int run() { /* utils::hex() test. */ std::ostringstream os; std::string ref; os << utils::hex(static_cast<int32_t>(0x42)) << " "; ref += "0x00000042 "; os << utils::hex(static_cast<uint32_t>(0x42)) << " "; ref += "0x00000042 "; os << utils::hex(static_cast<int64_t>(0x42)) << " "; ref += "0x0000000000000042 "; os << utils::hex(static_cast<uint64_t>(0x42)) << " "; ref += "0x0000000000000042 "; os << utils::hex(static_cast<int32_t>(0x42), 4) << " "; ref += "0x0042 "; os << utils::hex(static_cast<uint32_t>(0x42), 1) << " "; ref += "0x42 "; os << utils::hex(static_cast<int64_t>(0x42), 4) << " "; ref += "0x0042 "; os << utils::hex(static_cast<uint64_t>(0x42), 1) << " "; ref += "0x42 "; std::string s = os.str(); if (s != ref) { cerr << "utils::hex() test failed, expected '" << ref << "', got '" << s << "'"; return TestFail; } /* utils::join() and utils::split() test. */ std::vector<std::string> elements = { "/bin", "/usr/bin", "", "", }; std::string path; for (const auto &element : elements) path += (path.empty() ? "" : ":") + element; if (path != utils::join(elements, ":")) { cerr << "utils::join() test failed" << endl; return TestFail; } std::vector<std::string> dirs; for (const auto &dir : utils::split(path, ":")) dirs.push_back(dir); if (dirs != elements) { cerr << "utils::split() test failed" << endl; return TestFail; } /* utils::join() with conversion function test. */ std::vector<Size> sizes = { { 0, 0 }, { 100, 100 } }; s = utils::join(sizes, "/", [](const Size &size) { return size.toString(); }); if (s != "0x0/100x100") { cerr << "utils::join() with conversion test failed" << endl; return TestFail; } /* utils::dirname() tests. */ if (TestPass != testDirname()) return TestFail; /* utils::map_keys() test. */ const std::map<std::string, unsigned int> map{ { "zero", 0 }, { "one", 1 }, { "two", 2 }, }; std::vector<std::string> expectedKeys{ "zero", "one", "two", }; std::sort(expectedKeys.begin(), expectedKeys.end()); const std::vector<std::string> keys = utils::map_keys(map); if (keys != expectedKeys) { cerr << "utils::map_keys() test failed" << endl; return TestFail; } /* utils::alignUp() and utils::alignDown() tests. */ if (utils::alignDown(6, 3) != 6 || utils::alignDown(7, 3) != 6) { cerr << "utils::alignDown test failed" << endl; return TestFail; } if (utils::alignUp(6, 3) != 6 || utils::alignUp(7, 3) != 9) { cerr << "utils::alignUp test failed" << endl; return TestFail; } /* utils::enumerate() test. */ if (testEnumerate() != TestPass) return TestFail; /* utils::Duration test. */ if (testDuration() != TestPass) return TestFail; return TestPass; } }; TEST_REGISTER(UtilsTest)