tests FEATURE include tests into build system

basic tests of ly_set implementation
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0202a3a..6827dc0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,19 +21,19 @@
     set(CMAKE_BUILD_TYPE debug)
 endif()
 
-set(CMAKE_C_FLAGS         "${CMAKE_C_FLAGS} -Wall -Wextra -std=c89")
+set(CMAKE_C_FLAGS         "${CMAKE_C_FLAGS} -Wall -Wextra -std=c99")
 set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
 set(CMAKE_C_FLAGS_PACKAGE "-g -O2 -DNDEBUG")
 set(CMAKE_C_FLAGS_DEBUG   "-g -O0")
 
 # options
-#if((CMAKE_BUILD_TYPE STREQUAL debug) OR (CMAKE_BUILD_TYPE STREQUAL Package))
-#    option(ENABLE_BUILD_TESTS "Build tests" ON)
-#    option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" ON)
-#else()
-#    option(ENABLE_BUILD_TESTS "Build tests" OFF)
-#    option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
-#endif()
+if((CMAKE_BUILD_TYPE STREQUAL debug) OR (CMAKE_BUILD_TYPE STREQUAL Package))
+    option(ENABLE_BUILD_TESTS "Build tests" ON)
+    option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" ON)
+else()
+    option(ENABLE_BUILD_TESTS "Build tests" OFF)
+    option(ENABLE_VALGRIND_TESTS "Build tests with valgrind" OFF)
+endif()
 #option(ENABLE_CALLGRIND_TESTS "Build performance tests to be run with callgrind" OFF)
 
 #option(ENABLE_CACHE "Enable data caching for schemas and hash tables for data (time-efficient at the cost of increased space-complexity)" ON)
@@ -270,12 +270,12 @@
 # YANG extensions plugins
 #set(EXTENSIONS_LIST "nacm" "metadata" "yangdata")
 # if the tests are enabled, build libyang_ext_test
-#if(ENABLE_BUILD_TESTS)
-#    find_package(CMocka 1.0.0)
+if(ENABLE_BUILD_TESTS)
+    find_package(CMocka 1.0.0)
 #    if(CMOCKA_FOUND AND CMAKE_BUILD_TYPE MATCHES debug)
 #        list(APPEND EXTENSIONS_LIST "libyang_ext_test")
 #    endif(CMOCKA_FOUND AND CMAKE_BUILD_TYPE MATCHES debug)
-#endif(ENABLE_BUILD_TESTS)
+endif(ENABLE_BUILD_TESTS)
 
 #if(ENABLE_STATIC)
 #    set(EXTENSIONS_LIST_SIZE " 0 ")
@@ -327,19 +327,19 @@
 # yang2yin
 #add_executable(yang2yin ${yang2yinsrc})
 
-#if(ENABLE_VALGRIND_TESTS)
-#    set(ENABLE_BUILD_TESTS ON)
-#endif()
+if(ENABLE_VALGRIND_TESTS)
+    set(ENABLE_BUILD_TESTS ON)
+endif()
 
-#if(ENABLE_BUILD_TESTS)
-#    if(CMOCKA_FOUND)
-#        enable_testing()
-#        add_subdirectory(tests)
-#    else(CMOCKA_FOUND)
-#        message(STATUS "Disabling tests because of missing CMocka")
-#        set(ENABLE_BUILD_TESTS NO)
-#    endif(CMOCKA_FOUND)
-#endif(ENABLE_BUILD_TESTS)
+if(ENABLE_BUILD_TESTS)
+    if(CMOCKA_FOUND)
+        enable_testing()
+        add_subdirectory(tests)
+    else(CMOCKA_FOUND)
+        message(STATUS "Disabling tests because of missing CMocka")
+        set(ENABLE_BUILD_TESTS NO)
+    endif(CMOCKA_FOUND)
+endif(ENABLE_BUILD_TESTS)
 
 #if(GEN_LANGUAGE_BINDINGS AND GEN_CPP_BINDINGS)
 #    add_subdirectory(swig)
