utest: fix all failed tests and add new tests
[platform/core/uifw/libtdm.git] / utests / src / ut_tdm_output.cpp
index 460972c..a883cd4 100644 (file)
 #include "gtest/gtest.h"
 #include "ut_common.h"
 #include <climits>
-extern "C" {
 #include "tdm.h"
+extern "C" {
 #include "tbm_bufmgr.h"
 #include "tbm_drm_helper.h"
 }
+#include <vector>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <pthread.h>
 
 class TDMOutput : public ::testing::Test {
 protected:
        tdm_display *dpy = NULL;
-       int output_count = -42;
+       int output_count = 0, master_fd = -42, tbm_fd = -42;
        bool has_output = false;
        tbm_bufmgr tbm_bufmgr = NULL;
        static unsigned int handle_call;
@@ -49,22 +53,44 @@ protected:
                                                                                                        tdm_value value,
                                                                                                        void *u_data)
        {
-               if ( ((int) u_data) < -100) {
+               if ( ((intptr_t) u_data) < -100) {
                        TDMOutput::handle_call++;
                }
        }
-       void SetUp(void)
+       virtual void SetEnvs()
        {
+               setenv("TDM_DEBUG_MODULE", "all", 1);
+               setenv("TDM_DEBUG", "1", 1);
                setenv("TDM_DLOG", "1", 1);
-               setenv("XDG_RUNTIME_DIR", ".", 1);
+               setenv("XDG_RUNTIME_DIR", "/run", 1);
                setenv("TBM_DLOG", "1", 1);
                setenv("TBM_DISPLAY_SERVER", "1", 1);
-               tbm_bufmgr = tbm_bufmgr_init(-1);
-               ASSERT_FALSE(tbm_bufmgr == NULL);
+               setenv("TDM_COMMIT_PER_VBLANK", "0", 1);
+       }
+
+       virtual void UnsetEnvs()
+       {
+               unsetenv("TDM_DEBUG_MODULE");
+               unsetenv("TDM_DEBUG");
+               unsetenv("TDM_DLOG");
+               unsetenv("XDG_RUNTIME_DIR");
+               unsetenv("TBM_DLOG");
+               unsetenv("TBM_DISPLAY_SERVER");
+               unsetenv("TDM_COMMIT_PER_VBLANK");
+       }
+
+       void SetUp(void)
+       {
+               SetEnvs();
+
                tdm_error error = TDM_ERROR_NONE;
                dpy = tdm_display_init(&error);
                ASSERT_TRUE(error == TDM_ERROR_NONE);
                ASSERT_FALSE(dpy == NULL);
+               tbm_bufmgr = tbm_bufmgr_init(-1);
+               ASSERT_FALSE(tbm_bufmgr == NULL);
+               master_fd = tbm_drm_helper_get_master_fd();
+               tbm_fd = tbm_drm_helper_get_fd();
                error = tdm_display_get_output_count(dpy, &output_count);
 #ifdef FAIL_ON_UNSUPPORTED
                ASSERT_GT(output_count, 0);
@@ -79,14 +105,324 @@ protected:
                dpy = NULL;
                tbm_bufmgr_deinit(tbm_bufmgr);
                tbm_bufmgr = NULL;
-               unsetenv("TDM_DLOG");
-               unsetenv("XDG_RUNTIME_DIR");
-               unsetenv("TBM_DLOG");
-               unsetenv("TBM_DISPLAY_SERVER");
+               if (master_fd > -1) {
+                       int temp_master_fd = tbm_drm_helper_get_master_fd();
+                       EXPECT_EQ(temp_master_fd, -1) << "Fatal Error. Can't deinit tdm/tbm" << std::endl;
+                       if (temp_master_fd > -1)
+                               exit(1);
+                       close(master_fd);
+               }
+               if (tbm_fd > -1) {
+                       int temp_tbm_fd = tbm_drm_helper_get_fd();
+                       EXPECT_EQ(temp_tbm_fd, -1) << "Fatal Error. Can't deinit tdm/tbm" << std::endl;
+                       if (temp_tbm_fd > -1)
+                               exit(1);
+                       close(tbm_fd);
+               }
+
+               UnsetEnvs();
+       }
+};
+
+class TDMOutputHWC : public TDMOutput {
+       void SetEnvs(void)
+       {
+               TDMOutput::SetEnvs();
+               setenv("TDM_HWC", "1", 1);
+       }
+       void UnsetEnvs(void)
+       {
+               TDMOutput::UnsetEnvs();
+               unsetenv("TDM_HWC");
+       }
+};
+
+class TDMOutputThread : public TDMOutput {
+       void SetEnvs(void)
+       {
+
+               TDMOutput::SetEnvs();
+               setenv("TDM_THREAD", "1", 1);
+       }
+       void UnsetEnvs(void)
+       {
+               TDMOutput::UnsetEnvs();
+               unsetenv("TDM_THREAD");
+       }
+};
+
+class TDMOutputCommit : public TDMOutput {
+private:
+       int epFd = -1;
+       int timerFd = -1;
+       int tdmFd = -1;
+       static const int timeLimitSec = 1;
+       static const int timeLimitNsec = 0;
+protected:
+       int conn_output_count = 0;
+       tdm_output ** connected_output_array = NULL;
+       const tdm_output_mode** preferred_mode = NULL;
+       bool has_output = false;
+       std::vector<std::vector<tdm_layer *>> layers_array;
+       std::vector<tbm_surface_h> buffers;
+       static unsigned int utOutputCommitHandlerCounter;
+       static void UtOutputCommitHandler(tdm_output *output, unsigned int sequence,
+                                                          unsigned int tv_sec, unsigned int tv_usec,
+                                                          void *user_data)
+       {
+               utOutputCommitHandlerCounter++;
+       }
+
+       static unsigned int utOutputVblankHandlerCounter;
+       static void UtOutputVblankHandler(tdm_output *output, unsigned int sequence,
+                                                          unsigned int tv_sec, unsigned int tv_usec,
+                                                          void *user_data)
+       {
+               utOutputVblankHandlerCounter++;
+       }
+       friend void *UtOutputRemoveChangeHandlerSuccessfulThread(void *ptr);
+
+       void SetUp(void)
+       {
+               struct epoll_event ep;
+
+               utOutputCommitHandlerCounter = 0;
+               utOutputVblankHandlerCounter = 0;
+
+               ASSERT_NO_FATAL_FAILURE(TDMOutput::SetUp());
+               if (TDMOutput::output_count > 0) {
+                       connected_output_array = (tdm_output **) calloc(TDMOutput::output_count, sizeof(tdm_output *));
+                       ASSERT_FALSE(NULL == connected_output_array);
+                       preferred_mode = (const tdm_output_mode **) calloc(TDMOutput::output_count, sizeof(tdm_output_mode*));
+                       ASSERT_FALSE(NULL == preferred_mode);
+               }
+               conn_output_count = 0;
+               for (int i = 0; i < TDMOutput::output_count; i++) {
+                       tdm_error error = TDM_ERROR_NONE;
+                       int output_modes_cnt = 0;
+                       int layer_count = 0;
+                       const tdm_output_mode* output_modes = NULL;
+                       tdm_output * output = tdm_display_get_output(TDMOutput::dpy, i, &error);
+                       std::vector<tdm_layer *> layers;
+                       if (TDM_ERROR_NONE != error || NULL == output)
+                               continue;
+                       tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
+                       if (TDM_ERROR_NONE != tdm_output_get_conn_status(output, &status))
+                               continue;
+                       if (TDM_OUTPUT_CONN_STATUS_DISCONNECTED == status)
+                               continue;
+                       if (TDM_ERROR_NONE != tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON))
+                               continue;
+                       if(TDM_ERROR_NONE != tdm_output_get_available_modes(output,
+                                                                                                                               &output_modes,
+                                                                                                                               &output_modes_cnt))
+                               continue;
+                       for(int k = 0; k < output_modes_cnt; k++) {
+                               if(output_modes[k].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) {
+                                       preferred_mode[conn_output_count] = &output_modes[k];
+                                       break;
+                               }
+                       }
+                       if (NULL == preferred_mode[conn_output_count])
+                               continue;
+
+                       if (TDM_ERROR_NONE != tdm_output_get_layer_count(output, &layer_count))
+                               continue;
+                       if (0 == layer_count)
+                               continue;
+
+                       for (int i = 0; i < layer_count; ++i) {
+                               tdm_layer *layer;
+                               layer = tdm_output_get_layer(output, i, &error);
+                               if (layer == nullptr)
+                                       continue;
+                               layers.push_back(layer);
+                       }
+                       connected_output_array[conn_output_count++] = output;
+                       layers_array.push_back(layers);
+               }
+#ifdef FAIL_ON_UNSUPPORTED
+               ASSERT_GT(conn_output_count, 0);
+#endif
+
+               if (conn_output_count > 0)
+                       has_output = true;
+
+               epFd = epoll_create1(0);
+               ASSERT_TRUE(epFd != -1);
+
+               timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
+               ASSERT_TRUE(timerFd != -1);
+
+               memset(&ep, 0, sizeof ep);
+               ep.events |= EPOLLIN;
+               ep.data.fd = timerFd;
+               ASSERT_TRUE(epoll_ctl(epFd, EPOLL_CTL_ADD, timerFd, &ep) == 0);
+
+               ASSERT_TRUE(tdm_display_get_fd(dpy, &tdmFd) == TDM_ERROR_NONE);
+
+               memset(&ep, 0, sizeof ep);
+               ep.events |= EPOLLIN;
+               ep.data.fd = tdmFd;
+               ASSERT_TRUE(epoll_ctl(epFd, EPOLL_CTL_ADD, tdmFd, &ep) == 0);
+       }
+       void TearDown(void)
+       {
+               for (size_t i = 0; i < layers_array.size(); ++i) {
+                       for (tdm_layer *layer : layers_array[i]) {
+                               tdm_layer_unset_buffer(layer);
+                       }
+               }
+
+               for (tbm_surface_h buffer : buffers) {
+                       tbm_surface_destroy(buffer);
+               }
+
+               for (int i = 0; i < conn_output_count; i++) {
+                       EXPECT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(connected_output_array[i],
+                                                                                                                         TDM_OUTPUT_DPMS_OFF));
+               }
+               if (connected_output_array)
+                       free(connected_output_array);
+               if (preferred_mode)
+                       free(preferred_mode);
+               ASSERT_NO_FATAL_FAILURE(TDMOutput::TearDown());
+       }
+
+       tbm_surface_h UtCreateBuffer(int width, int height, tbm_format format)
+       {
+               tbm_surface_h buffer;
+
+               buffer = tbm_surface_internal_create_with_flags(width, height, format, TBM_BO_SCANOUT);
+
+               if (buffer)
+                       buffers.push_back(buffer);
+
+               return buffer;
+       }
+
+       void UtPrepareToCommit()
+       {
+               for (size_t i = 0; i < layers_array.size(); ++i) {
+                       for (tdm_layer *layer : layers_array[i]) {
+                               int w, h;
+                               tdm_error error;
+                               tdm_layer_capability lcapabilities;
+                               tbm_surface_h buffer;
+                               tdm_info_layer layer_info = {0};
+
+                               w = preferred_mode[i]->hdisplay;
+                               h = preferred_mode[i]->vdisplay;
+
+                               error = tdm_output_set_mode(connected_output_array[i], preferred_mode[i]);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+
+                               error = tdm_layer_get_capabilities(layer, &lcapabilities);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+                               if (!(lcapabilities & TDM_LAYER_CAPABILITY_PRIMARY)) {
+                                       w = w / 2;
+                                       h = h / 2;
+                               }
+
+                               buffer = UtCreateBuffer(w, h, TBM_FORMAT_ARGB8888);
+                               ASSERT_NE(nullptr, buffer);
+
+                               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;
+
+                               error = tdm_layer_set_info(layer, &layer_info);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+
+                               error = tdm_layer_set_buffer(layer, buffer);
+                               ASSERT_EQ(TDM_ERROR_NONE, error);
+                       }
+               }
+       }
+
+       void UtHandleEvent(unsigned int & wait_var, unsigned int num)
+       {
+               struct itimerspec its;
+               int count;
+               struct epoll_event ep_event[2];
+
+               if (wait_var == num)
+                       return;
+
+               its.it_interval.tv_sec = 0;
+               its.it_interval.tv_nsec = 0;
+               its.it_value.tv_sec = timeLimitSec;
+               its.it_value.tv_nsec = timeLimitNsec;
+
+               ASSERT_TRUE(timerfd_settime(timerFd, 0, &its, NULL) == 0);
+
+               while (1) {
+                       count = epoll_wait(epFd, ep_event, sizeof(ep_event), -1);
+                       ASSERT_TRUE(count >= 0);
+
+                       for (int i = 0; i < count; i++) {
+                               if (ep_event[i].data.fd == timerFd) {
+                                       return;
+                               } else {
+                                       ASSERT_TRUE(tdm_display_handle_events(dpy) == TDM_ERROR_NONE);
+                                       if (wait_var == num)
+                                               return;
+                               }
+                       }
+               }
+       }
+
+       void UtHandleCommitEvent()
+       {
+               UtHandleEvent(utOutputCommitHandlerCounter, (unsigned int)conn_output_count);
+       }
+
+       void UtHandleVblankEvent()
+       {
+               UtHandleEvent(utOutputVblankHandlerCounter, conn_output_count);
+       }
+};
+
+class TDMOutputCommitPerVblankEnabled : public TDMOutputCommit {
+       void SetEnvs(void)
+       {
+
+               TDMOutputCommit::SetEnvs();
+               setenv("TDM_COMMIT_PER_VBLANK", "1", 1);
+       }
+       void UnsetEnvs(void)
+       {
+               TDMOutputCommit::UnsetEnvs();
+               unsetenv("TDM_COMMIT_PER_VBLANK");
+       }
+};
+
+class TDMOutputCommitThread : public TDMOutputCommit {
+       void SetEnvs(void)
+       {
+               TDMOutputCommit::SetEnvs();
+               setenv("TDM_THREAD", "1", 1);
+       }
+
+       void UnsetEnvs(void)
+       {
+               TDMOutputCommit::UnsetEnvs();
+               unsetenv("TDM_THREAD");
        }
 };
 
 unsigned int TDMOutput::handle_call = 0;
