From e51d7b992ab79a89b7d26487ec7e89641a0209ed Mon Sep 17 00:00:00 2001 From: Hayk Martirosyan Date: Sun, 18 Jan 2015 21:27:24 -0800 Subject: [PATCH] GTest suite for unit testing, improved CMakeLists --- CMakeLists.txt | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- README.md | 12 ++++++++---- test/test.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 test/test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d1cdf39..b0e1c8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,19 @@ cmake_minimum_required(VERSION 2.8.4) project(redox) -#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall -O3") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall -g -fno-omit-frame-pointer") -# set(CMAKE_VERBOSE_MAKEFILE ON) +option(library "Build Redox as a library." ON) +option(tests "Build all tests." ON) +option(examples "Build all examples." ON) + +# Use RelWithDebInfo if no configuration specified +if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo) +endif(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall") + +# Print out compiler commands +set(CMAKE_VERBOSE_MAKEFILE ON) # --------------------------------------------------------- # Source files @@ -23,35 +33,55 @@ set(SRC_ALL ${SRC_CORE}) # --------------------------------------------------------- set(LIB_REDIS hiredis ev pthread) -set(LIB_ALL ${LIB_REDIS}) + +# --------------------------------------------------------- +# Test suite +# --------------------------------------------------------- +if (tests) + + enable_testing() + find_package(GTest REQUIRED) + include_directories(${GTEST_INCLUDE_DIRS}) + + add_executable(test_redox test/test.cpp ${SRC_ALL}) + + target_link_libraries(test_redox ${LIB_REDIS} gtest) + + # So that we can run 'make test' + add_test(test_redox test_redox) + +endif() # --------------------------------------------------------- # Examples # --------------------------------------------------------- +if (examples) + + add_executable(basic examples/basic.cpp ${SRC_ALL}) + target_link_libraries(basic ${LIB_REDIS}) -add_executable(basic examples/basic.cpp ${SRC_ALL}) -target_link_libraries(basic ${LIB_REDIS}) + add_executable(basic_threaded examples/basic_threaded.cpp ${SRC_ALL}) + target_link_libraries(basic_threaded ${LIB_REDIS}) -add_executable(basic_threaded examples/basic_threaded.cpp ${SRC_ALL}) -target_link_libraries(basic_threaded ${LIB_REDIS}) + add_executable(lpush_benchmark examples/lpush_benchmark.cpp ${SRC_ALL}) + target_link_libraries(lpush_benchmark ${LIB_REDIS}) -add_executable(lpush_benchmark examples/lpush_benchmark.cpp ${SRC_ALL}) -target_link_libraries(lpush_benchmark ${LIB_REDIS}) + add_executable(speed_test_async examples/speed_test_async.cpp ${SRC_ALL}) + target_link_libraries(speed_test_async ${LIB_REDIS}) -add_executable(speed_test_async examples/speed_test_async.cpp ${SRC_ALL}) -target_link_libraries(speed_test_async ${LIB_REDIS}) + add_executable(speed_test_sync examples/speed_test_sync.cpp ${SRC_ALL}) + target_link_libraries(speed_test_sync ${LIB_REDIS}) -add_executable(speed_test_sync examples/speed_test_sync.cpp ${SRC_ALL}) -target_link_libraries(speed_test_sync ${LIB_REDIS}) + add_executable(speed_test_async_multi examples/speed_test_async_multi.cpp ${SRC_ALL}) + target_link_libraries(speed_test_async_multi ${LIB_REDIS}) -add_executable(speed_test_async_multi examples/speed_test_async_multi.cpp ${SRC_ALL}) -target_link_libraries(speed_test_async_multi ${LIB_REDIS}) + add_executable(data_types examples/data_types.cpp ${SRC_ALL}) + target_link_libraries(data_types ${LIB_REDIS}) -add_executable(data_types examples/data_types.cpp ${SRC_ALL}) -target_link_libraries(data_types ${LIB_REDIS}) + add_executable(string_v_char examples/string_vs_charp.cpp ${SRC_ALL}) + target_link_libraries(string_v_char ${LIB_REDIS}) -add_executable(string_v_char examples/string_vs_charp.cpp ${SRC_ALL}) -target_link_libraries(string_v_char ${LIB_REDIS}) + add_executable(multi_client examples/multi-client.cpp ${SRC_ALL}) + target_link_libraries(multi_client ${LIB_REDIS}) -add_executable(multi_client examples/multi-client.cpp ${SRC_ALL}) -target_link_libraries(multi_client ${LIB_REDIS}) +endif() diff --git a/README.md b/README.md index 60302b7..60c8afa 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,10 @@ Get the dependencies: sudo apt-get install libhiredis-dev libev-dev +For testing: + + sudo apt-get install libgtest-dev + Build Redox and examples using CMake (a helper script is provided): cd redox @@ -53,14 +57,14 @@ Basic synchronous usage: redox::Redox rdx = {"localhost", 6379}; // Initialize Redox rdx.start(); // Start the event loop - + rdx.del("occupation"); - + if(!rdx.set("occupation", "carpenter")) // Set a key, check if succeeded cerr << "Failed to set key!" << endl; - + cout << "key = occupation, value = \"" << rdx.get("occupation") << "\"" << endl; - + rdx.stop(); // Shut down the event loop Output: `key = occupation, value = "carpenter"` diff --git a/test/test.cpp b/test/test.cpp new file mode 100644 index 0000000..57423e8 --- /dev/null +++ b/test/test.cpp @@ -0,0 +1,110 @@ +/** +* Test suite for Redox using GTest. +*/ + +#include + +#include "../src/redox.hpp" +#include "gtest/gtest.h" + +namespace { + +using namespace redox; +using namespace std; + +// ------------------------------------------ +// The fixture for testing class Redox. +// ------------------------------------------ +class RedoxTest : public ::testing::Test { +protected: + + Redox rdx = {"localhost", 6379}; + + RedoxTest() { + rdx.start(); + } + + virtual ~RedoxTest() { + rdx.block(); + } + + // CV and counter to wait for async commands to complete + atomic_int cmd_count = {0}; + condition_variable cmd_waiter; + mutex cmd_waiter_lock; + + // To make the callback code nicer + template + using Callback = std::function; + + /** + * Helper function that returns a command callback to print out the + * command/reply and to test the reply against the provided value. + */ + template + Callback check(const ReplyT& value) { + cmd_count++; + return [this, value](const string& cmd, const ReplyT& reply) { + EXPECT_EQ(reply, value); + cmd_count--; + cmd_waiter.notify_all(); + }; + } + + /** + * Wrapper for the callback that also prints out the command. + */ + template + Callback print(Callback callback) { + return [callback](const string& cmd, const ReplyT& reply) { + cout << cmd << ": " << reply << endl; + callback(cmd, reply); + }; + } + + /** + * Combination of print and check for simplicity. + */ + template + Callback print_and_check(const ReplyT& value) { + return print(check(value)); + } + + /** + * Wait until all async commands that used check() as a callback + * complete. + */ + void wait_and_stop() { + unique_lock ul(cmd_waiter_lock); + cmd_waiter.wait(ul, [this] { return (cmd_count == 0); }); + rdx.stop_signal(); + }; +}; + +// ------------------------------------------- +// Unit tests - asynchronous +// ------------------------------------------- + +TEST_F(RedoxTest, GetSet) { + rdx.command("SET redox_test:a apple", print_and_check("OK")); + rdx.command("GET redox_test:a", print_and_check("apple")); + wait_and_stop(); +} + +TEST_F(RedoxTest, Delete) { + rdx.command("SET redox_test:b banana", print_and_check("OK")); + rdx.command("DEL redox_test:b", print_and_check(1)); + rdx.command("GET redox_test:b", check(nullptr)); + wait_and_stop(); +} + +// ------------------------------------------- +// End tests +// ------------------------------------------- + +} // namespace + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} -- libgit2 0.21.4