diff --git a/CMakeModules/FindCMocka.cmake b/CMakeModules/FindCMocka.cmake
new file mode 100644
index 0000000..2dd9fc5
--- /dev/null
+++ b/CMakeModules/FindCMocka.cmake
@@ -0,0 +1,49 @@
+# - Try to find CMocka
+# Once done this will define
+#
+#  CMOCKA_ROOT_DIR - Set this variable to the root installation of CMocka
+#
+# Read-Only variables:
+#  CMOCKA_FOUND - system has CMocka
+#  CMOCKA_INCLUDE_DIR - the CMocka include directory
+#  CMOCKA_LIBRARIES - Link these to use CMocka
+#  CMOCKA_DEFINITIONS - Compiler switches required for using CMocka
+#
+#=============================================================================
+#  Copyright (c) 2011-2012 Andreas Schneider <asn@cryptomilk.org>
+#
+#  Distributed under the OSI-approved BSD License (the "License");
+#  see accompanying file Copyright.txt for details.
+#
+#  This software is distributed WITHOUT ANY WARRANTY; without even the
+#  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  See the License for more information.
+#=============================================================================
+#
+
+find_path(CMOCKA_INCLUDE_DIR
+    NAMES
+        cmocka.h
+    PATHS
+        ${CMOCKA_ROOT_DIR}/include
+)
+
+find_library(CMOCKA_LIBRARY
+    NAMES
+        cmocka
+    PATHS
+        ${CMOCKA_ROOT_DIR}/include
+)
+
+if (CMOCKA_LIBRARY)
+  set(CMOCKA_LIBRARIES
+      ${CMOCKA_LIBRARIES}
+      ${CMOCKA_LIBRARY}
+  )
+endif (CMOCKA_LIBRARY)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CMocka DEFAULT_MSG CMOCKA_LIBRARIES CMOCKA_INCLUDE_DIR)
+
+# show the CMOCKA_INCLUDE_DIR and CMOCKA_LIBRARIES variables only in the advanced view
+mark_as_advanced(CMOCKA_INCLUDE_DIR CMOCKA_LIBRARIES)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..5cd8733
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,46 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+# Correct RPATH usage on OS X
+set(CMAKE_MACOSX_RPATH TRUE)
+
+# Set TESTS_DIR to realpath
+#get_filename_component(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests" REALPATH)
+
+if(ENABLE_STATIC AND ENABLE_VALGRIND_TESTS)
+    message(WARNING "Can't run C valgrind tests on a static build")
+else()
+    find_program(VALGRIND_FOUND valgrind)
+endif()
+
+include_directories(SYSTEM ${CMOCKA_INCLUDE_DIR})
+
+set(tests)
+add_subdirectory(src)
+
+foreach(test_name IN LISTS tests)
+    string(REGEX REPLACE "[a-z]*_" "" name "${test_name}")
+    string(REGEX REPLACE "([a-z]*)_.*" "\\1" prefix "${test_name}")
+    add_executable(${test_name} ${prefix}/${name}.c)
+endforeach(test_name)
+
+# Set common attributes of all tests
+foreach(test_name IN LISTS tests)
+    target_link_libraries(${test_name} ${CMOCKA_LIBRARIES} yang)
+    add_test(NAME ${test_name} COMMAND ${test_name})
+#    set_property(TEST ${test_name} PROPERTY ENVIRONMENT "LIBYANG_EXTENSIONS_PLUGINS_DIR=${CMAKE_BINARY_DIR}/src/extensions")
+#    set_property(TEST ${test_name} APPEND PROPERTY ENVIRONMENT "LIBYANG_USER_TYPES_PLUGINS_DIR=${CMAKE_BINARY_DIR}/src/user_types")
+    set_property(TEST ${test_name} APPEND PROPERTY ENVIRONMENT "MALLOC_CHECK_=3")
+endforeach(test_name)
+
+if(ENABLE_VALGRIND_TESTS)
+    if(VALGRIND_FOUND)
+        foreach(test_name IN LISTS tests)
+            add_test(${test_name}_valgrind valgrind --leak-check=full --show-leak-kinds=all --suppressions=${PROJECT_SOURCE_DIR}/tests/ld.supp --error-exitcode=1
+                 ${CMAKE_BINARY_DIR}/tests/${test_name})
+#            set_property(TEST ${test_name}_valgrind PROPERTY ENVIRONMENT "LIBYANG_EXTENSIONS_PLUGINS_DIR=${CMAKE_BINARY_DIR}/src/extensions")
+#            set_property(TEST ${test_name}_valgrind APPEND PROPERTY ENVIRONMENT "LIBYANG_USER_TYPES_PLUGINS_DIR=${CMAKE_BINARY_DIR}/src/user_types")
+        endforeach(test_name)
+    else(VALGRIND_FOUND)
+        message(WARNING "valgrind executable not found! Disabling memory leaks tests.")
+    endif(VALGRIND_FOUND)
+endif()
\ No newline at end of file
diff --git a/tests/ld.supp b/tests/ld.supp
new file mode 100644
index 0000000..53876b6
--- /dev/null
+++ b/tests/ld.supp
@@ -0,0 +1,10 @@
+{
+   <insert_a_suppression_name_here>
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:calloc
+   fun:_dlerror_run
+   fun:dlopen@@GLIBC_2.2.5
+   fun:lyext_load_plugins
+   fun:ly_ctx_new
+}
diff --git a/tests/src/CMakeLists.txt b/tests/src/CMakeLists.txt
new file mode 100644
index 0000000..56eefd6
--- /dev/null
+++ b/tests/src/CMakeLists.txt
@@ -0,0 +1,2 @@
+set(local_tests src_set)
+set(tests ${tests} ${local_tests} PARENT_SCOPE)
diff --git a/tests/src/set.c b/tests/src/set.c
new file mode 100644
index 0000000..28b6f59
--- /dev/null
+++ b/tests/src/set.c
@@ -0,0 +1,147 @@
+/*
+ * @file set.c
+ * @author: Radek Krejci <rkrejci@cesnet.cz>
+ * @brief unit tests for functions from set.c
+ *
+ * Copyright (c) 2018 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#define _BSD_SOURCE
+#define _DEFAULT_SOURCE
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <string.h>
+
+#include "libyang.h"
+#include "../../src/set.c"
+
+#define BUFSIZE 1024
+char logbuf[BUFSIZE] = {0};
+
+static void
+logger(LY_LOG_LEVEL level, const char *msg, const char *path)
+{
+    (void) level; /* unused */
+    (void) path; /* unused */
+
+    strncpy(logbuf, msg, BUFSIZE - 1);
+}
+
+static int
+logger_setup(void **state)
+{
+    (void) state; /* unused */
+
+    ly_set_log_clb(logger, 0);
+
+    return 0;
+}
+
+static void
+test_basics(void **state)
+{
+    (void) state; /* unused */
+
+    struct ly_set *set;
+    char *str;
+    unsigned int u;
+    void *ptr;
+
+    /* creation - everything is empty */
+    set = ly_set_new();
+    assert_non_null(set);
+    assert_int_equal(0, set->count);
+    assert_int_equal(0, set->size);
+    assert_null(set->objs);
+
+    /* add a testing object */
+    str = strdup("test string");
+    assert_non_null(str);
+
+    ly_set_add(set, str, 0);
+    assert_int_not_equal(0, set->size);
+    assert_int_equal(1, set->count);
+    assert_non_null(set->objs);
+    assert_non_null(set->objs[0]);
+
+    /* check the presence of the testing data */
+    assert_int_equal(0, ly_set_contains(set, str));
+    assert_int_equal(-1, ly_set_contains(set, str - 1));
+
+    /* remove data, but keep the set */
+    u = set->size;
+    ptr = set->objs;
+    ly_set_clean(set, free);
+    assert_int_equal(0, set->count);
+    assert_int_equal(u, set->size);
+    assert_ptr_equal(ptr, set->objs);
+
+    /* remove buffer, but keep the set object */
+    ly_set_erase(set, NULL);
+    assert_int_equal(0, set->count);
+    assert_int_equal(0, set->size);
+    assert_ptr_equal(NULL, set->objs);
+
+    /* final cleanup */
+    ly_set_free(set, NULL);
+}
+
+static void
+test_inval(void **state)
+{
+    struct ly_set set;
+    memset(&set, 0, sizeof set);
+
+    ly_set_clean(NULL, NULL);
+    assert_string_equal(logbuf, "Invalid argument set (ly_set_clean()).");
+
+    ly_set_erase(NULL, NULL);
+    assert_string_equal(logbuf, "Invalid argument set (ly_set_erase()).");
+
+    ly_set_free(NULL, NULL);
+    assert_string_equal(logbuf, "Invalid argument set (ly_set_free()).");
+
+    assert_null(ly_set_dup(NULL));
+    assert_string_equal(logbuf, "Invalid argument set (ly_set_dup()).");
+
+    assert_int_equal(-1, ly_set_add(NULL, NULL, 0));
+    assert_string_equal(logbuf, "Invalid argument set (ly_set_add()).");
+    assert_int_equal(-1, ly_set_add(&set, NULL, 0));
+    assert_string_equal(logbuf, "Invalid argument object (ly_set_add()).");
+
+    assert_int_equal(-1, ly_set_merge(NULL, NULL, 0));
+    assert_string_equal(logbuf, "Invalid argument trg (ly_set_merge()).");
+    assert_int_equal(0, ly_set_merge(&set, NULL, 0));
+    assert_string_equal(logbuf, "Invalid argument src (ly_set_merge()).");
+
+    assert_int_equal(LY_EINVAL, ly_set_rm_index(NULL, 0));
+    assert_string_equal(logbuf, "Invalid argument set (ly_set_rm_index()).");
+    assert_int_equal(LY_EINVAL, ly_set_rm_index(&set, 1));
+    assert_string_equal(logbuf, "Invalid argument index (ly_set_rm_index()).");
+
+    assert_int_equal(LY_EINVAL, ly_set_rm(NULL, NULL));
+    assert_string_equal(logbuf, "Invalid argument set (ly_set_rm()).");
+    assert_int_equal(LY_EINVAL, ly_set_rm(&set, NULL));
+    assert_string_equal(logbuf, "Invalid argument object (ly_set_rm()).");
+    assert_int_equal(LY_EINVAL, ly_set_rm(&set, &state));
+    assert_string_equal(logbuf, "Invalid argument object (ly_set_rm()).");
+}
+
+int main(void)
+{
+    const struct CMUnitTest tests[] = {
+        cmocka_unit_test(test_basics),
+        cmocka_unit_test_setup(test_inval, logger_setup),
+    };
+
+    return cmocka_run_group_tests(tests, NULL, NULL);
+}