diff --git a/.gitignore b/.gitignore index 3ac8df7..c0b397c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -externals/udplibrary \ No newline at end of file +externals/udplibrary +build* diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d6e370..d344193 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,14 +7,12 @@ if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(FATAL_ERROR "CMake should have crashed - this is a failsafe in case the call used to trigger the crash gets fixed.") endif() -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.2 FATAL_ERROR) -project(stationapi CXX) +project(stationapi VERSION 1.0 LANGUAGES CXX) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin") -include(GroupSourceByFilesystem) include(ModernCpp) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -33,14 +31,25 @@ set(Boost_USE_MULTITHREADED ON) find_package(Boost COMPONENTS program_options REQUIRED) find_package(SQLite3 REQUIRED) -if (NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings") -endif () - add_subdirectory(externals) add_subdirectory(src) add_subdirectory(tests) -configure_file(extras/logger.cfg.dist bin/logger.cfg COPYONLY) -configure_file(extras/swgchat.cfg.dist bin/swgchat.cfg COPYONLY) -configure_file(extras/chat.db.dist bin/chat.db COPYONLY) +install(FILES + extras/logger.cfg.dist + DESTINATION etc/stationapi + RENAME logger.cfg) + +install(FILES + extras/swgchat.cfg.dist + DESTINATION etc/stationapi + RENAME swgchat.cfg) + +install(FILES + extras/stationchat.db.dist + DESTINATION var/stationapi + RENAME stationchat.db) + +install(FILES + extras/init_database.sql + DESTINATION share/stationapi) diff --git a/extras/logger.cfg.dist b/extras/logger.cfg.dist index 75648b9..c45da37 100644 --- a/extras/logger.cfg.dist +++ b/extras/logger.cfg.dist @@ -1,18 +1,18 @@ * GLOBAL: - FILENAME = "logs/swgchat.log" + FILENAME = "var/log/swgchat.log" TO_STANDARD_OUTPUT = true * TRACE: - FILENAME = "logs/swgchat.log" + FILENAME = "var/log/swgchat.log" * DEBUG: - FILENAME = "logs/swgchat.log" + FILENAME = "var/log/swgchat.log" * FATAL: - FILENAME = "logs/swgchat.log" + FILENAME = "var/log/swgchat.log" * ERROR: - FILENAME = "logs/swgchat.log" + FILENAME = "var/log/swgchat.log" * WARNING: - FILENAME = "logs/swgchat.log" + FILENAME = "var/log/swgchat.log" * INFO: - FILENAME = "logs/swgchat.log" + FILENAME = "var/log/swgchat.log" * VERBOSE: - FILENAME = "logs/verbose.%datetime{%Y%M%d_%H%m%s}.log" + FILENAME = "var/log/swgchat-verbose.%datetime{%Y%M%d_%H%m%s}.log" TO_STANDARD_OUTPUT = false diff --git a/extras/chat.db.dist b/extras/stationchat.db.dist similarity index 100% rename from extras/chat.db.dist rename to extras/stationchat.db.dist diff --git a/extras/swgchat.cfg.dist b/extras/swgchat.cfg.dist index a018b1e..494097e 100644 --- a/extras/swgchat.cfg.dist +++ b/extras/swgchat.cfg.dist @@ -11,7 +11,7 @@ registrar_address = 127.0.0.1 registrar_port = 5000 # Path to the application database -database_path = chat.db +database_path = var/stationapi/stationchat.db # When set to true, binds to the config address; otherwise, binds on any interface bind_to_ip = false diff --git a/src/stationapi/CMakeLists.txt b/src/stationapi/CMakeLists.txt index 61670ef..361ba1e 100644 --- a/src/stationapi/CMakeLists.txt +++ b/src/stationapi/CMakeLists.txt @@ -1,11 +1,5 @@ -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROJECT_SOURCE_DIR}/externals/easyloggingpp - ${PROJECT_SOURCE_DIR}/externals/udplibrary - ${Boost_INCLUDE_DIRS} - ${SQLite3_INCLUDE_DIR}) -set(SOURCES +add_library(stationapi Node.hpp NodeClient.cpp NodeClient.hpp @@ -16,6 +10,10 @@ set(SOURCES StringUtils.cpp StringUtils.hpp) -add_library(stationapi ${SOURCES}) - -GroupSourceByFilesystem("${SOURCES}") +target_include_directories(stationapi PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/externals/catch + ${PROJECT_SOURCE_DIR}/externals/easyloggingpp + ${PROJECT_SOURCE_DIR}/externals/udplibrary + ${Boost_INCLUDE_DIRS} + ${SQLite3_INCLUDE_DIR}) diff --git a/src/stationchat/CMakeLists.txt b/src/stationchat/CMakeLists.txt index 68af2a0..b2e335e 100644 --- a/src/stationchat/CMakeLists.txt +++ b/src/stationchat/CMakeLists.txt @@ -1,12 +1,5 @@ -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROJECT_SOURCE_DIR}/src/stationapi - ${PROJECT_SOURCE_DIR}/externals/easyloggingpp - ${PROJECT_SOURCE_DIR}/externals/udplibrary - ${Boost_INCLUDE_DIRS} - ${SQLite3_INCLUDE_DIR}) -set(SOURCES +add_executable(stationchat protocol/AddBan.hpp protocol/AddFriend.hpp protocol/AddIgnore.hpp @@ -69,16 +62,14 @@ set(SOURCES StationChatApp.hpp StationChatConfig.hpp) -add_executable(stationchat ${SOURCES}) - -GroupSourceByFilesystem("${SOURCES}") - target_link_libraries(stationchat stationapi udplibrary ${Boost_LIBRARIES} - ${SQLite3_LIBRARY}) + ${SQLite3_LIBRARY} + $<$:ws2_32>) -if(WIN32) - target_link_libraries(stationchat ws2_32) -endif() +target_include_directories(stationchat PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}) + +install(TARGETS stationchat RUNTIME DESTINATION bin) diff --git a/src/stationchat/main.cpp b/src/stationchat/main.cpp index 1fb3fe9..0c147cf 100644 --- a/src/stationchat/main.cpp +++ b/src/stationchat/main.cpp @@ -1,7 +1,7 @@ #define ELPP_DISABLE_DEFAULT_CRASH_HANDLING 1 -#define ELPP_DEFAULT_LOG_FILE "logs/swgchat.log" +#define ELPP_NO_DEFAULT_LOG_FILE #include "easylogging++.h" @@ -56,9 +56,9 @@ StationChatConfig BuildConfiguration(int argc, const char* argv[]) { po::options_description generic("Generic options"); generic.add_options() ("help,h", "produces help message") - ("config,c", po::value(&configFile)->default_value("swgchat.cfg"), + ("config,c", po::value(&configFile)->default_value("etc/stationapi/swgchat.cfg"), "sets path to the configuration file") - ("logger_config", po::value(&config.loggerConfig)->default_value("logger.cfg"), + ("logger_config", po::value(&config.loggerConfig)->default_value("etc/stationapi/logger.cfg"), "sets path to the logger configuration file") ; @@ -74,7 +74,7 @@ StationChatConfig BuildConfiguration(int argc, const char* argv[]) { "port for registrar connections") ("bind_to_ip", po::value(&config.bindToIp)->default_value(false), "when set to true, binds to the config address; otherwise, binds on any interface") - ("database_path", po::value(&config.chatDatabasePath)->default_value("chat.db"), + ("database_path", po::value(&config.chatDatabasePath)->default_value("var/stationapi/stationchat.db"), "path to the sqlite3 database file") ; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cdf669d..16d3794 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,7 +2,10 @@ include_directories(${PROJECT_SOURCE_DIR}/externals/catch ${PROJECT_SOURCE_DIR}/src) add_executable(stationapi_tests - main.cpp) + main.cpp + + stationapi/Serialization_Tests.cpp + stationapi/StringUtils_Tests.cpp) target_link_libraries(stationapi_tests stationapi) diff --git a/tests/stationapi/Serialization_Tests.cpp b/tests/stationapi/Serialization_Tests.cpp new file mode 100644 index 0000000..4433b86 --- /dev/null +++ b/tests/stationapi/Serialization_Tests.cpp @@ -0,0 +1,99 @@ + +#include "catch.hpp" + +#include "Serialization.hpp" + +SCENARIO("integer serialization", "[serialization]") { + GIVEN("an initialized 32bit signed integer and a binary stream") { + int32_t signedInt = -8; + std::stringstream bs(std::ios_base::out | std::ios_base::in | std::ios_base::binary); + + WHEN("the stream has the integer written to it") { + write(bs, signedInt); + + THEN("the serialized output size is increased by 4") { + REQUIRE(bs.str().length() == 4); + } + + AND_THEN("the serialized output is little-endian") { + auto str = bs.str(); + REQUIRE(str[0] == (char)0xF8); + REQUIRE(str[1] == (char)0xFF); + REQUIRE(str[2] == (char)0xFF); + REQUIRE(str[3] == (char)0xFF); + } + } + } + + GIVEN("a binary stream containing a serialized 32bit signed integer") { + int32_t signedInt = -8; + std::stringstream bs(std::ios_base::out | std::ios_base::in | std::ios_base::binary); + write(bs, signedInt); + + WHEN("the stream has the integer read from it") { + auto testInt = read(bs); + + THEN("the value read is the value expected") { + REQUIRE(testInt == signedInt); + } + } + + AND_WHEN("the stream is read into an existing integer variable") { + int32_t testInt = 0; + read(bs, testInt); + + THEN("the value read is the value expected") { + REQUIRE(testInt == signedInt); + } + } + } +} + +SCENARIO("string serialization", "[serialization]") { + GIVEN("an initialized ascii string and a binary stream") { + std::string asciiStr = "Some string value"; + std::stringstream bs(std::ios_base::out | std::ios_base::in | std::ios_base::binary); + + WHEN("the stream has an ascii string written to it") { + write(bs, asciiStr); + + THEN("the serialized output size is increased by the length of the string, plus a uint16_t string length") { + REQUIRE(bs.str().length() == asciiStr.length() + sizeof(uint16_t)); + } + + AND_THEN("the output contains a uint16_t string length, followed by the ascii string") { + auto length = peekAt(bs, 0); + REQUIRE(length == asciiStr.length()); + + auto str = bs.str(); + + REQUIRE(str[2] == asciiStr[0]); + REQUIRE(str[18] == asciiStr[16]); + } + } + } + + GIVEN("a binary string containing a serialized ascii string") { + std::string asciiStr = "Some string value"; + std::stringstream bs(std::ios_base::out | std::ios_base::in | std::ios_base::binary); + write(bs, asciiStr); + + WHEN("the stream has the string read from it") { + auto testStr = read(bs); + + THEN("the value re ad is the value expected") { + REQUIRE(testStr.compare(asciiStr) == 0); + } + } + + AND_WHEN("the stream is read into an existing string variable") { + std::string testStr; + read(bs, testStr); + + THEN("the value read is the value expected") { + REQUIRE(testStr.compare(asciiStr) == 0); + } + } + } +} + diff --git a/tests/stationapi/StringUtils_Tests.cpp b/tests/stationapi/StringUtils_Tests.cpp new file mode 100644 index 0000000..722435b --- /dev/null +++ b/tests/stationapi/StringUtils_Tests.cpp @@ -0,0 +1,43 @@ + +#include "catch.hpp" + +#include "StringUtils.hpp" + +SCENARIO("string widths can be converted to and from 8 and 16 bits", "[strings]") { + GIVEN("a narrow string initialized with text") { + std::string narrowStr = "Some string text here."; + + REQUIRE(narrowStr.length() == 22); + + WHEN("the width is converted to wide") { + auto wideStr = ToWideString(narrowStr); + + THEN("the length of the new string is the same as the narrow string") { + REQUIRE(wideStr.length() == narrowStr.length()); + } + + AND_THEN("the contents of the new string is equivalent to the narrow string") { + REQUIRE(wideStr.compare(u"Some string text here.") == 0); + } + } + + } + + GIVEN("a wide string initialized with text") { + std::u16string wideStr = u"Some string text here."; + + REQUIRE(wideStr.length() == 22); + + WHEN("the width is converted to narrow") { + auto narrowStr = FromWideString(wideStr); + + THEN("the length of the new string is the same as the wide string") { + REQUIRE(narrowStr.length() == wideStr.length()); + } + + AND_THEN("the contents of the new string is equivalent to the wide string") { + REQUIRE(narrowStr.compare("Some string text here.") == 0); + } + } + } +}