+unsigned int TDMOutputCommit::utOutputCommitHandlerCounter = 0;
+unsigned int TDMOutputCommit::utOutputVblankHandlerCounter = 0;
 
 TEST_F(TDMOutput, DisplayGetOutputSuccessful)
 {
@@ -133,7 +469,7 @@ TEST_F(TDMOutput, DisplayOutputGetCapabilitiesSuccessful)
        SKIP_FLAG(has_output);
        for (int i = 0; i < output_count; i++) {
                tdm_error error = TDM_ERROR_NONE;
-               tdm_output_capability capabilities = -42;
+               tdm_output_capability capabilities = (tdm_output_capability) -42;
                tdm_output * output = tdm_display_get_output(dpy, i, &error);
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
@@ -199,7 +535,7 @@ TEST_F(TDMOutput, OutputGetConnStatusSuccessful)
        SKIP_FLAG(has_output);
        for (int i = 0; i < output_count; i++) {
                tdm_error error = TDM_ERROR_NONE;
-               tdm_output_conn_status status = -42;
+               tdm_output_conn_status status = (tdm_output_conn_status) -42;
                tdm_output * output = tdm_display_get_output(dpy, i, &error);
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
@@ -229,59 +565,86 @@ TEST_F(TDMOutput, OutputGetConnStatusFailOnlyOutput)
 TEST_F(TDMOutput, OutputSetDPMSSuccessful)
 {
        SKIP_FLAG(has_output);
+       bool checked = false;
        for (int i = 0; i < output_count; i++) {
                tdm_error error = TDM_ERROR_NONE;
+               tdm_output_conn_status status;
                tdm_output * output = tdm_display_get_output(dpy, i, &error);
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_conn_status(output, &status));
+               if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
+                       continue;
+               checked = true;
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_STANDBY));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_SUSPEND));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
        }
