--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2017 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Contact: Konstantin Drabeniuk <k.drabeniuk@samsung.com>
+ * Contact: Andrii Sokolenko <a.sokolenko@samsung.com>
+ * Contact: Roman Marchenko <r.marchenko@samsung.com>
+ * Contact: Sergey Sizonov <s.sizonov@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+**************************************************************************/
+
+#include "gtest/gtest.h"
+#include "ut_common.h"
+
+#include <cstring>
+
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <sys/signalfd.h>
+#include <poll.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/timerfd.h>
+
+extern "C"
+{
+#include "tdm.h"
+#include "tdm_client.h"
+
+#include "tbm_surface.h"
+
+#include "wayland-client.h"
+}
+
+class tdm_client_test_prepare
+{
+public:
+ tdm_client_test_prepare()
+ {
+ /* we have to deal with a named semaphore to protect an access to tdm across several instances
+ * of servers */
+ semaphore = sem_open(semaphore_name.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR, 1);
+ if (semaphore == SEM_FAILED)
+ {
+ if (errno == EEXIST)
+ sem_unlink(semaphore_name.c_str());
+ else
+ {
+ std::cout << "can't create semaphore(1): " << semaphore_name << ", errno: " << errno << ".\n";
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ return;
+ }
+
+ semaphore = sem_open(semaphore_name.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR, 1);
+ if (semaphore == SEM_FAILED)
+ {
+ std::cout << "can't create semaphore(2): " << semaphore_name << ", errno: " << errno << ".\n";
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ ~tdm_client_test_prepare()
+ {
+ sem_close(semaphore);
+ sem_unlink(semaphore_name.c_str());
+ }
+
+ static sem_t *semaphore;
+
+ /* /dev/shm/sem.tdm-client-utests */
+ static const std::string semaphore_name;
+};
+
+sem_t *tdm_client_test_prepare::semaphore;
+const std::string tdm_client_test_prepare::semaphore_name = "/tdm-client-utests";
+
+/* global object is created before main() */
+tdm_client_test_prepare dont_use_it;
+
+/* real mess, sorry... */
+class TDMClientTest : public ::testing::Test
+{
+protected:
+ TDMClientTest() : error(TDM_ERROR_NONE), server_pid(0), cl_serv_lock_fd(-1),
+ dsp(nullptr), output(nullptr), layer(nullptr), buffer(nullptr), is_server_stopped(false)
+ {
+ set_env_vars();
+ start_server(); /* as a separate process */
+ wait_till_server_ready();
+ }
+
+ ~TDMClientTest()
+ {
+ _stop_server();
+ unset_env_vars();
+ }
+
+ void send_request_to_server(int req)
+ {
+ switch(req)
+ {
+ case ChangeDPMS:
+ send_request(ChangeDPMS);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* to stop server by user demand */
+ void stop_server(void)
+ {
+ _stop_server();
+ wait_till_serv_is_over();
+
+ /* TODO: maybe it makes a sense to use this approach in the dtor too */
+ }
+
+ enum
+ {
+ ChangeDPMS,
+ };
+
+private:
+ void set_env_vars(void)
+ {
+ setenv("XDG_RUNTIME_DIR", "/run", 1);
+ setenv("TBM_DISPLAY_SERVER", "1", 1);
+ }
+
+ void unset_env_vars(void)
+ {
+ unsetenv("TBM_DISPLAY_SERVER");
+ unsetenv("XDG_RUNTIME_DIR");
+ }
+
+ void start_server(void)
+ {
+ cl_serv_lock_fd = eventfd(0, 0);
+ socketpair(AF_UNIX, SOCK_STREAM, 0, reinterpret_cast<int*>(&socks_pair));
+
+ server_pid = fork();
+
+ if (server_pid)
+ {
+ close(socks_pair.server_socket);
+ return;
+ }
+
+ close(socks_pair.client_socket);
+
+ wait_till_serv_resources_available();
+ run_server();
+ }
+
+ void _stop_server(void)
+ {
+ if (is_server_stopped) return;
+
+ close(socks_pair.client_socket);
+ close(cl_serv_lock_fd);
+ kill(server_pid, SIGINT);
+
+ is_server_stopped = true;
+ }
+
+ void wait_till_server_ready(void)
+ {
+ uint64_t val;
+
+ if (read(cl_serv_lock_fd, &val, sizeof val) < 0)
+ std::cout << "error while trying to read from cl_serv_lock_fd eventfd object.\n";
+ }
+
+ void notify_server_ready(void)
+ {
+ uint64_t val;
+
+ val = 1;
+
+ if (write(cl_serv_lock_fd, &val, sizeof val) < 0)
+ std::cout << "error while trying to write to cl_serv_lock_fd evenfd object.\n";
+ }
+
+ void wait_till_serv_resources_available(void)
+ {
+ while (1)
+ {
+ int ret;
+
+ ret = sem_wait(tdm_client_test_prepare::semaphore);
+ if (ret < 0 && errno == EINTR)
+ continue;
+ else
+ break;
+ }
+ }
+
+ void notify_serv_resources_available(void)
+ {
+ sem_post(tdm_client_test_prepare::semaphore);
+
+ sem_close(tdm_client_test_prepare::semaphore);
+ sem_unlink(tdm_client_test_prepare::semaphore_name.c_str());
+ }
+
+ void wait_till_serv_is_over(void)
+ {
+ wait_till_serv_resources_available();
+ sem_post(tdm_client_test_prepare::semaphore);
+ }
+
+ void send_request(int req)
+ {
+ send(socks_pair.client_socket, &req, sizeof req, 0);
+ }
+
+ void handle_client_request()
+ {
+ int req;
+
+ recv(socks_pair.server_socket, &req, sizeof req, 0);
+
+ switch(req)
+ {
+ case ChangeDPMS:
+ change_dpms_request_handler();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ void run_server(void)
+ {
+ sigset_t mask;
+ int signal_fd;
+ int tdm_fd;
+ pollfd work_fds[3];
+
+ /* ask kernel to notify us about parent's die via SIGHUP signal */
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGHUP);
+
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ signal_fd = signalfd(-1, &mask, 0);
+
+ init_tdm();
+ tdm_display_get_fd(dsp, &tdm_fd);
+
+ std::memset(&work_fds, 0, sizeof work_fds);
+
+ work_fds[0].fd = signal_fd;
+ work_fds[0].events = POLLIN;
+
+ work_fds[1].fd = tdm_fd;
+ work_fds[1].events = POLLIN;
+
+ work_fds[2].fd = socks_pair.server_socket;
+ work_fds[2].events = POLLIN;
+
+ notify_server_ready();
+
+ while (1)
+ {
+ int ret;
+
+ ret = poll(work_fds, 3, -1);
+ if (ret < 0 && errno == EINTR) continue;
+
+ if (work_fds[0].revents == POLLIN)
+ {
+ signal_hndl();
+ exit(EXIT_SUCCESS);
+ }
+
+ if(work_fds[1].revents == POLLIN)
+ tdm_display_handle_events(dsp);
+
+ if(work_fds[2].revents == POLLIN)
+ handle_client_request();
+ }
+ }
+
+ void signal_hndl(void)
+ {
+ close(socks_pair.server_socket);
+ close(cl_serv_lock_fd);
+
+ deinit_tdm();
+ notify_serv_resources_available();
+ }
+
+ void init_tdm(void);
+ void deinit_tdm(void);
+
+ void set_layer_geometry(int w, int h);
+ void set_image_on_screen(int w, int h);
+
+ void change_dpms_request_handler(void);
+
+ struct sockets_pair
+ {
+ sockets_pair() : server_socket(0), client_socket(0) {}
+ int server_socket;
+ int client_socket;
+ };
+
+protected:
+ tdm_error error;
+
+private:
+ pid_t server_pid;
+ int cl_serv_lock_fd;
+ sockets_pair socks_pair;
+
+ tdm_display *dsp;
+ tdm_output *output;
+ tdm_layer *layer;
+
+ tbm_surface_h buffer;
+
+ bool is_server_stopped;
+};
+
+class TDMClientTestClient : public TDMClientTest
+{
+protected:
+ TDMClientTestClient() : TDMClientTest()
+ {
+ tdm_cl = tdm_client_create(nullptr);
+ }
+ ~TDMClientTestClient()
+ {
+ tdm_client_destroy(tdm_cl);
+ }
+
+protected:
+ tdm_client *tdm_cl;
+};
+
+class TDMClientTestClientOutput : public TDMClientTestClient
+{
+protected:
+ TDMClientTestClientOutput() : TDMClientTestClient()
+ {
+ cl_output = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+ }
+ ~TDMClientTestClientOutput()
+ {
+ }
+
+protected:
+ tdm_client_output* cl_output;
+};
+
+class TDMClientTestVblank : public TDMClientTestClientOutput
+{
+protected:
+ TDMClientTestVblank() : TDMClientTestClientOutput()
+ {
+ cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr);
+ }
+ ~TDMClientTestVblank()
+ {
+ tdm_client_vblank_destroy(cl_vblank);
+ }
+
+protected:
+ tdm_client_vblank* cl_vblank;
+};
+
+typedef TDMClientTest TDMClientTestDeathTest;
+typedef TDMClientTestClient TDMClientTestClientDeathTest;
+typedef TDMClientTestClientOutput TDMClientTestClientOutputDeathTest;
+typedef TDMClientTestVblank TDMClientTestVblankDeathTest;
+
+
+void TDMClientTest::set_layer_geometry(int w, int h)
+{
+ tdm_info_layer layer_info;
+
+ std::memset(&layer_info, 0, sizeof(tdm_info_layer));
+
+ layer_info.src_config.size.h = w;
+ layer_info.src_config.size.v = h;
+ layer_info.src_config.pos.x = 0;
+ layer_info.src_config.pos.y = 0;
+ layer_info.src_config.pos.w = w;
+ layer_info.src_config.pos.h = h;
+ layer_info.src_config.format = TBM_FORMAT_ARGB8888;
+ layer_info.dst_pos.x = 0;
+ layer_info.dst_pos.y = 0;
+ layer_info.dst_pos.w = w;
+ layer_info.dst_pos.h = h;
+ layer_info.transform = TDM_TRANSFORM_NORMAL;
+
+ tdm_layer_set_info(layer, &layer_info);
+}
+
+void TDMClientTest::set_image_on_screen(int w, int h)
+{
+ tbm_surface_info_s tbm_surface_info;
+
+ /* to have a hw vblank we have to make at least one tdm_commit */
+ buffer = tbm_surface_create(w, h, TBM_FORMAT_ARGB8888);
+
+ std::memset(&tbm_surface_info, 0, sizeof(tbm_surface_info_s));
+
+ tbm_surface_map(buffer, TBM_SURF_OPTION_WRITE, &tbm_surface_info);
+
+ int *img = (int *)tbm_surface_info.planes[0].ptr;
+
+ for (uint32_t i = 0; i < tbm_surface_info.height; i++)
+ for (uint32_t j = 0; j < tbm_surface_info.planes[0].stride / 4; j++)
+ *img++ = 0x0000000;
+
+ tbm_surface_unmap(buffer);
+
+ set_layer_geometry(w, h);
+ tdm_layer_set_buffer(layer, buffer);
+ tdm_output_commit(output, 0, nullptr, nullptr);
+}
+
+void TDMClientTest::init_tdm(void)
+{
+ int outputs_cnt = 0;
+ tdm_output_type tdm_output_type;
+
+ int output_modes_cnt = 0;
+ const tdm_output_mode* output_modes;
+ const tdm_output_mode* preferred_mode = NULL;
+
+ int layers_cnt = 0;
+ tdm_layer_capability tdm_layer_capability;
+
+ dsp = tdm_display_init(nullptr);
+
+ tdm_display_get_output_count(dsp, &outputs_cnt);
+
+ /* this part is hardware dependent, how to resolve this issue ? */
+ for (int i = 0; i < outputs_cnt; i++)
+ {
+ output = tdm_display_get_output(dsp, i, nullptr);
+ tdm_output_get_output_type(output, &tdm_output_type);
+
+ /* we're not interesting about other outputs */
+ if (tdm_output_type != TDM_OUTPUT_TYPE_VIRTUAL &&
+ tdm_output_type != TDM_OUTPUT_TYPE_HDMIA)
+ break;
+ }
+
+ /* get output's preferred mode to obtain width & height we'll use later to create surface */
+ tdm_output_get_available_modes(output, &output_modes, &output_modes_cnt);
+
+ /* look for output's preferred mode */
+ for (int i = 0; i < output_modes_cnt; i++)
+ {
+ if (output_modes[i].type & TDM_OUTPUT_MODE_TYPE_PREFERRED)
+ {
+ preferred_mode = &output_modes[i];
+ break;
+ }
+ }
+
+ tdm_output_set_mode(output, preferred_mode);
+
+ tdm_output_get_layer_count(output, &layers_cnt);
+
+ /* it supposed that output always has primary & graphic layer */
+ for (int i = 0; i < layers_cnt; i++)
+ {
+ layer = tdm_output_get_layer(output, i, nullptr);
+ tdm_layer_get_capabilities(layer, &tdm_layer_capability);
+
+ if ((tdm_layer_capability & TDM_LAYER_CAPABILITY_PRIMARY) &&
+ (tdm_layer_capability & TDM_LAYER_CAPABILITY_GRAPHIC))
+ break;
+ }
+
+ tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON);
+
+ set_image_on_screen(preferred_mode->hdisplay, preferred_mode->vdisplay);
+}
+
+void TDMClientTest::deinit_tdm(void)
+{
+ if (layer)
+ {
+ tdm_layer_unset_buffer(layer);
+ tdm_output_commit(output, 1, nullptr, nullptr);
+ }
+
+ if (buffer)
+ tbm_surface_internal_unref(buffer);
+
+ if (dsp)
+ tdm_display_deinit(dsp);
+}
+
+void TDMClientTest::change_dpms_request_handler(void)
+{
+ std::cout << "tdm_output_set_dpms.\n";
+ tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateSuccessfulCheckClient)
+{
+ tdm_client *tdm_cl = tdm_client_create(nullptr);
+ ASSERT_TRUE(nullptr != tdm_cl);
+
+ tdm_client_destroy(tdm_cl);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateSuccessfulCheckError)
+{
+ tdm_client* tdm_cl = tdm_client_create(&error);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+
+ tdm_client_destroy(tdm_cl);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateFailServerStoppedCheckError)
+{
+ stop_server();
+
+ tdm_client_create(&error);
+ ASSERT_TRUE(TDM_ERROR_OPERATION_FAILED == error);
+}
+
+TEST_F(TDMClientTest, TdmClientCreateFailServerStopped)
+{
+ stop_server();
+
+ tdm_client *tdm_cl = tdm_client_create(nullptr);
+ ASSERT_TRUE(nullptr == tdm_cl);
+}
+
+TEST_F(TDMClientTestDeathTest, TdmClientDestroySuccessful)
+{
+ ASSERT_EXIT(
+ {
+ tdm_client_destroy(nullptr);
+
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestDeathTest, TdmClientDestroySuccessfulServerStopped)
+{
+ ASSERT_EXIT(
+ {
+ tdm_client *tdm_cl = tdm_client_create(nullptr);
+
+ stop_server();
+
+ tdm_client_destroy(tdm_cl);
+
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdSuccessful)
+{
+ int fd;
+
+ tdm_client_get_fd(tdm_cl, &fd);
+ ASSERT_TRUE(0 < fd);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdSuccessfulCheckError)
+{
+ int fd;
+
+ error = tdm_client_get_fd(tdm_cl, &fd);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdFailNullTdmClient)
+{
+ int fd;
+
+ error = tdm_client_get_fd(nullptr, &fd);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetFdFailNullFd)
+{
+ error = tdm_client_get_fd(nullptr, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClient, DISABLED_TdmClientHandleEventsSuccessful)
+{
+ ASSERT_EXIT(
+ {
+ pollfd work_fds[2];
+ itimerspec times_up;
+
+ std::memset(&work_fds, 0, sizeof work_fds);
+ std::memset(×_up, 0, sizeof times_up);
+
+ tdm_client_get_fd(tdm_cl, &work_fds[0].fd);
+ work_fds[0].events = POLLIN;
+
+ work_fds[1].fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ work_fds[1].events = POLLIN;
+
+ times_up.it_value.tv_nsec = 100000000; /* 100ms */
+ timerfd_settime(work_fds[1].fd, 0, ×_up, nullptr);
+
+ while (1)
+ {
+ int ret;
+
+ ret = poll(work_fds, 2, -1);
+ if (ret < 0 && errno == EINTR) continue;
+
+ if (work_fds[0].revents == POLLIN)
+ {
+ tdm_client_handle_events(tdm_cl);
+ std::cout << "ha.\n";
+ }
+
+ if(work_fds[1].revents == POLLIN)
+ exit(EXIT_SUCCESS);
+ }
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClient, TdmClientHandleEventsFailNullTDMClient)
+{
+ error = tdm_client_handle_events(nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessful)
+{
+ tdm_client_output* cl_output;
+
+ cl_output = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+ ASSERT_TRUE(nullptr != cl_output);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulCallTwice)
+{
+ tdm_client_output* cl_output_1, *cl_output_2;
+
+ cl_output_1 = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+ cl_output_2 = tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), nullptr);
+ ASSERT_TRUE(cl_output_1 == cl_output_2);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulCheckError)
+{
+ tdm_client_get_output(tdm_cl, const_cast<char*>("primary"), &error);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulNullName)
+{
+ tdm_client_output* cl_output;
+
+ cl_output = tdm_client_get_output(tdm_cl, nullptr, nullptr);
+ ASSERT_TRUE(nullptr != cl_output);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputSuccessfulNullNameCheckError)
+{
+ tdm_client_get_output(tdm_cl, nullptr, &error);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputFailNullTdmClient)
+{
+ tdm_client_output* cl_output;
+
+ cl_output = tdm_client_get_output(nullptr, const_cast<char*>("primary"), nullptr);
+ ASSERT_TRUE(nullptr == cl_output);
+}
+
+TEST_F(TDMClientTestClient, TdmClientGetOutputFailNullTdmClientCheckError)
+{
+ tdm_client_get_output(nullptr, const_cast<char*>("primary"), &error);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, DISABLED_TdmClientOutputAddChangeHandlerSuccessful)
+{
+ static bool got_an_event = false;
+ wl_display *wl_dsp;
+
+ /* is this function implemented fully? */
+ tdm_client_output_add_change_handler(cl_output, [] (tdm_client_output *output,
+ tdm_output_change_type type,
+ tdm_value value,
+ void *user_data) { got_an_event = true; }, nullptr);
+
+ /* force a requests flush */
+ wl_dsp = wl_display_connect("tdm-socket");
+ wl_display_flush(wl_dsp);
+ wl_display_roundtrip(wl_dsp);
+ wl_display_disconnect(wl_dsp);
+
+ send_request_to_server(TDMClientTest::ChangeDPMS);
+ tdm_client_handle_events(tdm_cl);
+
+ ASSERT_TRUE(true == got_an_event);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputAddChangeHandlerFailNullOutput)
+{
+ error = tdm_client_output_add_change_handler(nullptr, [] (tdm_client_output *output,
+ tdm_output_change_type type,
+ tdm_value value,
+ void *user_data) {}, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputAddChangeHandlerFailNullHandler)
+{
+ error = tdm_client_output_add_change_handler(cl_output, nullptr, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerSuccessful)
+{
+ ASSERT_EXIT(
+ {
+ auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value,
+ void *user_data) {};
+
+ tdm_client_output_add_change_handler(cl_output, func, nullptr);
+
+ tdm_client_output_remove_change_handler(cl_output, func, nullptr);
+
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerSuccessfulInvalidHandler)
+{
+ ASSERT_EXIT(
+ {
+ auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value,
+ void *user_data) {};
+
+ tdm_client_output_remove_change_handler(cl_output, func, nullptr);
+
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerFailNullOutput)
+{
+ ASSERT_EXIT(
+ {
+ auto func = [] (tdm_client_output *output, tdm_output_change_type type, tdm_value value,
+ void *user_data) {};
+
+ tdm_client_output_remove_change_handler(nullptr, func, nullptr);
+
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientOutputRemoveChangeHandlerFailNullHandler)
+{
+ ASSERT_EXIT(
+ {
+ tdm_client_output_remove_change_handler(cl_output, nullptr, nullptr);
+
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateSuccessful)
+{
+ uint32_t refresh_rate;
+
+ error = tdm_client_output_get_refresh_rate(cl_output, &refresh_rate);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateFailNullOutput)
+{
+ uint32_t refresh_rate;
+
+ error = tdm_client_output_get_refresh_rate(nullptr, &refresh_rate);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetRefreshRateFailNullRefreshRate)
+{
+ error = tdm_client_output_get_refresh_rate(cl_output, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetConnectionStatusSuccessful)
+{
+ tdm_output_conn_status conn_status;
+
+ error = tdm_client_output_get_conn_status(cl_output, &conn_status);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetConnectionStatusFailNullOutput)
+{
+ tdm_output_conn_status conn_status;
+
+ error = tdm_client_output_get_conn_status(nullptr, &conn_status);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TTdmClientOutputGetConnectionStatusFailNullConnState)
+{
+ error = tdm_client_output_get_conn_status(cl_output, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsSuccessful)
+{
+ tdm_output_dpms dpms_val;
+
+ error = tdm_client_output_get_dpms(cl_output, &dpms_val);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsFailNullOutput)
+{
+ tdm_output_dpms dpms_val;
+
+ error = tdm_client_output_get_dpms(nullptr, &dpms_val);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputGetDpmsFailNullDpmsArg)
+{
+ error = tdm_client_output_get_dpms(cl_output, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankSuccessful)
+{
+ tdm_client_vblank* cl_vblank;
+
+ cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr);
+ ASSERT_TRUE(nullptr != cl_vblank);
+
+ tdm_client_vblank_destroy(cl_vblank);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankSuccessfulCheckError)
+{
+ tdm_client_vblank* cl_vblank;
+
+ cl_vblank = tdm_client_output_create_vblank(cl_output, &error);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+
+ tdm_client_vblank_destroy(cl_vblank);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankFailNullOutput)
+{
+ tdm_client_vblank* cl_vblank;
+
+ cl_vblank = tdm_client_output_create_vblank(nullptr, nullptr);
+ ASSERT_TRUE(nullptr == cl_vblank);
+}
+
+TEST_F(TDMClientTestClientOutput, TdmClientOutputCreateVblankFailNullOutputCheckError)
+{
+ tdm_client_output_create_vblank(nullptr, &error);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientDestroyVblankSuccessful)
+{
+ ASSERT_EXIT(
+ {
+ tdm_client_vblank *cl_vblank = tdm_client_output_create_vblank(cl_output, nullptr);
+
+ tdm_client_vblank_destroy(cl_vblank);
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestClientOutputDeathTest, TdmClientDestroyVblankFailNoClientVblankArg)
+{
+ ASSERT_EXIT(
+ {
+ tdm_client_vblank_destroy(nullptr);
+ exit(EXIT_SUCCESS);
+ },
+ ::testing::ExitedWithCode(EXIT_SUCCESS), "");
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetNameSuccessful)
+{
+ error = tdm_client_vblank_set_name(cl_vblank, "wassup");
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetNameSuccessfulNoExplicitName)
+{
+ error = tdm_client_vblank_set_name(cl_vblank, nullptr);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetNameFailNullClientVblank)
+{
+ error = tdm_client_vblank_set_name(nullptr, "wassup");
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetSyncSuccessful)
+{
+ error = tdm_client_vblank_set_sync(cl_vblank, 0);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetSyncFailNullClientVblank)
+{
+ error = tdm_client_vblank_set_sync(nullptr, 0);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsSuccessful)
+{
+ error = tdm_client_vblank_set_fps(cl_vblank, 60);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsSuccessfulSetTwice)
+{
+ tdm_client_vblank_set_fps(cl_vblank, 60);
+ error = tdm_client_vblank_set_fps(cl_vblank, 60);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsFailNullClientVblank)
+{
+ error = tdm_client_vblank_set_fps(nullptr, 60);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFpsFailInvalidFpsArg)
+{
+ error = tdm_client_vblank_set_fps(cl_vblank, 0);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetSuccessful)
+{
+ error = tdm_client_vblank_set_offset(cl_vblank, 10);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetSuccessfulSetTwice)
+{
+ tdm_client_vblank_set_offset(cl_vblank, 10);
+ error = tdm_client_vblank_set_offset(cl_vblank, 10);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetOffsetFailNullClientVblank)
+{
+ error = tdm_client_vblank_set_offset(nullptr, 10);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulEnableFake)
+{
+ error = tdm_client_vblank_set_enable_fake(cl_vblank, 1);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulDisableFake)
+{
+ error = tdm_client_vblank_set_enable_fake(cl_vblank, 0);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeSuccessfulSetTwice)
+{
+ tdm_client_vblank_set_enable_fake(cl_vblank, 0);
+ error = tdm_client_vblank_set_enable_fake(cl_vblank, 0);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankSetFakeFailNullClientVblank)
+{
+ error = tdm_client_vblank_set_enable_fake(nullptr, 0);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSuccessful)
+{
+ auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data) {};
+
+ tdm_client_vblank_set_sync(cl_vblank, 0);
+ tdm_client_vblank_set_enable_fake(cl_vblank, 1);
+
+ error = tdm_client_vblank_wait(cl_vblank, 1, func, nullptr);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailNullClientVblank)
+{
+ auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data) {};
+
+ error = tdm_client_vblank_wait(nullptr, 1, func, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailNullHandler)
+{
+ error = tdm_client_vblank_wait(cl_vblank, 1, nullptr, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitFailInvalidInterval)
+{
+ auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data) {};
+
+ error = tdm_client_vblank_wait(cl_vblank, 0, func, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencySuccessful)
+{
+ auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data) {};
+
+ tdm_client_vblank_set_sync(cl_vblank, 0);
+ tdm_client_vblank_set_enable_fake(cl_vblank, 1);
+
+ error = tdm_client_vblank_wait_seq(cl_vblank, 100, func, nullptr);
+ ASSERT_TRUE(TDM_ERROR_NONE == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencyFailNullClientVblank)
+{
+ auto func = [](tdm_client_vblank *vblank, tdm_error error, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data) {};
+
+ error = tdm_client_vblank_wait_seq(nullptr, 1, func, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+
+TEST_F(TDMClientTestVblank, TdmClientVblankWaitSequencyFailNullHandler)
+{
+ error = tdm_client_vblank_wait_seq(cl_vblank, 1, nullptr, nullptr);
+ ASSERT_TRUE(TDM_ERROR_INVALID_PARAMETER == error);
+}
+