diff --git a/.travis.yml b/.travis.yml
index a1a17f61..b8699ec1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,6 +23,8 @@ before_script:
- sudo ldconfig
# installing sphinx, needed for documentation
- sudo apt-get install python-sphinx
+# installing check, needed for unit tests
+ - sudo apt-get install check
script:
- mkdir build && cd build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f56cd67a..a5e1196b 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -53,3 +53,4 @@ add_subdirectory(core)
add_subdirectory(testing)
add_subdirectory(other)
add_subdirectory(docs)
+add_subdirectory(auto_tests)
diff --git a/INSTALL.md b/INSTALL.md
index 8c7147fa..1ee1c66f 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -16,14 +16,14 @@
Build dependencies:
```bash
-apt-get install build-essential libtool autotools-dev automake libconfig-dev ncurses-dev cmake checkinstall
+apt-get install build-essential libtool autotools-dev automake libconfig-dev ncurses-dev cmake checkinstall check
```
On Fedora:
```bash
yum groupinstall "Development Tools"
-yum install libtool autoconf automake libconfig-devel ncurses-devel cmake
+yum install libtool autoconf automake libconfig-devel ncurses-devel cmake check
```
Note that `libconfig-dev` should be >= 1.4.
@@ -91,7 +91,7 @@ There are no binaries/executables going to /bin/ or /usr/bin/ now. Everything is
####Homebrew:
```
-brew install libtool automake autoconf libconfig libsodium cmake
+brew install libtool automake autoconf libconfig libsodium cmake check
cmake .
make
```
@@ -106,6 +106,7 @@ Grab the following packages:
* http://www.cmake.org/
* https://github.com/jedisct1/libsodium
* http://www.hyperrealm.com/libconfig/
+ * http://check.sourceforge.net/
Uncompress and install them all. Make sure to follow the README as the instructions change, but they all follow the same pattern below:
@@ -135,6 +136,7 @@ http://caiustheory.com/install-gcc-421-apple-build-56663-with-xcode-42
You should install:
- [MinGW](http://sourceforge.net/projects/mingw/)'s C compiler
- [CMake](http://www.cmake.org/cmake/resources/software.html)
+ - [check] (http://check.sourceforge.net/)
You have to [modify your PATH environment variable](http://www.computerhope.com/issues/ch000549.htm) so that it contains MinGW's bin folder path. With default settings, the bin folder is located at `C:\MinGW\bin`, which means that you would have to append `;C:\MinGW\bin` to the PATH variable.
diff --git a/auto_tests/CMakeLists.txt b/auto_tests/CMakeLists.txt
new file mode 100644
index 00000000..237dae1b
--- /dev/null
+++ b/auto_tests/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.6.0)
+cmake_policy(SET CMP0011 NEW)
+
+include_directories(${CHECK_INCLUDE_DIRS})
+
+find_package(Check REQUIRED)
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/messenger_test.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/friends_test.cmake)
diff --git a/auto_tests/cmake/friends_test.cmake b/auto_tests/cmake/friends_test.cmake
new file mode 100644
index 00000000..5c2d0fc6
--- /dev/null
+++ b/auto_tests/cmake/friends_test.cmake
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.6.0)
+project(friends_test C)
+set(exe_name friends_test)
+
+add_executable(${exe_name}
+ friends_test.c)
+
+linkCoreLibraries(${exe_name})
+add_dependencies(${exe_name} Check)
+target_link_libraries(${exe_name} check)
diff --git a/auto_tests/cmake/messenger_test.cmake b/auto_tests/cmake/messenger_test.cmake
new file mode 100644
index 00000000..084586bb
--- /dev/null
+++ b/auto_tests/cmake/messenger_test.cmake
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.6.0)
+project(messenger_test C)
+set(exe_name messenger_test)
+
+add_executable(${exe_name}
+ messenger_test.c)
+
+linkCoreLibraries(${exe_name})
+add_dependencies(${exe_name} Check)
+target_link_libraries(${exe_name} check)
diff --git a/auto_tests/friends_test.c b/auto_tests/friends_test.c
new file mode 100755
index 00000000..4f777ab5
--- /dev/null
+++ b/auto_tests/friends_test.c
@@ -0,0 +1,217 @@
+/* Unit testing for friend requests, statuses, and messages.
+ * Purpose: Check that messaging functions actually do what
+ * they're supposed to by setting up two local clients.
+ *
+ * Design: (Subject to change.)
+ * 1. Parent sends a friend request, and waits for a response.
+ * It it doesn't get one, it kills the child.
+ * 2. Child gets friend request, accepts, then waits for a status change.
+ * 3. The parent waits on a status change, killing the child if it takes
+ * too long.
+ * 4. The child gets the status change, then sends a message. After that,
+ * it returns. If if doesn't get the status change, it just loops forever.
+ * 5. After getting the status change, the parent waits for a message, on getting
+ * one, it waits on the child to return, then returns 0.
+ *
+ * Note about "waiting":
+ * Wait time is decided by WAIT_COUNT and WAIT_TIME. c_sleep(WAIT_TIME) WAIT_COUNT
+ * times. This is used both to ensure that we don't loop forever on a broken build,
+ * and that we don't get too slow with messaging. The current time is 15 seconds. */
+
+#include "../core/friend_requests.h"
+#include "../core/Messenger.h"
+#include
+#include
+#include
+#include
+#include
+
+#define WAIT_COUNT 30
+#define WAIT_TIME 500
+
+/* first step, second step */
+#define FIRST_FLAG 0x1
+#define SECOND_FLAG 0x2
+
+/* ensure that we sleep in milliseconds */
+#ifdef WIN32
+#define c_sleep(x) Sleep(x)
+#else
+#define c_sleep(x) usleep(1000*x)
+#endif
+
+uint8_t *parent_id = NULL;
+uint8_t *child_id = NULL;
+
+pid_t child_pid = 0;
+int request_flags = 0;
+
+void do_tox(void)
+{
+ static int dht_on = 0;
+
+ if(!dht_on && DHT_isconnected()) {
+ dht_on = 1;
+ } else if(dht_on && !DHT_isconnected()) {
+ dht_on = 0;
+ }
+
+ doMessenger();
+}
+
+void parent_confirm_message(int num, uint8_t *data, uint16_t length)
+{
+ puts("OK");
+ request_flags |= SECOND_FLAG;
+}
+
+void parent_confirm_status(int num, USERSTATUS_KIND status, uint8_t *data, uint16_t length)
+{
+ puts("OK");
+ request_flags |= FIRST_FLAG;
+}
+
+int parent_friend_request(void)
+{
+ char *message = "Watson, come here, I need you.";
+ int len = strlen(message);
+ int i = 0;
+
+ fputs("Sending child request.", stdout);
+ fflush(stdout);
+
+ m_addfriend(child_id, (uint8_t *)message, len);
+
+ /* wait on the status change */
+ for(i = 0; i < WAIT_COUNT; i++) {
+ do_tox();
+ if(request_flags & FIRST_FLAG)
+ break;
+ fputs(".", stdout);
+ fflush(stdout);
+ c_sleep(WAIT_TIME);
+ }
+
+ if(!(request_flags & FIRST_FLAG)) {
+ fputs("\nfriends_test: The child took to long to respond!\n"
+ "Friend requests may be broken, failing build!\n", stderr);
+ kill(child_pid, SIGKILL);
+ return -1;
+ }
+
+ return 0;
+}
+
+void child_got_request(uint8_t *public_key, uint8_t *data, uint16_t length)
+{
+ fputs("OK\nsending status to parent", stdout);
+ fflush(stdout);
+ m_addfriend_norequest(public_key);
+ request_flags |= FIRST_FLAG;
+}
+
+void child_got_statuschange(int friend_num, USERSTATUS_KIND status, uint8_t *string, uint16_t length)
+{
+ request_flags |= SECOND_FLAG;
+}
+
+int parent_wait_for_message(void)
+{
+ int i = 0;
+
+ fputs("Parent waiting for message.", stdout);
+ fflush(stdout);
+
+ for(i = 0; i < WAIT_COUNT; i++) {
+ do_tox();
+ if(request_flags & SECOND_FLAG)
+ break;
+ fputs(".", stdout);
+ fflush(stdout);
+ c_sleep(WAIT_TIME);
+ }
+
+ if(!(request_flags & SECOND_FLAG)) {
+ fputs("\nParent hasn't recieved the message yet!\n"
+ "Messaging may be broken, failing the build!\n", stderr);
+ kill(child_pid, SIGKILL);
+ return -1;
+ }
+
+ return 0;
+}
+
+void cleanup(void)
+{
+ munmap(parent_id, crypto_box_PUBLICKEYBYTES);
+ munmap(child_id, crypto_box_PUBLICKEYBYTES);
+ puts("============= END TEST =============");
+}
+
+int main(int argc, char *argv[])
+{
+ puts("=========== FRIENDS_TEST ===========");
+
+ /* set up the global memory */
+ parent_id = mmap(NULL, crypto_box_PUBLICKEYBYTES, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ child_id = mmap(NULL, crypto_box_PUBLICKEYBYTES, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+ fputs("friends_test: Starting test...\n", stdout);
+ if((child_pid = fork()) == 0) {
+ /* child */
+ int i = 0;
+ char *message = "Y-yes Mr. Watson?";
+
+ initMessenger();
+ Messenger_save(child_id);
+ msync(child_id, crypto_box_PUBLICKEYBYTES, MS_SYNC);
+
+ m_callback_friendrequest(child_got_request);
+ m_callback_userstatus(child_got_statuschange);
+
+ /* wait on the friend request */
+ while(!(request_flags & FIRST_FLAG))
+ do_tox();
+
+ /* wait for the status change */
+ while(!(request_flags & SECOND_FLAG))
+ do_tox();
+
+ for(i = 0; i < 6; i++) {
+ /* send the message six times, just to be sure */
+ m_sendmessage(0, (uint8_t *)message, strlen(message));
+ do_tox();
+ }
+
+ return 0;
+ }
+
+ /* parent */
+ if(atexit(cleanup) != 0) {
+ fputs("friends_test: atexit() failed!\nFailing build...\n", stderr);
+ kill(child_pid, SIGKILL);
+ return -1;
+ }
+
+ msync(parent_id, crypto_box_PUBLICKEYBYTES, MS_SYNC);
+ m_callback_userstatus(parent_confirm_status);
+ m_callback_friendmessage(parent_confirm_message);
+
+ /* hacky way to give the child time to set up */
+ c_sleep(50);
+
+ initMessenger();
+ Messenger_save(parent_id);
+
+ if(parent_friend_request() == -1)
+ return -1;
+
+ if(parent_wait_for_message() == -1)
+ return -1;
+
+ wait(NULL);
+ fputs("friends_test: Build passed!\n", stdout);
+ return 0;
+}
diff --git a/auto_tests/messenger_test.c b/auto_tests/messenger_test.c
new file mode 100644
index 00000000..deed498f
--- /dev/null
+++ b/auto_tests/messenger_test.c
@@ -0,0 +1,279 @@
+/* unit tests for /core/Messenger.c
+ * Design:
+ * Just call every non-static function in Messenger.c, checking that
+ * they return as they should with check calls. "Bad" calls of the type
+ * function(bad_data, good_length) are _not_ checked for, this type
+ * of call is the fault of the client code.
+ *
+ * Note:
+ * None of the functions here test things that rely on the network, i.e.
+ * checking that status changes are recieved, messages can be sent, etc.
+ * All of that is done in a separate test, with two local clients running. */
+
+#include "../core/Messenger.h"
+#include
+#include
+#include
+#include
+
+#define REALLY_BIG_NUMBER ((1) << (sizeof(uint16_t) * 7))
+#define STRINGS_EQUAL(X, Y) (strcmp(X, Y) == 0)
+
+char *friend_id_str = "1145e295b0fbdc9330d5d74ec204a8bf23c315106040b4035d0d358d07ee3f7d";
+
+/* in case we need more than one ID for a test */
+char *good_id_a_str = "DB9B569D14850ED8364C3744CAC2C8FF78985D213E980C7C508D0E91E8E45441";
+char *good_id_b_str = "d3f14b6d384d8f5f2a66cff637e69f28f539c5de61bc29744785291fa4ef4d64";
+
+char *bad_id_str = "9B569D14ff637e69f2";
+
+unsigned char *friend_id = NULL;
+unsigned char *good_id_a = NULL;
+unsigned char *good_id_b = NULL;
+unsigned char *bad_id = NULL;
+
+int friend_id_num = 0;
+
+unsigned char * hex_string_to_bin(char hex_string[])
+{
+ size_t len = strlen(hex_string);
+ unsigned char *val = calloc(1, len);
+ char *pos = hex_string;
+ int i = 0;
+ for(i = 0; i < len; ++i, pos+=2)
+ sscanf(pos,"%2hhx",&val[i]);
+ return val;
+}
+
+START_TEST(test_m_sendmesage)
+{
+ char *message = "h-hi :3";
+ int good_len = strlen(message);
+ int bad_len = MAX_DATA_SIZE;
+
+
+ ck_assert(m_sendmessage(-1, (uint8_t *)message, good_len) == 0);
+ ck_assert(m_sendmessage(REALLY_BIG_NUMBER, (uint8_t *)message, good_len) == 0);
+ ck_assert(m_sendmessage(17, (uint8_t *)message, good_len) == 0);
+ ck_assert(m_sendmessage(friend_id_num, (uint8_t *)message, bad_len) == 0);
+}
+END_TEST
+
+START_TEST(test_m_get_userstatus_size)
+{
+ int rc = 0;
+ ck_assert_msg((m_get_userstatus_size(-1) == -1),
+ "m_get_userstatus_size did NOT catch an argument of -1");
+ ck_assert_msg((m_get_userstatus_size(REALLY_BIG_NUMBER) == -1),
+ "m_get_userstatus_size did NOT catch the following argument: %d\n",
+ REALLY_BIG_NUMBER);
+ rc = m_get_userstatus_size(friend_id_num);
+
+ /* this WILL error if the original m_addfriend_norequest() failed */
+ ck_assert_msg((rc > 0 && rc <= MAX_USERSTATUS_LENGTH),
+ "m_get_userstatus_size is returning out of range values!\n"
+ "(this can be caused by the error of m_addfriend_norequest"
+ " in the beginning of the suite)\n");
+}
+END_TEST
+
+START_TEST(test_m_set_userstatus)
+{
+ char *status = "online!";
+ uint16_t good_length = strlen(status);
+ uint16_t bad_length = REALLY_BIG_NUMBER;
+
+ if(m_set_userstatus(USERSTATUS_KIND_ONLINE,
+ (uint8_t *)status, bad_length) != -1)
+ ck_abort_msg("m_set_userstatus did NOT catch the following length: %d\n",
+ REALLY_BIG_NUMBER);
+
+ if((m_set_userstatus(USERSTATUS_KIND_RETAIN,
+ (uint8_t *)status, good_length)) != 0)
+ ck_abort_msg("m_set_userstatus did NOT return 0 on the following length: %d\n"
+ "MAX_USERSTATUS_LENGTH: %d\n", good_length, MAX_USERSTATUS_LENGTH);
+}
+END_TEST
+
+START_TEST(test_m_friendstatus)
+{
+ ck_assert_msg((m_friendstatus(-1) == NOFRIEND),
+ "m_friendstatus did NOT catch an argument of -1.\n");
+ ck_assert_msg((m_friendstatus(REALLY_BIG_NUMBER) == NOFRIEND),
+ "m_friendstatus did NOT catch an argument of %d.\n",
+ REALLY_BIG_NUMBER);
+}
+END_TEST
+
+START_TEST(test_m_delfriend)
+{
+ ck_assert_msg((m_delfriend(-1) == -1),
+ "m_delfriend did NOT catch an argument of -1\n");
+ ck_assert_msg((m_delfriend(REALLY_BIG_NUMBER) == -1),
+ "m_delfriend did NOT catch the following number: %d\n",
+ REALLY_BIG_NUMBER);
+}
+END_TEST
+
+START_TEST(test_m_addfriend)
+{
+ char *good_data = "test";
+ char *bad_data = "";
+
+ int good_len = strlen(good_data);
+ int bad_len = strlen(bad_data);
+ int really_bad_len = (MAX_DATA_SIZE - crypto_box_PUBLICKEYBYTES
+ - crypto_box_NONCEBYTES - crypto_box_BOXZEROBYTES
+ + crypto_box_ZEROBYTES + 100);
+
+ if(m_addfriend((uint8_t *)friend_id, (uint8_t *)good_data, really_bad_len) != FAERR_TOOLONG)
+ ck_abort_msg("m_addfriend did NOT catch the following length: %d\n", really_bad_len);
+
+ /* this will error if the original m_addfriend_norequest() failed */
+ if(m_addfriend((uint8_t *)friend_id, (uint8_t *)good_data, good_len) != FAERR_ALREADYSENT)
+ ck_abort_msg("m_addfriend did NOT catch adding a friend we already have.\n"
+ "(this can be caused by the error of m_addfriend_norequest in"
+ " the beginning of the suite)\n");
+
+ if(m_addfriend((uint8_t *)good_id_b, (uint8_t *)bad_data, bad_len) != FAERR_NOMESSAGE)
+ ck_abort_msg("m_addfriend did NOT catch the following length: %d\n", bad_len);
+
+ /* this should REALLY error */
+ if(m_addfriend((uint8_t *)bad_id, (uint8_t *)good_data, good_len) >= 0)
+ ck_abort_msg("The following ID passed through "
+ "m_addfriend without an error:\n'%s'\n", bad_id_str);
+}
+END_TEST
+
+START_TEST(test_setname)
+{
+ char *good_name = "consensualCorn";
+ int good_length = strlen(good_name);
+ int bad_length = REALLY_BIG_NUMBER;
+
+ if(setname((uint8_t *)good_name, bad_length) != -1)
+ ck_abort_msg("setname() did NOT error on %d as a length argument!\n",
+ bad_length);
+ if(setname((uint8_t *)good_name, good_length) != 0)
+ ck_abort_msg("setname() did NOT return 0 on good arguments!\n");
+}
+END_TEST
+
+START_TEST(test_getself_name)
+{
+ char *nickname = "testGallop";
+ int len = strlen(nickname);
+ char nick_check[len];
+
+ setname((uint8_t *)nickname, len);
+ getself_name((uint8_t *)nick_check);
+
+ ck_assert_msg((!STRINGS_EQUAL(nickname, nick_check)),
+ "getself_name failed to return the known name!\n"
+ "known name: %s\nreturned: %s\n", nickname, nick_check);
+}
+END_TEST
+
+/* this test is excluded for now, due to lack of a way
+ * to set a friend's status for now.
+ * ideas:
+ * if we have access to the friends list, we could
+ * just add a status manually ourselves. */
+/*
+START_TEST(test_m_copy_userstatus)
+{
+ assert(m_copy_userstatus(-1, buf, MAX_USERSTATUS_LENGTH) == -1);
+ assert(m_copy_userstatus(REALLY_BIG_NUMBER, buf, MAX_USERSTATUS_LENGTH) == -1);
+ m_copy_userstatus(friend_id_num, buf, MAX_USERSTATUS_LENGTH + 6);
+
+ assert(STRINGS_EQUAL(name_buf, friend_id_status));
+}
+END_TEST
+*/
+
+/* this test is excluded for now, due to lack of a way
+ * to set a friend's nickname for now.
+ * ideas:
+ * if we have access to the friends list, we could
+ * just add a name manually ourselves. */
+/*
+START_TEST(test_getname)
+{
+ uint8_t name_buf[MAX_NAME_LENGTH];
+
+ assert(getname(-1, name_buf) == -1);
+ assert(getname(REALLY_BIG_NUMBER, name_buf) == -1);
+
+ getname(friend_id_num, name_buf);
+ assert(name_buf[MAX_NAME_LENGTH] == '\0'); // something like this
+}
+END_TEST
+*/
+
+Suite *messenger_suite(void)
+{
+ Suite *s = suite_create("Messenger");
+
+ TCase *userstatus_size = tcase_create("userstatus_size");
+ TCase *set_userstatus = tcase_create("set_userstatus");
+ TCase *send_message = tcase_create("send_message");
+ TCase *friendstatus = tcase_create("friendstatus");
+ TCase *getself_name = tcase_create("getself_name");
+ TCase *delfriend = tcase_create("delfriend");
+ TCase *addfriend = tcase_create("addfriend");
+ TCase *setname = tcase_create("setname");
+
+ tcase_add_test(userstatus_size, test_m_get_userstatus_size);
+ tcase_add_test(set_userstatus, test_m_set_userstatus);
+ tcase_add_test(friendstatus, test_m_friendstatus);
+ tcase_add_test(getself_name, test_getself_name);
+ tcase_add_test(send_message, test_m_sendmesage);
+ tcase_add_test(delfriend, test_m_delfriend);
+ tcase_add_test(addfriend, test_m_addfriend);
+ tcase_add_test(setname, test_setname);
+
+ suite_add_tcase(s, userstatus_size);
+ suite_add_tcase(s, set_userstatus);
+ suite_add_tcase(s, friendstatus);
+ suite_add_tcase(s, send_message);
+ suite_add_tcase(s, getself_name);
+ suite_add_tcase(s, delfriend);
+ suite_add_tcase(s, addfriend);
+ suite_add_tcase(s, setname);
+
+ return s;
+}
+
+int main(int argc, char *argv[])
+{
+ Suite *messenger = messenger_suite();
+ SRunner *test_runner = srunner_create(messenger);
+ int number_failed = 0;
+
+ friend_id = hex_string_to_bin(friend_id_str);
+ good_id_a = hex_string_to_bin(good_id_a_str);
+ good_id_b = hex_string_to_bin(good_id_b_str);
+ bad_id = hex_string_to_bin(bad_id_str);
+
+ /* setup a default friend and friendnum */
+ if(m_addfriend_norequest((uint8_t *)friend_id) < 0)
+ fputs("m_addfriend_norequest() failed on a valid ID!\n"
+ "this was CRITICAL to the test, and the build WILL fail.\n"
+ "the tests will continue now...\n\n", stderr);
+
+ if((friend_id_num = getfriend_id((uint8_t *)friend_id)) < 0)
+ fputs("getfriend_id() failed on a valid ID!\n"
+ "this was CRITICAL to the test, and the build WILL fail.\n"
+ "the tests will continue now...\n\n", stderr);
+
+ srunner_run_all(test_runner, CK_NORMAL);
+ number_failed = srunner_ntests_failed(test_runner);
+
+ srunner_free(test_runner);
+ free(friend_id);
+ free(good_id_a);
+ free(good_id_b);
+ free(bad_id);
+
+ return number_failed;
+}
diff --git a/auto_tests/run_tests b/auto_tests/run_tests
new file mode 100755
index 00000000..4448b2e2
--- /dev/null
+++ b/auto_tests/run_tests
@@ -0,0 +1,5 @@
+#!/bin/bash
+# run_tests - run the current tests for tox core
+set -e
+
+./messenger_test && ./friends_test
diff --git a/cmake/FindCheck.cmake b/cmake/FindCheck.cmake
new file mode 100644
index 00000000..e9e7f4d1
--- /dev/null
+++ b/cmake/FindCheck.cmake
@@ -0,0 +1,46 @@
+# - Try to find the CHECK libraries
+# Once done this will define
+#
+# CHECK_FOUND - system has check
+# CHECK_INCLUDE_DIR - the check include directory
+# CHECK_LIBRARIES - check library
+#
+# Copyright (c) 2007 Daniel Gollub
+# Copyright (c) 2007 Bjoern Ricks
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+INCLUDE( FindPkgConfig )
+
+# Take care about check.pc settings
+PKG_SEARCH_MODULE( CHECK check )
+
+# Look for CHECK include dir and libraries
+IF( NOT CHECK_FOUND )
+
+ FIND_PATH( CHECK_INCLUDE_DIR check.h )
+
+ FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
+
+ IF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
+ SET( CHECK_FOUND 1 )
+ IF ( NOT Check_FIND_QUIETLY )
+ MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
+ ENDIF ( NOT Check_FIND_QUIETLY )
+ ELSE ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
+ IF ( Check_FIND_REQUIRED )
+ MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
+ ELSE ( Check_FIND_REQUIRED )
+ IF ( NOT Check_FIND_QUIETLY )
+ MESSAGE( STATUS "Could NOT find CHECK" )
+ ENDIF ( NOT Check_FIND_QUIETLY )
+ ENDIF ( Check_FIND_REQUIRED )
+ ENDIF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
+ENDIF( NOT CHECK_FOUND )
+
+# Hide advanced variables from CMake GUIs
+MARK_AS_ADVANCED( CHECK_INCLUDE_DIR CHECK_LIBRARIES )
+