+       if (false == checked) {
+               FAIL() << "All outputs are disconnected. Testcase skipped" << std::endl;
+       }
 }
 
 TEST_F(TDMOutput, OutputAddChangeHandlerSuccessful)
 {
        SKIP_FLAG(has_output);
+       bool checked = false;
        for (int i = 0; i < output_count; i++) {
                tdm_error error = TDM_ERROR_NONE;
                tdm_output * output = tdm_display_get_output(dpy, i, &error);
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
+               tdm_output_conn_status status;
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_conn_status(output, &status));
+               if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
+                       continue;
+               checked = true;
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_add_change_handler(output,
                                                                                                                                        tdm_output_change_handler_test_func,
-                                                                                                                                       -101));
+                                                                                                                                       (void *) -101));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
                ASSERT_GT(handle_call, 0);
        }
+       if (false == checked) {
+               FAIL() << "All outputs are disconnected. Testcase skipped" << std::endl;
+       }
 }
 
 TEST_F(TDMOutput, OutputAddChangeHandlerSuccessfulFewFuncs)
 {
        SKIP_FLAG(has_output);
+       bool checked = false;
        for (int i = 0; i < output_count; i++) {
                tdm_error error = TDM_ERROR_NONE;
                tdm_output * output = tdm_display_get_output(dpy, i, &error);
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
-               for (int k = 0; k < 20; k++) {
+               tdm_output_conn_status status;
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_conn_status(output, &status));
+               if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
+                       continue;
+               checked = true;
+               for (intptr_t k = 0; k < 20; k++) {
                        ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_add_change_handler(output,
                                                                                                                                                tdm_output_change_handler_test_func,
-                                                                                                                                               (-101-k)));
+                                                                                                                                               (void *) (-101-k)));
                }
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
                ASSERT_GT(handle_call, 20);
        }
