From 93b1d1c76ae9979c9fa3056535be8222176b2695 Mon Sep 17 00:00:00 2001 From: Jeremy <51220084+jeremy-rifkin@users.noreply.github.com> Date: Sat, 4 May 2024 22:28:53 -0500 Subject: [PATCH] Add basic unittest --- CMakeLists.txt | 1 + Makefile | 15 +++--- test/CMakeLists.txt | 15 ++++++ test/unittest.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 test/unittest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1192791..5d85da2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -575,5 +575,6 @@ endif() # =============================================== Demo/test =============================================== if(CPPTRACE_BUILD_TESTING) + enable_testing() add_subdirectory(test) endif() diff --git a/Makefile b/Makefile index 3a45f35..90469e0 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ default: help help: # with thanks to Ben Rady @grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' +.PHONY: build +build: debug ## build in debug mode + .PHONY: debug debug: ## build in debug mode cmake -S . -B build -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DCPPTRACE_BUILD_TESTING=On @@ -29,13 +32,13 @@ release-msvc: ## build in release mode (with debug info) clean: ## clean rm -rf build -# .PHONY: test -# test: debug ## test -# cd build && ninja test +.PHONY: test +test: debug ## test + cd build && ninja test -# .PHONY: test-release -# test-release: release ## test-release -# cd build && ninja test +.PHONY: test-release +test-release: release ## test-release + cd build && ninja test # .PHONY: test-msvc # test-msvc: debug-msvc ## test diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 29e5617..2a2f3a5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,3 +34,18 @@ if(UNIX) target_compile_features(signal_tracer PRIVATE cxx_std_11) target_link_libraries(signal_tracer PRIVATE ${target_name}) endif() + +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY "https://github.com/google/googletest.git" + GIT_TAG f8d7d77c06936315286eb55f8de22cd23c188571 # v1.14.0 +) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +add_executable(unittest unittest.cpp) +target_compile_features(unittest PRIVATE cxx_std_20) +target_link_libraries(unittest PRIVATE ${target_name} GTest::gtest_main GTest::gmock_main) +add_test(NAME unittest COMMAND unittest) diff --git a/test/unittest.cpp b/test/unittest.cpp new file mode 100644 index 0000000..a166582 --- /dev/null +++ b/test/unittest.cpp @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace std::literals; + +// Raw trace tests + +// This is fickle, however, it's the only way to do it really. It's a reliable test in practice. + +[[gnu::noinline]] void raw_trace_basic() { + auto raw_trace = cpptrace::generate_raw_trace(); + // look for within 90 bytes of the start of the function + EXPECT_GE(raw_trace.frames[0], reinterpret_cast(raw_trace_basic)); + EXPECT_LE(raw_trace.frames[0], reinterpret_cast(raw_trace_basic) + 90); +} + +#ifndef _MSC_VER +[[gnu::noinline]] void raw_trace_basic_precise() { + a: + auto raw_trace = cpptrace::generate_raw_trace(); + b: + // look for within 30 bytes of the start of the function + EXPECT_GE(raw_trace.frames[0], reinterpret_cast(&&a)); + EXPECT_LE(raw_trace.frames[0], reinterpret_cast(&&b)); +} +#endif + +TEST(RawTrace, Basic) { + raw_trace_basic(); + raw_trace_basic_precise(); +} + +[[gnu::noinline]] void raw_trace_multi_1(std::pair parent) { + auto raw_trace = cpptrace::generate_raw_trace(); + EXPECT_GE(raw_trace.frames[0], reinterpret_cast(raw_trace_multi_1)); + EXPECT_LE(raw_trace.frames[0], reinterpret_cast(raw_trace_multi_1) + 90); + EXPECT_GE(raw_trace.frames[1], parent.first); + EXPECT_LE(raw_trace.frames[1], parent.second); +} + +[[gnu::noinline]] void raw_trace_multi_top() { + auto raw_trace = cpptrace::generate_raw_trace(); + raw_trace_multi_1({reinterpret_cast(raw_trace_multi_top), reinterpret_cast(raw_trace_multi_top) + 300}); + EXPECT_GE(raw_trace.frames[0], reinterpret_cast(raw_trace_multi_top)); + EXPECT_LE(raw_trace.frames[0], reinterpret_cast(raw_trace_multi_top) + 90); +} + +#ifndef _MSC_VER +[[gnu::noinline]] void raw_trace_multi_precise_2(std::vector>& parents) { + a: + auto raw_trace = cpptrace::generate_raw_trace(); + b: + EXPECT_GE(raw_trace.frames[0], reinterpret_cast(&&a)); // this frame + EXPECT_LE(raw_trace.frames[0], reinterpret_cast(&&b)); + for(size_t i = 0; i < parents.size(); i++) { // parent frames + EXPECT_GE(raw_trace.frames[i + 1], parents[i].first); + EXPECT_LE(raw_trace.frames[i + 1], parents[i].second); + } +} + +[[gnu::noinline]] void raw_trace_multi_precise_1(std::vector>& parents) { + a: + auto raw_trace = cpptrace::generate_raw_trace(); + b: + EXPECT_GE(raw_trace.frames[0], reinterpret_cast(&&a)); // this frame + EXPECT_LE(raw_trace.frames[0], reinterpret_cast(&&b)); + for(size_t i = 0; i < parents.size(); i++) { // parent frames + EXPECT_GE(raw_trace.frames[i + 1], parents[i].first); + EXPECT_LE(raw_trace.frames[i + 1], parents[i].second); + } + parents.insert(parents.begin(), {reinterpret_cast(&&c), reinterpret_cast(&&d)}); + c: + raw_trace_multi_precise_2(parents); + d:; +} + +[[gnu::noinline]] void raw_trace_multi_precise_top() { + a: + auto raw_trace = cpptrace::generate_raw_trace(); + b: + EXPECT_GE(raw_trace.frames[0], reinterpret_cast(&&a)); + EXPECT_LE(raw_trace.frames[0], reinterpret_cast(&&b)); + std::vector> parents; + parents.insert(parents.begin(), {reinterpret_cast(&&c), reinterpret_cast(&&d)}); + c: + raw_trace_multi_precise_1(parents); + d:; +} +#endif + +TEST(RawTrace, MultipleCalls) { + raw_trace_multi_top(); + raw_trace_multi_precise_top(); +} + +[[gnu::noinline]] void stacktrace_basic() { + auto line = __LINE__ + 1; + auto trace = cpptrace::generate_trace(); + EXPECT_THAT(trace.frames[0].filename, testing::EndsWith("unittest.cpp")); + EXPECT_EQ(trace.frames[0].line.value(), line); + EXPECT_THAT(trace.frames[0].symbol, testing::HasSubstr("stacktrace_basic")); +} + +TEST(Stacktrace, Basic) { + stacktrace_basic(); +}