refactor(tests): Migrate to googletest
googletest (gtest) is more feature rich than the current implementation which only provides expect() which is basically an assertion. It is also quite intuitive to use, this can be seen in the rewrite of the command_line test where EXPECT_THROW replaces a whole try-catch block. I have also moved the source files the test depend on to be linked in CMakeLists.txt instead of including them directly because include .cpp files is bad. The two x11 tests were removed because they were written two years ago and a lot of the things they depend on, don't actually exist anymore in polybar (I think we switched to xpp after those tests were written) Tests are now compiled with the gcov lib which can be used to provide test coverage in a second step
This commit is contained in:
parent
1d20df00e8
commit
c865add821
@ -35,6 +35,8 @@ addons:
|
|||||||
- python-xcbgen
|
- python-xcbgen
|
||||||
- xcb-proto
|
- xcb-proto
|
||||||
- xutils-dev
|
- xutils-dev
|
||||||
|
- libgtest0
|
||||||
|
- libgtest-dev
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
|
@ -26,6 +26,9 @@ add_subdirectory(lib)
|
|||||||
add_subdirectory(man)
|
add_subdirectory(man)
|
||||||
add_subdirectory(src bin)
|
add_subdirectory(src bin)
|
||||||
|
|
||||||
|
# We need to enable testing in the root folder so that 'ctest' and 'make test'
|
||||||
|
# can be run in the build directory
|
||||||
|
enable_testing()
|
||||||
if(BUILD_TESTS)
|
if(BUILD_TESTS)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
else()
|
else()
|
||||||
|
@ -1,26 +1,62 @@
|
|||||||
#
|
# Compile and link with coverage
|
||||||
# Based on https://github.com/modern-cpp-examples/match3/blob/master/test/CMakeLists.txt
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fprofile-arcs -ftest-coverage")
|
||||||
#
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -include common/test.hpp")
|
|
||||||
|
|
||||||
link_libraries(${libs})
|
link_libraries(${libs})
|
||||||
include_directories(${dirs})
|
include_directories(${dirs})
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
function(unit_test file)
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(GTEST REQUIRED gtest)
|
||||||
|
|
||||||
|
function(unit_test file tests)
|
||||||
|
set(multi_value_args SOURCES)
|
||||||
|
|
||||||
|
cmake_parse_arguments("BIN" "" "" "${multi_value_args}" ${ARGN})
|
||||||
|
|
||||||
|
# Prefix all sources needed by the tests with ../src/ so that the calls to the
|
||||||
|
# unit_test function become cleaner
|
||||||
|
SET(sources "")
|
||||||
|
FOREACH(f ${BIN_SOURCES})
|
||||||
|
LIST(APPEND sources "../src/${f}")
|
||||||
|
ENDFOREACH(f)
|
||||||
|
|
||||||
string(REPLACE "/" "_" testname ${file})
|
string(REPLACE "/" "_" testname ${file})
|
||||||
add_executable(unit_test.${testname} unit_tests/${file}.cpp)
|
set(name "unit_test.${testname}")
|
||||||
add_test(unit_test.${testname} unit_test.${testname})
|
add_executable(${name} unit_tests/${file}.cpp ${sources})
|
||||||
|
|
||||||
|
# Link against googletest
|
||||||
|
target_link_libraries(${name} ${GTEST_LDFLAGS})
|
||||||
|
target_compile_options(${name} PUBLIC ${GTEST_CFLAGS})
|
||||||
|
|
||||||
|
add_test(NAME ${name} COMMAND ${name})
|
||||||
|
|
||||||
|
# Add test to list of unit tests
|
||||||
|
list(APPEND ${tests} "${name}")
|
||||||
|
set(${tests} ${${tests}} PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
unit_test(utils/color)
|
unit_test(utils/color unit_tests)
|
||||||
unit_test(utils/math)
|
unit_test(utils/math unit_tests)
|
||||||
unit_test(utils/memory)
|
unit_test(utils/memory unit_tests)
|
||||||
unit_test(utils/string)
|
unit_test(utils/string unit_tests
|
||||||
unit_test(utils/file)
|
SOURCES
|
||||||
unit_test(components/command_line)
|
utils/string.cpp)
|
||||||
|
unit_test(utils/file unit_tests
|
||||||
|
SOURCES
|
||||||
|
utils/command.cpp
|
||||||
|
utils/file.cpp
|
||||||
|
utils/env.cpp
|
||||||
|
utils/process.cpp
|
||||||
|
utils/io.cpp
|
||||||
|
utils/string.cpp
|
||||||
|
utils/concurrency.cpp
|
||||||
|
components/logger.cpp)
|
||||||
|
unit_test(components/command_line unit_tests
|
||||||
|
SOURCES
|
||||||
|
components/command_line.cpp
|
||||||
|
utils/string.cpp)
|
||||||
|
|
||||||
# XXX: Requires mocked xcb connection
|
# Compile all unit tests with 'make all_unit_tests'
|
||||||
#unit_test("x11/connection")
|
add_custom_target("all_unit_tests" DEPENDS ${unit_tests})
|
||||||
#unit_test("x11/winspec")
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#define expect(...) \
|
#define expect(...) \
|
||||||
(void)((__VA_ARGS__) || (expect_fail__(#__VA_ARGS__, __FILE__, __LINE__), 0))
|
(void)((__VA_ARGS__) || (expect_fail__(#__VA_ARGS__, __FILE__, __LINE__), 0))
|
||||||
|
@ -1,160 +1,113 @@
|
|||||||
#include "components/command_line.cpp"
|
#include "common/test.hpp"
|
||||||
#include "utils/string.cpp"
|
#include "components/command_line.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
int main() {
|
using namespace polybar;
|
||||||
using namespace polybar;
|
|
||||||
|
|
||||||
const auto get_opts = []() -> const command_line::options {
|
class CommandLine : public ::testing::Test {
|
||||||
// clang-format off
|
protected:
|
||||||
return command_line::options{
|
virtual void SetUp() {
|
||||||
command_line::option{"-f", "--flag", "Flag description"},
|
set_cli();
|
||||||
command_line::option{"-o", "--option", "Option description", "OPTION", {"foo", "bar", "baz"}},
|
}
|
||||||
|
|
||||||
|
virtual void set_cli() {
|
||||||
|
cli = command_line::parser::make("cmd", get_opts());
|
||||||
|
}
|
||||||
|
|
||||||
|
command_line::options get_opts() {
|
||||||
|
// clang-format off
|
||||||
|
return command_line::options {
|
||||||
|
command_line::option{"-f", "--flag", "Flag description"},
|
||||||
|
command_line::option{"-o", "--option", "Option description", "OPTION", {"foo", "bar", "baz"}},
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
};
|
};
|
||||||
// clang-format on
|
|
||||||
};
|
|
||||||
|
|
||||||
"has_short"_test = [&] {
|
command_line::parser::make_type cli;
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());
|
};
|
||||||
cli->process_input(string_util::split("-f", ' '));
|
|
||||||
expect(cli->has("flag"));
|
|
||||||
expect(!cli->has("option"));
|
|
||||||
|
|
||||||
cli = command_line::parser::make("cmd", get_opts());;
|
|
||||||
cli->process_input(string_util::split("-f -o foo", ' '));
|
|
||||||
expect(cli->has("flag"));
|
|
||||||
expect(cli->has("option"));
|
|
||||||
|
|
||||||
cli = command_line::parser::make("cmd", get_opts());;
|
TEST_F(CommandLine, hasShort) {
|
||||||
cli->process_input(string_util::split("-o baz", ' '));
|
cli->process_input(string_util::split("-f", ' '));
|
||||||
expect(!cli->has("flag"));
|
EXPECT_TRUE(cli->has("flag"));
|
||||||
expect(cli->has("option"));
|
EXPECT_FALSE(cli->has("option"));
|
||||||
};
|
|
||||||
|
|
||||||
"has_long"_test = [&] {
|
set_cli();
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
cli->process_input(string_util::split("-f -o foo", ' '));
|
||||||
cli->process_input(string_util::split("--flag", ' '));
|
EXPECT_TRUE(cli->has("flag"));
|
||||||
expect(cli->has("flag"));
|
EXPECT_TRUE(cli->has("option"));
|
||||||
expect(!cli->has("option"));
|
|
||||||
|
|
||||||
cli = command_line::parser::make("cmd", get_opts());;
|
set_cli();
|
||||||
cli->process_input(string_util::split("--flag --option=foo", ' '));
|
cli->process_input(string_util::split("-o baz", ' '));
|
||||||
expect(cli->has("flag"));
|
EXPECT_FALSE(cli->has("flag"));
|
||||||
expect(cli->has("option"));
|
EXPECT_TRUE(cli->has("option"));
|
||||||
|
}
|
||||||
cli = command_line::parser::make("cmd", get_opts());;
|
|
||||||
cli->process_input(string_util::split("--option=foo --flag", ' '));
|
TEST_F(CommandLine, hasLong) {
|
||||||
expect(cli->has("flag"));
|
cli->process_input(string_util::split("--flag", ' '));
|
||||||
expect(cli->has("option"));
|
EXPECT_TRUE(cli->has("flag"));
|
||||||
|
EXPECT_FALSE(cli->has("option"));
|
||||||
cli = command_line::parser::make("cmd", get_opts());;
|
|
||||||
cli->process_input(string_util::split("--option=baz", ' '));
|
set_cli();
|
||||||
expect(!cli->has("flag"));
|
cli->process_input(string_util::split("--flag --option=foo", ' '));
|
||||||
expect(cli->has("option"));
|
EXPECT_TRUE(cli->has("flag"));
|
||||||
};
|
EXPECT_TRUE(cli->has("option"));
|
||||||
|
|
||||||
"compare"_test = [&] {
|
set_cli();
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
cli->process_input(string_util::split("--option=foo --flag", ' '));
|
||||||
cli->process_input(string_util::split("-o baz", ' '));
|
EXPECT_TRUE(cli->has("flag"));
|
||||||
expect(cli->compare("option", "baz"));
|
EXPECT_TRUE(cli->has("option"));
|
||||||
|
|
||||||
cli = command_line::parser::make("cmd", get_opts());;
|
set_cli();
|
||||||
cli->process_input(string_util::split("--option=foo", ' '));
|
cli->process_input(string_util::split("--option=baz", ' '));
|
||||||
expect(cli->compare("option", "foo"));
|
EXPECT_FALSE(cli->has("flag"));
|
||||||
};
|
EXPECT_TRUE(cli->has("option"));
|
||||||
|
}
|
||||||
"get"_test = [&] {
|
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
TEST_F(CommandLine, compare) {
|
||||||
cli->process_input(string_util::split("--option=baz", ' '));
|
cli->process_input(string_util::split("-o baz", ' '));
|
||||||
expect("baz" == cli->get("option"));
|
EXPECT_TRUE(cli->compare("option", "baz"));
|
||||||
|
|
||||||
cli = command_line::parser::make("cmd", get_opts());;
|
set_cli();
|
||||||
cli->process_input(string_util::split("--option=foo", ' '));
|
cli->process_input(string_util::split("--option=foo", ' '));
|
||||||
expect("foo" == cli->get("option"));
|
EXPECT_TRUE(cli->compare("option", "foo"));
|
||||||
};
|
}
|
||||||
|
|
||||||
"missing_value"_test = [&] {
|
TEST_F(CommandLine, get) {
|
||||||
auto input1 = string_util::split("--option", ' ');
|
cli->process_input(string_util::split("--option=baz", ' '));
|
||||||
auto input2 = string_util::split("-o", ' ');
|
EXPECT_EQ("baz", cli->get("option"));
|
||||||
auto input3 = string_util::split("--option baz", ' ');
|
|
||||||
|
set_cli();
|
||||||
bool exception_thrown = false;
|
cli->process_input(string_util::split("--option=foo", ' '));
|
||||||
try {
|
EXPECT_EQ("foo", cli->get("option"));
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
}
|
||||||
cli->process_input(input1);
|
|
||||||
} catch (const command_line::value_error&) {
|
TEST_F(CommandLine, missingValue) {
|
||||||
exception_thrown = true;
|
auto input1 = string_util::split("--option", ' ');
|
||||||
} catch (...) {
|
auto input2 = string_util::split("-o", ' ');
|
||||||
}
|
auto input3 = string_util::split("--option baz", ' ');
|
||||||
expect(exception_thrown);
|
|
||||||
|
EXPECT_THROW(cli->process_input(input1), command_line::value_error);
|
||||||
exception_thrown = false; // reset
|
set_cli();
|
||||||
try {
|
EXPECT_THROW(cli->process_input(input2), command_line::value_error);
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
set_cli();
|
||||||
cli->process_input(input2);
|
EXPECT_THROW(cli->process_input(input3), command_line::value_error);
|
||||||
} catch (const command_line::value_error&) {
|
}
|
||||||
exception_thrown = true;
|
|
||||||
} catch (...) {
|
TEST_F(CommandLine, invalidValue) {
|
||||||
}
|
auto input1 = string_util::split("--option=invalid", ' ');
|
||||||
expect(exception_thrown);
|
auto input2 = string_util::split("-o invalid_value", ' ');
|
||||||
|
|
||||||
exception_thrown = false; // reset
|
EXPECT_THROW(cli->process_input(input1), command_line::value_error);
|
||||||
try {
|
set_cli();
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
EXPECT_THROW(cli->process_input(input2), command_line::value_error);
|
||||||
cli->process_input(input3);
|
}
|
||||||
} catch (const command_line::value_error&) {
|
|
||||||
exception_thrown = true;
|
TEST_F(CommandLine, unrecognized) {
|
||||||
} catch (...) {
|
auto input1 = string_util::split("-x", ' ');
|
||||||
}
|
auto input2 = string_util::split("--unrecognized", ' ');
|
||||||
expect(exception_thrown);
|
|
||||||
};
|
EXPECT_THROW(cli->process_input(input1), command_line::argument_error);
|
||||||
|
set_cli();
|
||||||
"invalid_value"_test = [&] {
|
EXPECT_THROW(cli->process_input(input2), command_line::argument_error);
|
||||||
auto input1 = string_util::split("--option=invalid", ' ');
|
|
||||||
auto input2 = string_util::split("-o invalid_value", ' ');
|
|
||||||
|
|
||||||
bool exception_thrown = false;
|
|
||||||
try {
|
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
|
||||||
cli->process_input(input1);
|
|
||||||
} catch (const command_line::value_error&) {
|
|
||||||
exception_thrown = true;
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
expect(exception_thrown);
|
|
||||||
|
|
||||||
exception_thrown = false; // reset
|
|
||||||
try {
|
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
|
||||||
cli->process_input(input2);
|
|
||||||
} catch (const command_line::value_error&) {
|
|
||||||
exception_thrown = true;
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
expect(exception_thrown);
|
|
||||||
};
|
|
||||||
|
|
||||||
"unrecognized"_test = [&] {
|
|
||||||
auto input1 = string_util::split("-x", ' ');
|
|
||||||
auto input2 = string_util::split("--unrecognized", ' ');
|
|
||||||
|
|
||||||
bool exception_thrown = false;
|
|
||||||
try {
|
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
|
||||||
cli->process_input(input1);
|
|
||||||
} catch (const command_line::argument_error&) {
|
|
||||||
exception_thrown = true;
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
expect(exception_thrown);
|
|
||||||
|
|
||||||
exception_thrown = false; // reset
|
|
||||||
try {
|
|
||||||
auto cli = command_line::parser::make("cmd", get_opts());;
|
|
||||||
cli->process_input(input2);
|
|
||||||
} catch (const command_line::argument_error&) {
|
|
||||||
exception_thrown = true;
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
expect(exception_thrown);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "components/logger.cpp"
|
#include "common/test.hpp"
|
||||||
#include "utils/command.cpp"
|
#include "utils/command.hpp"
|
||||||
#include "utils/concurrency.cpp"
|
#include "utils/file.hpp"
|
||||||
#include "utils/env.cpp"
|
|
||||||
#include "utils/file.cpp"
|
|
||||||
#include "utils/io.cpp"
|
|
||||||
#include "utils/process.cpp"
|
|
||||||
#include "utils/string.cpp"
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
using namespace polybar;
|
using namespace polybar;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "common/test.hpp"
|
||||||
#include "utils/math.hpp"
|
#include "utils/math.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
|
#include "common/test.hpp"
|
||||||
#include "utils/memory.hpp"
|
#include "utils/memory.hpp"
|
||||||
|
|
||||||
|
using namespace polybar;
|
||||||
|
|
||||||
struct mytype {
|
struct mytype {
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
TEST(Memory, makeMallocPtr) {
|
||||||
using namespace polybar;
|
auto ptr = memory_util::make_malloc_ptr<mytype>();
|
||||||
|
EXPECT_EQ(sizeof(mytype*), sizeof(ptr.get()));
|
||||||
"make_malloc_ptr"_test = [] {
|
ptr.reset();
|
||||||
auto ptr = memory_util::make_malloc_ptr<mytype>();
|
EXPECT_EQ(nullptr, ptr.get());
|
||||||
expect(sizeof(mytype*) == sizeof(ptr.get()));
|
}
|
||||||
ptr.reset();
|
|
||||||
expect(ptr.get() == nullptr);
|
TEST(Memory, countof) {
|
||||||
};
|
mytype A[3]{{}, {}, {}};
|
||||||
|
mytype B[8]{{}, {}, {}, {}, {}, {}, {}, {}};
|
||||||
"countof"_test = [] {
|
|
||||||
mytype A[3]{{}, {}, {}};
|
EXPECT_EQ(memory_util::countof(A), size_t{3});
|
||||||
mytype B[8]{{}, {}, {}, {}, {}, {}, {}, {}};
|
EXPECT_EQ(memory_util::countof(B), size_t{8});
|
||||||
|
|
||||||
expect(memory_util::countof(A) == size_t{3});
|
|
||||||
expect(memory_util::countof(B) == size_t{8});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "common/test.hpp"
|
||||||
#include "utils/scope.hpp"
|
#include "utils/scope.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include "utils/string.cpp"
|
#include "common/test.hpp"
|
||||||
|
#include "utils/string.hpp"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
using namespace polybar;
|
using namespace polybar;
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
#include "utils/string.cpp"
|
|
||||||
#include "x11/atoms.cpp"
|
|
||||||
#include "x11/connection.cpp"
|
|
||||||
#include "x11/xutils.cpp"
|
|
||||||
#include "x11/xlib.cpp"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
using namespace polybar;
|
|
||||||
|
|
||||||
"id"_test = [] {
|
|
||||||
connection& conn{configure_connection().create<connection&>()};
|
|
||||||
expect(conn.id(static_cast<xcb_window_t>(0x12345678)) == "0x12345678");
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
#include "utils/string.cpp"
|
|
||||||
#include "x11/atoms.cpp"
|
|
||||||
#include "x11/connection.cpp"
|
|
||||||
#include "x11/winspec.hpp"
|
|
||||||
#include "x11/xutils.cpp"
|
|
||||||
#include "x11/xlib.cpp"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
using namespace polybar;
|
|
||||||
|
|
||||||
"cw_create"_test = [] {
|
|
||||||
connection& conn{configure_connection().create<connection&>()};
|
|
||||||
auto id = conn.generate_id();
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
auto win = winspec(conn, id)
|
|
||||||
<< cw_size(100, 200)
|
|
||||||
<< cw_pos(10, -20)
|
|
||||||
<< cw_border(9)
|
|
||||||
<< cw_class(XCB_WINDOW_CLASS_INPUT_ONLY)
|
|
||||||
<< cw_parent(0x000110a)
|
|
||||||
;
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
expect(static_cast<xcb_window_t>(win) == id);
|
|
||||||
|
|
||||||
xcb_rectangle_t rect{static_cast<xcb_rectangle_t>(win)};
|
|
||||||
expect(rect.width == 100);
|
|
||||||
expect(rect.height == 200);
|
|
||||||
expect(rect.x == 10);
|
|
||||||
expect(rect.y == -20);
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user