This commit is contained in:
oy 2019-02-10 18:48:56 +01:00
commit e6170cd1f0
12 changed files with 318 additions and 11 deletions

View file

@ -26,14 +26,16 @@ jobs:
command: |
mkdir -p release
cd release
env CFLAGS="-Wdeclaration-after-statement -Werror" CXXFLAGS="-Werror" cmake ..
env CFLAGS="-Wdeclaration-after-statement -Werror" CXXFLAGS="-Werror" cmake -Werror=dev -DDOWNLOAD_GTEST=ON ..
make everything
make run_tests
./teeworlds_srv shutdown
- run:
name: Build teeworlds with cmake in Debug mode
command: |
mkdir -p debug
cd debug
env CFLAGS="-Wdeclaration-after-statement -Werror" CXXFLAGS="-Werror" cmake -DDEV=ON ..
env CFLAGS="-Wdeclaration-after-statement -Werror" CXXFLAGS="-Werror" cmake -Werror=dev -DDOWNLOAD_GTEST=ON -DDEV=ON ..
make everything
make run_tests
./teeworlds_srv shutdown

View file

@ -66,6 +66,7 @@ endif()
option(CLIENT "Compile client" ON)
option(DOWNLOAD_DEPENDENCIES "Download dependencies (only available on Windows)" ${AUTO_DEPENDENCIES_DEFAULT})
option(DOWNLOAD_GTEST "Download and compile GTest if not found" ${AUTO_DEPENDENCIES_DEFAULT})
option(PREFER_BUNDLED_LIBS "Prefer bundled libraries over system libraries" ${AUTO_DEPENDENCIES_DEFAULT})
option(DEV "Don't generate stuff necessary for packaging" OFF)
@ -285,6 +286,7 @@ endif()
find_package(ZLIB)
find_package(Freetype)
find_package(Git)
find_package(GTest)
find_package(Pnglite)
find_package(SDL2)
find_package(Threads)
@ -346,6 +348,18 @@ endif()
if(CLIENT AND NOT(SDL2_FOUND))
message(SEND_ERROR "You must install SDL2 to compile the Teeworlds client")
endif()
if(NOT(GTEST_FOUND))
if(DOWNLOAD_GTEST)
if(GIT_FOUND)
message(STATUS "Automatically downloading GTest to be able to run tests")
else()
set(DOWNLOAD_GTEST OFF)
message(WARNING "To automatically download GTest, you have to install Git")
endif()
else()
message(STATUS "To run the tests, you have to install GTest")
endif()
endif()
if(TARGET_OS STREQUAL "windows")
set(PLATFORM_CLIENT)
@ -371,6 +385,57 @@ else()
endif()
endif()
########################################################################
# DOWNLOAD GTEST
########################################################################
if(NOT(GTEST_FOUND) AND DOWNLOAD_GTEST)
set(TEEWORLDS_GTEST_VERSION release-1.8.1)
configure_file(cmake/Download_GTest_CMakeLists.txt.in googletest-download/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/googletest-download
)
if(result)
message(WARNING "CMake step for googletest failed: ${result}")
set(DOWNLOAD_GTEST OFF)
else()
execute_process(COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/googletest-download
)
if(result)
message(WARNING "Build step for googletest failed: ${result}")
set(DOWNLOAD_GTEST OFF)
else()
# Prevent overriding the parent project's compiler/linker settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
# Add googletest directly to our build. This defines the gtest target.
add_subdirectory(
${PROJECT_BINARY_DIR}/googletest-src
${PROJECT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL
)
if(MSVC)
foreach(target gtest)
# `/w` disables all warnings. This is needed because `gtest` enables
# `/WX` (equivalent of `-Werror`) for some reason, breaking builds
# when MSVS adds new warnings.
target_compile_options(${target} PRIVATE $<$<NOT:${DBG}>:/MT> $<${DBG}:/MTd> /w)
endforeach()
endif()
set(GTEST_LIBRARIES gtest)
set(GTEST_INCLUDE_DIRS)
if(CMAKE_VERSION VERSION_LESS 2.8.11)
set(GTEST_INCLUDE_DIRS "${gtest_SOURCE_DIR}/include")
endif()
endif()
endif()
endif()
########################################################################
# DEPENDENCY COMPILATION
########################################################################
@ -1478,6 +1543,40 @@ list(APPEND TARGETS_LINK ${TARGETS_TOOLS})
add_custom_target(tools DEPENDS ${TARGETS_TOOLS})
add_custom_target(everything DEPENDS ${TARGETS_OWN})
########################################################################
# TESTS
########################################################################
if(GTEST_FOUND OR DOWNLOAD_GTEST)
set_src(TESTS GLOB src/test
fs.cpp
git_revision.cpp
str.cpp
test.cpp
test.h
thread.cpp
)
set(TARGET_TESTRUNNER testrunner)
add_executable(${TARGET_TESTRUNNER} EXCLUDE_FROM_ALL
${TESTS}
$<TARGET_OBJECTS:engine-shared>
$<TARGET_OBJECTS:game-shared>
${DEPS}
)
target_link_libraries(${TARGET_TESTRUNNER} ${LIBS} ${GTEST_LIBRARIES})
target_include_directories(${TARGET_TESTRUNNER} PRIVATE ${GTEST_INCLUDE_DIRS})
list(APPEND TARGETS_OWN ${TARGET_TESTRUNNER})
list(APPEND TARGETS_LINK ${TARGET_TESTRUNNER})
add_custom_target(run_tests
COMMAND $<TARGET_FILE:${TARGET_TESTRUNNER}> ${TESTRUNNER_ARGS}
COMMENT Running tests
DEPENDS ${TARGET_TESTRUNER}
USES_TERMINAL
)
endif()
########################################################################
# INSTALLATION
########################################################################

View file

@ -17,6 +17,10 @@ build_script:
- cmd: cmake --build build64 --config Release --target everything
test_script:
- cmd: cmake --build build32 --config Debug --target run_tests
- cmd: cmake --build build64 --config Debug --target run_tests
- cmd: cmake --build build32 --config Release --target run_tests
- cmd: cmake --build build64 --config Release --target run_tests
- cmd: |
cd build32
Release\teeworlds_srv shutdown

View file

@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 2.8)
project(googletest-download NONE)
include(ExternalProject)
ExternalProject_Add(googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG "${TEEWORLDS_GTEST_VERSION}"
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
TLS_VERIFY ON
)

