@@ -53,6 +53,7 @@ internal_tests = [
['threads', 'threads.cpp'],
['timer', 'timer.cpp'],
['timer-thread', 'timer-thread.cpp'],
+ ['unique-fd', 'unique-fd.cpp'],
['utils', 'utils.cpp'],
]
new file mode 100644
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * unique-fd.cpp - UniqueFD test
+ */
+
+#include <fcntl.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libcamera/base/unique_fd.h>
+#include <libcamera/base/utils.h>
+
+#include "test.h"
+
+using namespace libcamera;
+using namespace std;
+
+class UniqueFDTest : public Test
+{
+protected:
+ int init() override
+ {
+ return createFd();
+ }
+
+ int run() override
+ {
+ /* Test creating empty UniqueFD. */
+ UniqueFD fd;
+
+ if (fd.isValid() || fd.get() != -1) {
+ std::cout << "Failed fd check (default constructor)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test creating UniqueFD from numerical file descriptor. */
+ UniqueFD fd2(fd_);
+ if (!fd2.isValid() || fd2.get() != fd_) {
+ std::cout << "Failed fd check (fd constructor)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (!isValidFd(fd_)) {
+ std::cout << "Failed fd validity (fd constructor)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test move constructor. */
+ UniqueFD fd3(std::move(fd2));
+ if (!fd3.isValid() || fd3.get() != fd_) {
+ std::cout << "Failed fd check (move constructor)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (fd2.isValid() || fd2.get() != -1) {
+ std::cout << "Failed moved fd check (move constructor)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (!isValidFd(fd_)) {
+ std::cout << "Failed fd validity (move constructor)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test move assignment operator. */
+ fd = std::move(fd3);
+ if (!fd.isValid() || fd.get() != fd_) {
+ std::cout << "Failed fd check (move assignment)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (fd3.isValid() || fd3.get() != -1) {
+ std::cout << "Failed moved fd check (move assignment)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (!isValidFd(fd_)) {
+ std::cout << "Failed fd validity (move assignment)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test swapping. */
+ fd2.swap(fd);
+ if (!fd2.isValid() || fd2.get() != fd_) {
+ std::cout << "Failed fd check (swap)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (fd.isValid() || fd.get() != -1) {
+ std::cout << "Failed swapped fd check (swap)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (!isValidFd(fd_)) {
+ std::cout << "Failed fd validity (swap)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test release. */
+ int numFd = fd2.release();
+ if (fd2.isValid() || fd2.get() != -1) {
+ std::cout << "Failed fd check (release)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (numFd != fd_) {
+ std::cout << "Failed released fd check (release)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (!isValidFd(fd_)) {
+ std::cout << "Failed fd validity (release)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test reset assignment. */
+ fd.reset(numFd);
+ if (!fd.isValid() || fd.get() != fd_) {
+ std::cout << "Failed fd check (reset assignment)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (!isValidFd(fd_)) {
+ std::cout << "Failed fd validity (reset assignment)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test reset destruction. */
+ fd.reset();
+ if (fd.isValid() || fd.get() != -1) {
+ std::cout << "Failed fd check (reset destruction)"
+ << std::endl;
+ return TestFail;
+ }
+
+ if (isValidFd(fd_)) {
+ std::cout << "Failed fd validity (reset destruction)"
+ << std::endl;
+ return TestFail;
+ }
+
+ /* Test destruction. */
+ if (createFd() == TestFail) {
+ std::cout << "Failed to recreate test fd"
+ << std::endl;
+ return TestFail;
+ }
+
+ {
+ UniqueFD fd4(fd_);
+ }
+
+ if (isValidFd(fd_)) {
+ std::cout << "Failed fd validity (destruction)"
+ << std::endl;
+ return TestFail;
+ }
+
+ return TestPass;
+ }
+
+ void cleanup() override
+ {
+ if (fd_ > 0)
+ close(fd_);
+ }
+
+private:
+ int createFd()
+ {
+ fd_ = open("/tmp", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd_ < 0)
+ return TestFail;
+
+ /* Cache inode number of temp file. */
+ struct stat s;
+ if (fstat(fd_, &s))
+ return TestFail;
+
+ inodeNr_ = s.st_ino;
+
+ return 0;
+ }
+
+ bool isValidFd(int fd)
+ {
+ struct stat s;
+ if (fstat(fd, &s))
+ return false;
+
+ /* Check that inode number matches cached temp file. */
+ return s.st_ino == inodeNr_;
+ }
+
+ int fd_;
+ ino_t inodeNr_;
+};
+
+TEST_REGISTER(UniqueFDTest)