+       if (false == checked) {
+               FAIL() << "All outputs are disconnected. Testcase skipped" << std::endl;
+       }
 }
 
 
 TEST_F(TDMOutput, OutputAddChangeHandlerFailAllNull)
 {
        SKIP_FLAG(has_output);
-       ASSERT_FALSE(TDM_ERROR_NONE ==tdm_output_add_change_handler(NULL, NULL, NULL));
+       ASSERT_FALSE(TDM_ERROR_NONE == tdm_output_add_change_handler(NULL, NULL, NULL));
 }
 
 TEST_F(TDMOutput, OutputAddChangeHandlerFailOnlyOutput)
@@ -299,55 +662,874 @@ TEST_F(TDMOutput, OutputAddChangeHandlerFailOnlyOutput)
 TEST_F(TDMOutput, OutputAddChangeHandlerFailWrongOutput)
 {
        SKIP_FLAG(has_output);
-       ASSERT_EXIT({tdm_output *output = 0xBEAF;
+       ASSERT_EXIT({tdm_output *output = (tdm_output *) 0xBEAF;
                                 tdm_output_add_change_handler(output,
                                                                                           tdm_output_change_handler_test_func,
-                                                                                          -101);
+                                                                                          (void *) -101);
                                 exit(0);}, ::testing::ExitedWithCode(0), "");
 }
 
 TEST_F(TDMOutput, OutputRemoveChangeHandlerSuccessful)
 {
+       SKIP_FLAG(has_output);
+       bool checked = false;
        for (int i = 0; i < output_count; i++) {
                tdm_error error = TDM_ERROR_NONE;
                tdm_output * output = tdm_display_get_output(dpy, i, &error);
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
+               tdm_output_conn_status status;
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_conn_status(output, &status));
+               if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
+                       continue;
+               checked = true;
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_add_change_handler(output,
                                                                                                                                        tdm_output_change_handler_test_func,
-                                                                                                                                       -101));
+                                                                                                                                       (void *) -101));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
                ASSERT_GT(handle_call, 0);
                handle_call = 0;