View file

@ -39,6 +39,7 @@
#include <fcntl.h>
#include <direct.h>
#include <errno.h>
#include <process.h>
#include <wincrypt.h>
#else
#error NOT IMPLEMENTED
@ -99,7 +100,7 @@ void dbg_msg(const char *sys, const char *fmt, ...)
va_start(args, fmt);
#if defined(CONF_FAMILY_WINDOWS)
_vsnprintf(msg, sizeof(str)-len, fmt, args);
_vsprintf_p(msg, sizeof(str)-len, fmt, args);
#else
vsnprintf(msg, sizeof(str)-len, fmt, args);
#endif
@ -421,7 +422,7 @@ unsigned io_write_newline(IOHANDLE io)
int io_close(IOHANDLE io)
{
fclose((FILE*)io);
return 1;
return 0;
}
int io_flush(IOHANDLE io)
@ -1471,7 +1472,7 @@ int fs_storage_path(const char *appname, char *path, int max)
char *home = getenv("APPDATA");
if(!home)
return -1;
_snprintf(path, max, "%s/%s", home, appname);
str_format(path, max, "%s/%s", home, appname);
return 0;
#else
char *home = getenv("HOME");
@ -1483,25 +1484,25 @@ int fs_storage_path(const char *appname, char *path, int max)
return -1;
#if defined(CONF_PLATFORM_MACOSX)
snprintf(path, max, "%s/Library/Application Support/%s", home, appname);
str_format(path, max, "%s/Library/Application Support/%s", home, appname);
return 0;
#endif
/* old folder location */
snprintf(path, max, "%s/.%s", home, appname);
str_format(path, max, "%s/.%s", home, appname);
for(i = strlen(home)+2; path[i]; i++)
path[i] = tolower(path[i]);
if(!xdgdatahome)
{
/* use default location */
snprintf(xdgpath, max, "%s/.local/share/%s", home, appname);
str_format(xdgpath, max, "%s/.local/share/%s", home, appname);
for(i = strlen(home)+14; xdgpath[i]; i++)
xdgpath[i] = tolower(xdgpath[i]);
}
else
{
snprintf(xdgpath, max, "%s/%s", xdgdatahome, appname);
str_format(xdgpath, max, "%s/%s", xdgdatahome, appname);
for(i = strlen(xdgdatahome)+1; xdgpath[i]; i++)
xdgpath[i] = tolower(xdgpath[i]);
}
@ -1514,7 +1515,7 @@ int fs_storage_path(const char *appname, char *path, int max)
return 0;
}
snprintf(path, max, "%s", xdgpath);
str_format(path, max, "%s", xdgpath);
return 0;
#endif
@ -1773,7 +1774,7 @@ void str_format(char *buffer, int buffer_size, const char *format, ...)
#if defined(CONF_FAMILY_WINDOWS)
va_list ap;
va_start(ap, format);
_vsnprintf(buffer, buffer_size, format, ap);
_vsprintf_p(buffer, buffer_size, format, ap);
va_end(ap);
#else
va_list ap;
@ -2351,6 +2352,15 @@ void secure_random_fill(void *bytes, unsigned length)
#endif
}
int pid()
{
#if defined(CONF_FAMILY_WINDOWS)
return _getpid();
#else
return getpid();
#endif
}
#if defined(__cplusplus)
}
#endif

View file

@ -1441,6 +1441,15 @@ int secure_random_init();
*/
void secure_random_fill(void *bytes, unsigned length);
/*
Function: pid
Gets the process ID of the current process
Returns:
The process ID of the current process.
*/
int pid();
#ifdef __cplusplus
}
#endif

14
src/test/fs.cpp Normal file
View file

