build FEATURE provide locally generated code coverage report

adds build target coverage to generate code coverage report
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index e8e1395..e7b4e8b 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -9,6 +9,34 @@
     find_program(VALGRIND_FOUND valgrind)
 endif()
 
+if(ENABLE_COVERAGE)
+    find_program(PATH_GCOV NAMES gcov)
+    if(NOT PATH_GCOV)
+        message(WARNING "'gcov' executable not found! Disabling building code coverage report.")
+        set(ENABLE_COVERAGE OFF)
+    endif()
+
+    find_program(PATH_LCOV NAMES lcov)
+    if(NOT PATH_GCOV)
+        message(WARNING "'lcov' executable not found! Disabling building code coverage report.")
+        set(ENABLE_COVERAGE OFF)
+    endif()
+
+    find_program(PATH_GENHTML NAMES genhtml)
+    if(NOT PATH_GCOV)
+        message(WARNING "'genhtml' executable not found! Disabling building code coverage report.")
+        set(ENABLE_COVERAGE OFF)
+    endif()
+
+    if(NOT CMAKE_COMPILER_IS_GNUCC)
+        message(WARNING "Compiler is not gcc/g++! Building code coverage report may not work!")
+    endif()
+
+    if(ENABLE_COVERAGE)
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -fprofile-arcs -ftest-coverage")
+    endif()
+endif()
+
 configure_file("${PROJECT_SOURCE_DIR}/tests/config.h.in" "${PROJECT_BINARY_DIR}/tests/config.h" ESCAPE_QUOTES @ONLY)
 include_directories(SYSTEM ${CMOCKA_INCLUDE_DIR})
 include_directories(${PROJECT_BINARY_DIR})
@@ -49,4 +77,49 @@
     else(VALGRIND_FOUND)
         message(WARNING "valgrind executable not found! Disabling memory leaks tests.")
     endif(VALGRIND_FOUND)
-endif()
\ No newline at end of file
+endif()
+
+if(ENABLE_COVERAGE)
+    # Destination
+    set(COVERAGE_DIR        "${CMAKE_BINARY_DIR}/tests/code_coverage/")
+    set(COVERAGE_FILE_RAW   "${CMAKE_BINARY_DIR}/tests/coverage_raw.info")
+    set(COVERAGE_FILE_CLEAN "${CMAKE_BINARY_DIR}/tests/coverage_clean.info")
+
+    # Add coverage target
+    add_custom_target(coverage
+        COMMENT "Generating code coverage..."
+        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests"
+        # Cleanup code counters
+        COMMAND "${PATH_LCOV}" --directory . --zerocounters --quiet
+
+        # Run tests
+        COMMAND "${CMAKE_CTEST_COMMAND}" --quiet
+
+        # Capture the counters
+        COMMAND "${PATH_LCOV}"
+            --directory .
+            --rc lcov_branch_coverage=1
+            --rc 'lcov_excl_line=assert'
+            --capture --quiet
+            --output-file "${COVERAGE_FILE_RAW}"
+        # Remove coverage of tests, system headers, etc.
+        COMMAND "${PATH_LCOV}"
+            --remove "${COVERAGE_FILE_RAW}" '${CMAKE_BINARY_DIR}/*' '${CMAKE_BINARY_DIR}/tests/*' '/usr/*'
+            --rc lcov_branch_coverage=1
+            --quiet --output-file "${COVERAGE_FILE_CLEAN}"
+        # Generate HTML report
+        COMMAND "${PATH_GENHTML}"
+            --branch-coverage --function-coverage --quiet --title "libyang"
+            --legend --show-details --output-directory "${COVERAGE_DIR}"
+            "${COVERAGE_FILE_CLEAN}"
+        # Delete the counters
+        COMMAND "${CMAKE_COMMAND}" -E remove
+            ${COVERAGE_FILE_RAW} ${COVERAGE_FILE_CLEAN}
+        )
+
+    add_custom_command(TARGET coverage POST_BUILD
+        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/tests"
+        COMMENT "To see the code coverage report, open ${COVERAGE_DIR}index.html"
+        COMMAND ;
+        )
+endif()