-               tdm_output_remove_change_handler(output, tdm_output_change_handler_test_func, -101);
+               tdm_output_remove_change_handler(output, tdm_output_change_handler_test_func, (void *) -101);
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
                ASSERT_EQ(handle_call, 0);
        }
+       if (false == checked) {
+               FAIL() << "All outputs are disconnected. Testcase skipped" << std::endl;
+       }
+}
+
+void *UtOutputRemoveChangeHandlerSuccessfulThread(void *ptr)
+{
+       TDMOutputCommitThread *FTDMOutput = (TDMOutputCommitThread *)ptr;
+
+       bool checked = false;
+       for (int i = 0; i < FTDMOutput->output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               tdm_output * output = tdm_display_get_output(FTDMOutput->dpy, i, &error);
+               if (NULL == output || TDM_ERROR_NONE != error)
+                       return (void *)1;
+               tdm_output_conn_status status;
+               error = tdm_output_get_conn_status(output, &status);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)2;
+               if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
+                       continue;
+               checked = true;
+               error = tdm_output_add_change_handler(output,
+                                                                                               FTDMOutput->tdm_output_change_handler_test_func,
+                                                                                               (void *) -101);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)3;
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)4;
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)5;
+               FTDMOutput->UtHandleEvent(FTDMOutput->handle_call, 1);
+               if (FTDMOutput->handle_call <= 0)
+                       return (void *)6;
+               FTDMOutput->handle_call = 0;
+               tdm_output_remove_change_handler(output, FTDMOutput->tdm_output_change_handler_test_func, (void *) -101);
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)7;
+               error = tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF);
+               if (TDM_ERROR_NONE != error)
+                       return (void *)8;
+               FTDMOutput->UtHandleEvent(FTDMOutput->handle_call, 1);
+               if (FTDMOutput->handle_call != 0)
+                       return (void *)9;
+       }
+       if (false == checked) {
+               return (void *)10;
+       }
+
+       return nullptr;
+}
+
+TEST_F(TDMOutputCommitThread, OutputRemoveChangeHandlerSuccessfulThread)
+{
+       SKIP_FLAG(has_output);
+       pthread_t thread = 0;
+       int *status = nullptr;
+
+       ASSERT_FALSE(pthread_create(&thread, NULL, UtOutputRemoveChangeHandlerSuccessfulThread, this));
+
+       ASSERT_FALSE(pthread_join(thread, (void **)&status));
+
+       ASSERT_EQ(nullptr, status);
 }
 
 TEST_F(TDMOutput, OutputRemoveChangeHandlerSuccessfulFewFuncs)
 {
+       SKIP_FLAG(has_output);
+       bool checked = false;
        for (int i = 0; i < output_count; i++) {
                tdm_error error = TDM_ERROR_NONE;
                tdm_output * output = tdm_display_get_output(dpy, i, &error);
                ASSERT_FALSE(NULL == output);
                ASSERT_TRUE(TDM_ERROR_NONE == error);
-               for (int k = 0; k < 20; k++) {
+               tdm_output_conn_status status;
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_conn_status(output, &status));
+               if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
+                       continue;
+               checked = true;
+               for (intptr_t k = 0; k < 20; k++) {
                        ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_add_change_handler(output,
                                                                                                                                                tdm_output_change_handler_test_func,
-                                                                                                                                               (-101-k)));
+                                                                                                                                               (void *) (-101-k)));
                }
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
                ASSERT_GT(handle_call, 20);
                handle_call = 0;