@ -0,0 +1,14 @@
#include "test.h"
#include <gtest/gtest.h>
#include <base/system.h>
TEST(Filesystem, CreateCloseDelete)
{
CTestInfo Info;
IOHANDLE File = io_open(Info.m_aFilename, IOFLAG_WRITE);
ASSERT_TRUE(File);
EXPECT_FALSE(io_close(File));
EXPECT_FALSE(fs_remove(Info.m_aFilename));
}

14
src/test/git_revision.cpp Normal file
View file

@ -0,0 +1,14 @@
#include <gtest/gtest.h>
#include <base/system.h>
#include <game/version.h>
extern const char *GIT_SHORTREV_HASH;
TEST(GitRevision, ExistsOrNull)
{
if(GIT_SHORTREV_HASH)
{
ASSERT_STRNE(GIT_SHORTREV_HASH, "");
}
}

63
src/test/str.cpp Normal file
View file

@ -0,0 +1,63 @@
#include <gtest/gtest.h>
#include <base/system.h>
TEST(Str, Startswith)
{
EXPECT_TRUE(str_startswith("abcdef", "abc"));
EXPECT_FALSE(str_startswith("abc", "abcdef"));
EXPECT_TRUE(str_startswith("xyz", ""));
EXPECT_FALSE(str_startswith("", "xyz"));
EXPECT_FALSE(str_startswith("house", "home"));
EXPECT_FALSE(str_startswith("blackboard", "board"));
EXPECT_TRUE(str_startswith("поплавать", "по"));
EXPECT_FALSE(str_startswith("плавать", "по"));
static const char ABCDEFG[] = "abcdefg";
static const char ABC[] = "abc";
EXPECT_EQ(str_startswith(ABCDEFG, ABC) - ABCDEFG, str_length(ABC));
}
TEST(Str, Endswith)
{
EXPECT_TRUE(str_endswith("abcdef", "def"));
EXPECT_FALSE(str_endswith("def", "abcdef"));
EXPECT_TRUE(str_endswith("xyz", ""));
EXPECT_FALSE(str_endswith("", "xyz"));
EXPECT_FALSE(str_endswith("rhyme", "mine"));
EXPECT_FALSE(str_endswith("blackboard", "black"));
EXPECT_TRUE(str_endswith("люди", "юди"));
EXPECT_FALSE(str_endswith("люди", "любовь"));
static const char ABCDEFG[] = "abcdefg";
static const char DEFG[] = "defg";
EXPECT_EQ(str_endswith(ABCDEFG, DEFG) - ABCDEFG,
str_length(ABCDEFG) - str_length(DEFG));
}
TEST(StrFormat, Positional)
{
char aBuf[256];
// normal
str_format(aBuf, sizeof(aBuf), "%s %s", "first", "second");
EXPECT_STREQ(aBuf, "first second");
// normal with positional arguments
str_format(aBuf, sizeof(aBuf), "%1$s %2$s", "first", "second");
EXPECT_STREQ(aBuf, "first second");
// reverse
str_format(aBuf, sizeof(aBuf), "%2$s %1$s", "first", "second");
EXPECT_STREQ(aBuf, "second first");
// duplicate
str_format(aBuf, sizeof(aBuf), "%1$s %1$s %2$d %1$s %2$d", "str", 1);
EXPECT_STREQ(aBuf, "str str 1 str 1");
}

19
src/test/test.cpp Normal file
View file

@ -0,0 +1,19 @@
#include "test.h"
#include <gtest/gtest.h>
#include <base/system.h>
CTestInfo::CTestInfo()
{
const ::testing::TestInfo *pTestInfo =
::testing::UnitTest::GetInstance()->current_test_info();
str_format(m_aFilename, sizeof(m_aFilename), "%s.%s-%d.tmp",
pTestInfo->test_case_name(), pTestInfo->name(), pid());
}
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
net_init();
return RUN_ALL_TESTS();
}

9
src/test/test.h Normal file
View file

@ -0,0 +1,9 @@
#ifndef TEST_TEST_H
#define TEST_TEST_H
class CTestInfo
{
public:
CTestInfo();
char m_aFilename[64];
};
#endif // TEST_TEST_H

48
src/test/thread.cpp Normal file
View file

@ -0,0 +1,48 @@
#include <gtest/gtest.h>
#include <base/system.h>
static void Nothing(void *pUser)
{
(void)pUser;
}
TEST(Thread, Detach)
{
void *pThread = thread_init(Nothing, 0);
thread_detach(pThread);
}
static void SetToOne(void *pUser)
{
*(int *)pUser = 1;
}
TEST(Thread, Wait)
{
int Integer = 0;
void *pThread = thread_init(SetToOne, &Integer);
thread_wait(pThread);
EXPECT_EQ(Integer, 1);
}
TEST(Thread, Yield)
{
thread_yield();
}
static void LockThread(void *pUser)
{
LOCK *pLock = (LOCK *)pUser;
lock_wait(*pLock);
lock_unlock(*pLock);
}
TEST(Thread, Lock)
{
LOCK Lock = lock_create();
lock_wait(Lock);
void *pThread = thread_init(LockThread, &Lock);
lock_unlock(Lock);
thread_wait(pThread);
}