-               for (int k = 0; k < 20; k++) {
-                       tdm_output_remove_change_handler(output, tdm_output_change_handler_test_func, (-101-k));
+               for (intptr_t k = 0; k < 20; k++) {
+                       tdm_output_remove_change_handler(output, tdm_output_change_handler_test_func, (void *) (-101-k));
                }
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON));
                ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_OFF));
                ASSERT_EQ(handle_call, 0);
        }
+       if (false == checked) {
+               FAIL() << "All outputs are disconnected. Testcase skipped" << std::endl;
+       }
+}
+
+TEST_F(TDMOutput, OutputRemoveChangeHandlerFailAllNull)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({tdm_output_remove_change_handler(NULL, NULL, NULL);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputRemoveChangeHandlerFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        tdm_output_remove_change_handler(output, NULL, NULL);
+                                } exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputRemoveChangeHandlerFailWrongOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({tdm_output *output = (tdm_output *) 0xBEAF;
+                                tdm_output_remove_change_handler(output,
+                                                                                          tdm_output_change_handler_test_func,
+                                                                                          (void *) -101);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetOutputTypeSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               tdm_output_type type = (tdm_output_type) -42;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_output_type(output, &type));
+               ASSERT_NE(type, -42);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetOutputTypeFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_output_type(NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetOutputTypeFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_output_type(output, NULL) == TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetLayerCountSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int count = -42;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_layer_count(output, &count));
+               ASSERT_NE(count, -42);
+       }
+}
+
+int is_hwc_ennable(tdm_output * output)
+{
+       tdm_output_capability capabilities = (tdm_output_capability)0;
+       tdm_output_get_capabilities(output, &capabilities);
+       return capabilities & TDM_OUTPUT_CAPABILITY_HWC;
+}
+
+TEST_F(TDMOutputHWC, OutputGetLayerCountFailHWC)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int count = -42;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               if (is_hwc_ennable(output))
+                       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_get_layer_count(output, &count));
+       }
+}
+
+TEST_F(TDMOutputHWC, OutputGetLayerFailHWC)
+{
+       SKIP_FLAG(has_output);
+
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               if (is_hwc_ennable(output)) {
+                       ASSERT_TRUE(nullptr == tdm_output_get_layer(output, 0, &error));
+                       ASSERT_TRUE(TDM_ERROR_NONE != error);
+               }
+       }
+}
+
+TEST_F(TDMOutput, OutputGetLayerCountFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_layer_count(NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetLayerCountFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (TDM_ERROR_NONE == tdm_output_get_layer_count(output, NULL)) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailablePropertiesSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int count = -42;
+               const tdm_prop *tdm_prop_array = (const tdm_prop *) 0xBEAF;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_available_properties(output,
+                                                                                                                                                 &tdm_prop_array,
+                                                                                                                                                 &count));
+               ASSERT_NE(count, -42);
+               ASSERT_NE(tdm_prop_array, 0xBEAF);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetAvailablePropertiesFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_available_properties(NULL, NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailablePropertiesFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (TDM_ERROR_NONE == tdm_output_get_available_properties(output, NULL, NULL)) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailablePropertiesFailNullCount)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        const tdm_prop *tdm_prop_array = NULL;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (TDM_ERROR_NONE == tdm_output_get_available_properties(output,
+                                                                                                                                                          &tdm_prop_array,
+                                                                                                                                                          NULL)) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailablePropertiesFailNullProperty)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        int count = -42;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (TDM_ERROR_NONE == tdm_output_get_available_properties(output,
+                                                                                                                                                          NULL,
+                                                                                                                                                          &count)) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailableModesSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int count = -42;
+               const tdm_output_mode *modes_array = (const tdm_output_mode *) 0xBEAF;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_available_modes(output,
+                                                                                                                                        &modes_array,
+                                                                                                                                        &count));
+               ASSERT_NE(count, -42);
+               ASSERT_NE(modes_array, 0xBEAF);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetAvailableModesFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_available_modes(NULL, NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailableModesFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (TDM_ERROR_NONE == tdm_output_get_available_modes(output, NULL, NULL)) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailableModesFailNullCount)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        const tdm_output_mode *modes_array = NULL;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (TDM_ERROR_NONE == tdm_output_get_available_modes(output,
+                                                                                                                                                 &modes_array,
+                                                                                                                                                 NULL)) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailableModesFailNullModes)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        int count = -42;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (TDM_ERROR_NONE == tdm_output_get_available_modes(output,
+                                                                                                                                                 NULL,
+                                                                                                                                                 &count)) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailableSizeSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int min_w = -42, min_h = -42, max_w = -42, max_h = -42, preferred_align = -42;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_available_size(output, &min_w, &min_h,
+                                                                                                                                       &max_w, &max_h, &preferred_align));
+               ASSERT_NE(min_w, -42);
+               ASSERT_NE(min_h, -42);
+               ASSERT_NE(max_w, -42);
+               ASSERT_NE(max_h, -42);
+               ASSERT_NE(preferred_align, -42);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetAvailableSizeFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_available_size(NULL, NULL, NULL,
+                                                                                                  NULL, NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetAvailableSizeSuccessfulOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_available_size(output, NULL, NULL,
+                                                                                                               NULL, NULL, NULL) != TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+/*TODO: this test has to be fixed in the backends by increase the ABI version upper than 1.5*/
+TEST_F(TDMOutput, DISABLED_OutputGetCursorAvailableSizeSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int min_w = -42, min_h = -42, max_w = -42, max_h = -42, preferred_align = -42;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_cursor_available_size(output, &min_w, &min_h,
+                                                                                                                                                  &max_w, &max_h, &preferred_align));
+               ASSERT_NE(min_w, -42);
+               ASSERT_NE(min_h, -42);
+               ASSERT_NE(max_w, -42);
+               ASSERT_NE(max_h, -42);
+               ASSERT_NE(preferred_align, -42);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetCursorAvailableSizeFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_cursor_available_size(NULL, NULL, NULL,
+                                                                                                                 NULL, NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+/*TODO: this test has to be fixed in the backends by increase the ABI version upper than 1.5*/
+TEST_F(TDMOutput, DISABLED_OutputGetCursorAvailableSizeSuccessfulOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_cursor_available_size(output, NULL, NULL,
+                                                                                                                         NULL, NULL, NULL) != TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPhysicalSizeSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               unsigned int mmWidth = UINT_MAX, mmHeight = UINT_MAX;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_physical_size(output, &mmWidth, &mmHeight));
+               ASSERT_NE(mmWidth, UINT_MAX);
+               ASSERT_NE(mmHeight, UINT_MAX);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetPhysicalSizeFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_physical_size(NULL, NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPhysicalSuccessfulOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_physical_size(output, NULL, NULL) != TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetSubpixelSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               unsigned int subpixel = UINT_MAX;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_subpixel(output, &subpixel));
+               ASSERT_NE(subpixel, UINT_MAX);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetSubpixelFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_subpixel(NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetSubpixelFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_subpixel(output, NULL) == TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPipeSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               unsigned int pipe = UINT_MAX;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_pipe(output, &pipe));
+               ASSERT_NE(pipe, UINT_MAX);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetPipeFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_pipe(NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPipeFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_pipe(output, NULL) == TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPrimaryIndexSuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               int primary_index = INT_MAX;
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_get_primary_index(output, &primary_index));
+               ASSERT_NE(primary_index, INT_MAX);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetPrimaryIndexFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({if (tdm_output_get_primary_index(NULL, NULL) == TDM_ERROR_NONE) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPrimaryIndexFailOnlyOutput)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({for (int i = 0; i < output_count; i++) {
+                                        tdm_error error = TDM_ERROR_NONE;
+                                        tdm_output * output = tdm_display_get_output(dpy, i, &error);
+                                        if (NULL == output) exit(1);
+                                        if (TDM_ERROR_NONE != error) exit(1);
+                                        if (tdm_output_get_primary_index(output, NULL) == TDM_ERROR_NONE) exit(1);
+                               }
+                               exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputSetPropertySuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               tdm_value value = {.u32 = 0};
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               error = tdm_output_set_property(output, UINT_MAX, value);
+               ASSERT_TRUE(error == TDM_ERROR_NOT_IMPLEMENTED || error == TDM_ERROR_OPERATION_FAILED);
+       }
+}
+
+TEST_F(TDMOutput, OutputSetPropertyFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({tdm_error error = TDM_ERROR_NONE;
+                                tdm_value value = {.u32 = 0};
+                                error = tdm_output_set_property(NULL, 0, value);
+                                if (error == TDM_ERROR_NONE || error == TDM_ERROR_NOT_IMPLEMENTED ||
+                                       error == TDM_ERROR_OPERATION_FAILED) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutput, OutputGetPropertySuccessful)
+{
+       SKIP_FLAG(has_output);
+       for (int i = 0; i < output_count; i++) {
+               tdm_error error = TDM_ERROR_NONE;
+               tdm_value value = {.u32 = 0};
+               tdm_output * output = tdm_display_get_output(dpy, i, &error);
+               ASSERT_FALSE(NULL == output);
+               ASSERT_TRUE(TDM_ERROR_NONE == error);
+               error = tdm_output_get_property(output, UINT_MAX, &value);
+               ASSERT_TRUE(error == TDM_ERROR_NOT_IMPLEMENTED || error == TDM_ERROR_NONE);
+       }
+}
+
+TEST_F(TDMOutput, OutputGetPropertyFailNullAll)
+{
+       SKIP_FLAG(has_output);
+       ASSERT_EXIT({tdm_error error = TDM_ERROR_NONE;
+                                error = tdm_output_get_property(NULL, 0, NULL);
+                                if (error == TDM_ERROR_NONE || error == TDM_ERROR_NOT_IMPLEMENTED ||
+                                        error == TDM_ERROR_OPERATION_FAILED) exit(1);
+                                exit(0);}, ::testing::ExitedWithCode(0), "");
+}
+
+TEST_F(TDMOutputCommit, OutputCommitFailNullAll)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(NULL, 0, NULL, NULL));
+}
+
+TEST_F(TDMOutputCommit, OutputCommit)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+}
+
+TEST_F(TDMOutputCommitThread, OutputCommit)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+}
+
+TEST_F(TDMOutputCommitPerVblankEnabled, OutputCommitFailLayerCommit)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (size_t i = 0; i < layers_array.size(); ++i) {
+               for (tdm_layer *layer : layers_array[i]) {
+                       tdm_layer_commit(layer, NULL, NULL);
+               }
+       }
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+}
+
+TEST_F(TDMOutputCommitPerVblankEnabled, OutputCommitFailCommitPerVblankEnabled)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+}
+
+TEST_F(TDMOutputCommit, OutputCommitFailDpmsOff)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++) {
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(connected_output_array[i], TDM_OUTPUT_DPMS_OFF));
+
+               ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+       }
+}
+
+TEST_F(TDMOutputCommit, OutputWaitVBlankFailNullAll)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_wait_vblank(nullptr, 1, 0, nullptr, nullptr));
+}
+
+TEST_F(TDMOutputCommit, OutputWaitVBlankFailDpmsOff)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++) {
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(connected_output_array[i], TDM_OUTPUT_DPMS_OFF));
+
+               for (int i = 0; i < conn_output_count; i++)
+                       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_wait_vblank(connected_output_array[i], 1, 0, UtOutputVblankHandler, nullptr));
+       }
+}
+
+TEST_F(TDMOutputCommit, OutputWaitVBlank)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, nullptr));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_wait_vblank(connected_output_array[i], 1, 0, UtOutputVblankHandler, nullptr));
+
+       UtHandleVblankEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputVblankHandlerCounter);
+}
+
+TEST_F(TDMOutputCommitThread, OutputWaitVBlank)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_wait_vblank(connected_output_array[i], 1, 0, UtOutputVblankHandler, NULL));
+
+       UtHandleVblankEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputVblankHandlerCounter);
+}
+
+TEST_F(TDMOutputCommit, OutputRemoveVblankHandlerFailNullAll)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_remove_vblank_handler(nullptr, nullptr, nullptr));
+}
+
+TEST_F(TDMOutputCommitThread, OutputRemoveVblankHandlerSuccess)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       UtHandleCommitEvent();
+
+       ASSERT_EQ(conn_output_count, utOutputCommitHandlerCounter);
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_wait_vblank(connected_output_array[i], 2, 0, UtOutputVblankHandler, NULL));
+
+       for (int i = 0; i < conn_output_count; i++) {
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_remove_vblank_handler(connected_output_array[i], UtOutputVblankHandler, NULL));
+       }
+
+       UtHandleVblankEvent();
+
+       ASSERT_EQ(0, utOutputVblankHandlerCounter);
+}
+
+TEST_F(TDMOutputCommit, OutputRemoveCommitHandlerFailNullAll)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_TRUE(TDM_ERROR_NONE != tdm_output_remove_commit_handler(nullptr, nullptr, nullptr));
+}
+
+TEST_F(TDMOutputCommitThread, OutputRemoveCommitHandlerSuccess)
+{
+       SKIP_FLAG(has_output);
+
+       ASSERT_NO_FATAL_FAILURE(UtPrepareToCommit());
+
+       for (int i = 0; i < conn_output_count; i++)
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, UtOutputCommitHandler, NULL));
+
+       for (int i = 0; i < conn_output_count; i++) {
+               ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_remove_commit_handler(connected_output_array[i], UtOutputCommitHandler, NULL));
+       }
+
+       UtHandleCommitEvent();
 }