Add unit tests to CI (#140)

This commit is contained in:
Jeremy Rifkin 2024-06-19 20:33:32 -05:00 committed by GitHub
parent ce075b056f
commit 7a9ed920d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 158 additions and 36 deletions

View File

@ -136,3 +136,60 @@ jobs:
- name: build and test
run: |
python3 ci/test-all-configs.py --${{matrix.compiler}}
unittest-linux:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
compiler: [g++-10, clang++-14]
shared: [OFF, ON]
build_type: [Debug, RelWithDebInfo]
has_dl_find_object: [OFF, ON]
steps:
- uses: actions/checkout@v4
- name: dependencies
run: |
sudo apt install gcc-10 g++-10 libgcc-10-dev ninja-build
- name: build and test
run: |
mkdir build
cd build
cmake .. \
-GNinja \
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} \
-DCMAKE_C_COMPILER=${{matrix.compiler == 'g++-10' && 'gcc-10' || 'clang-14'}} \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.shared}} \
-DHAS_DL_FIND_OBJECT=${{matrix.has_dl_find_object}} \
-DCPPTRACE_WERROR_BUILD=On \
-DCPPTRACE_BUILD_TESTING=On
ninja
./unittest
bash -c "exec -a u ./unittest"
unittest-windows:
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
compiler: [cl, clang++]
shared: [OFF] # TODO: Re-enable shared
build_type: [Debug, RelWithDebInfo]
steps:
- uses: actions/checkout@v4
- name: Enable Developer Command Prompt
uses: ilammy/msvc-dev-cmd@v1.13.0
- name: build and test
run: |
mkdir build
cd build
cmake .. `
-DCMAKE_CXX_COMPILER=${{matrix.compiler}} `
-DCMAKE_C_COMPILER=${{matrix.compiler == 'clang++' && 'clang' || matrix.compiler}} `
-DBUILD_SHARED_LIBS=${{matrix.shared}} `
-DCPPTRACE_WERROR_BUILD=On `
-DCPPTRACE_BUILD_TESTING=On
cmake --build . --config ${{matrix.build_type}}
./${{matrix.build_type}}/unittest
# TODO: Macos, mingw

View File

@ -10,7 +10,9 @@ cd build
cmake .. -DZSTD_BUILD_SHARED=On -DZSTD_BUILD_SHARED=Off -DZSTD_LEGACY_SUPPORT=Off -DZSTD_BUILD_PROGRAMS=Off -DZSTD_BUILD_CONTRIB=Off -DZSTD_BUILD_TESTS=Off -G"Unix Makefiles"
make -j
make install
cd ../../../..
mkdir libdwarf
cd libdwarf
git init

View File

@ -1,4 +1,6 @@
#!/bin/bash
sudo apt install libgtest-dev
mkdir zstd
cd zstd
git init
@ -7,7 +9,9 @@ git fetch --depth 1 origin 63779c798237346c2b245c546c40b72a5a5913fe # 1.5.5
git checkout FETCH_HEAD
make -j
sudo make install
cd ..
mkdir libdwarf
cd libdwarf
git init

View File

@ -177,7 +177,7 @@ def build(matrix):
f"-D{matrix['demangle']}=On",
"-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h",
"-DCPPTRACE_BUILD_TESTING=On",
"-DCPPTRACE_IS_GH_ACTIONS=On",
"-DCPPTRACE_SKIP_UNIT=On",
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
]
if matrix['symbols'] == "CPPTRACE_GET_SYMBOLS_WITH_LIBDL":
@ -200,7 +200,7 @@ def build(matrix):
f"-D{matrix['symbols']}=On",
f"-D{matrix['demangle']}=On",
"-DCPPTRACE_BUILD_TESTING=On",
"-DCPPTRACE_IS_GH_ACTIONS=On",
"-DCPPTRACE_SKIP_UNIT=On",
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
]
if matrix["compiler"] == "g++":
@ -227,7 +227,7 @@ def build_full_or_auto(matrix):
f"-DCPPTRACE_WERROR_BUILD=On",
f"-DCPPTRACE_BACKTRACE_PATH=/usr/lib/gcc/x86_64-linux-gnu/10/include/backtrace.h",
"-DCPPTRACE_BUILD_TESTING=On",
"-DCPPTRACE_IS_GH_ACTIONS=On",
"-DCPPTRACE_SKIP_UNIT=On",
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
]
if matrix["config"] != "":
@ -247,7 +247,7 @@ def build_full_or_auto(matrix):
f"-DCPPTRACE_USE_EXTERNAL_ZSTD=On",
f"-DCPPTRACE_WERROR_BUILD=On",
"-DCPPTRACE_BUILD_TESTING=On",
"-DCPPTRACE_IS_GH_ACTIONS=On",
"-DCPPTRACE_SKIP_UNIT=On",
f"-DBUILD_SHARED_LIBS={matrix['shared']}"
]
if matrix["config"] != "":

View File

@ -166,7 +166,7 @@ option(CPPTRACE_VCPKG "" OFF)
option(CPPTRACE_SANITIZER_BUILD "" OFF)
option(CPPTRACE_WERROR_BUILD "" OFF)
option(CPPTRACE_POSITION_INDEPENDENT_CODE "" ON)
option(CPPTRACE_IS_GH_ACTIONS "" OFF)
option(CPPTRACE_SKIP_UNIT "" OFF)
option(CPPTRACE_USE_EXTERNAL_GTEST "" OFF)
mark_as_advanced(
@ -177,6 +177,6 @@ mark_as_advanced(
CPPTRACE_WERROR_BUILD
CPPTRACE_CONAN
CPPTRACE_VCPKG
CPPTRACE_IS_GH_ACTIONS
CPPTRACE_SKIP_UNIT
CPPTRACE_USE_EXTERNAL_GTEST
)

View File

@ -37,7 +37,7 @@ if(UNIX)
endif()
# primarily a workaround for github actions issue https://github.com/actions/runner-images/issues/8659
if(NOT CPPTRACE_IS_GH_ACTIONS)
if(NOT CPPTRACE_SKIP_UNIT)
if(CPPTRACE_USE_EXTERNAL_GTEST)
find_package(GTest)
else()
@ -60,6 +60,6 @@ if(NOT CPPTRACE_IS_GH_ACTIONS)
)
target_compile_features(unittest PRIVATE cxx_std_20)
target_link_libraries(unittest PRIVATE ${target_name} GTest::gtest_main GTest::gmock_main)
target_compile_options(unittest PRIVATE ${warning_options} -Wno-pedantic)
target_compile_options(unittest PRIVATE ${warning_options} $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-pedantic -Wno-attributes>)
add_test(NAME unittest COMMAND unittest)
endif()

View File

@ -49,16 +49,25 @@ TEST(ObjectTrace, BasicResolution) {
}
CPPTRACE_FORCE_NO_INLINE void object_resolve_3(std::vector<int>& line_numbers) {
// TODO: dbghelp uses raw address, not object
#ifndef _MSC_VER
CPPTRACE_FORCE_NO_INLINE int object_resolve_3(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
auto dummy = cpptrace::generate_trace();
auto dummy_otrace = cpptrace::generate_object_trace();
cpptrace::object_trace otrace;
otrace.frames.push_back(cpptrace::object_frame{0, dummy.frames[0].object_address, dummy_otrace.frames[0].object_path});
otrace.frames.push_back(cpptrace::object_frame{0, dummy.frames[1].object_address, dummy_otrace.frames[1].object_path});
otrace.frames.push_back(cpptrace::object_frame{0, dummy.frames[2].object_address, dummy_otrace.frames[2].object_path});
otrace.frames.push_back(cpptrace::object_frame{0, dummy.frames[3].object_address, dummy_otrace.frames[3].object_path});
otrace.frames.push_back(
cpptrace::object_frame{0, dummy.frames[0].object_address, dummy_otrace.frames[0].object_path}
);
otrace.frames.push_back(
cpptrace::object_frame{0, dummy.frames[1].object_address, dummy_otrace.frames[1].object_path}
);
otrace.frames.push_back(
cpptrace::object_frame{0, dummy.frames[2].object_address, dummy_otrace.frames[2].object_path}
);
otrace.frames.push_back(
cpptrace::object_frame{0, dummy.frames[3].object_address, dummy_otrace.frames[3].object_path}
);
auto trace = otrace.resolve();
int i = 0;
EXPECT_THAT(trace.frames[i].filename, testing::EndsWith("object_trace.cpp"));
@ -76,16 +85,17 @@ CPPTRACE_FORCE_NO_INLINE void object_resolve_3(std::vector<int>& line_numbers) {
EXPECT_THAT(trace.frames[i].filename, testing::EndsWith("object_trace.cpp"));
EXPECT_EQ(trace.frames[i].line.value(), line_numbers[i]);
EXPECT_THAT(trace.frames[i].symbol, testing::HasSubstr("ObjectTrace_Resolution_Test::TestBody"));
return 2;
}
CPPTRACE_FORCE_NO_INLINE void object_resolve_2(std::vector<int>& line_numbers) {
CPPTRACE_FORCE_NO_INLINE int object_resolve_2(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
object_resolve_3(line_numbers);
return object_resolve_3(line_numbers) * 2;
}
CPPTRACE_FORCE_NO_INLINE void object_resolve_1(std::vector<int>& line_numbers) {
CPPTRACE_FORCE_NO_INLINE int object_resolve_1(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
object_resolve_2(line_numbers);
return object_resolve_2(line_numbers) * 2;
}
TEST(ObjectTrace, Resolution) {
@ -93,3 +103,4 @@ TEST(ObjectTrace, Resolution) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
object_resolve_1(line_numbers);
}
#endif

View File

@ -16,7 +16,8 @@ using namespace std::literals;
// This is fickle, however, it's the only way to do it really. It's reasonably reliable test in practice.
CPPTRACE_FORCE_NO_INLINE void raw_trace_basic() {
// NOTE: MSVC likes creating trampoline-like entries for non-static functions
CPPTRACE_FORCE_NO_INLINE static 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<uintptr_t>(raw_trace_basic));
@ -28,7 +29,14 @@ CPPTRACE_FORCE_NO_INLINE 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
// This is stupid, but without it gcc was optimizing both &&a and &&b to point to the start of the function's body
volatile auto x = 0;
if(x) {
goto* &&a;
}
if(x) {
goto* &&b;
}
EXPECT_GE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&a));
EXPECT_LE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&b));
}
@ -39,11 +47,12 @@ TEST(RawTrace, Basic) {
#ifndef _MSC_VER
raw_trace_basic_precise();
#endif
[[maybe_unused]] volatile int x = 0; // prevent raw_trace_basic_precise() above being a jmp
}
CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_2(
CPPTRACE_FORCE_NO_INLINE static void raw_trace_multi_2(
cpptrace::frame_ptr parent_low_bound,
cpptrace::frame_ptr parent_high_bound
) {
@ -54,7 +63,7 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_2(
EXPECT_LE(raw_trace.frames[1], parent_high_bound);
}
CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_1() {
CPPTRACE_FORCE_NO_INLINE static void raw_trace_multi_1() {
auto raw_trace = cpptrace::generate_raw_trace();
raw_trace_multi_2(reinterpret_cast<uintptr_t>(raw_trace_multi_1), reinterpret_cast<uintptr_t>(raw_trace_multi_1) + 300);
EXPECT_GE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(raw_trace_multi_1));
@ -63,8 +72,8 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_1() {
std::vector<std::pair<cpptrace::frame_ptr, cpptrace::frame_ptr>> parents;
CPPTRACE_FORCE_NO_INLINE void record_parent(cpptrace::frame_ptr low_bound, cpptrace::frame_ptr high_bound) {
parents.insert(parents.begin(), {reinterpret_cast<uintptr_t>(low_bound), reinterpret_cast<uintptr_t>(high_bound)});
CPPTRACE_FORCE_NO_INLINE void record_parent(uintptr_t low_bound, uintptr_t high_bound) {
parents.insert(parents.begin(), {low_bound, high_bound});
}
#ifndef _MSC_VER
@ -72,6 +81,13 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_3() {
a:
auto raw_trace = cpptrace::generate_raw_trace();
b:
volatile auto x = 0;
if(x) {
goto* &&a;
}
if(x) {
goto* &&b;
}
EXPECT_GE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&a)); // this frame
EXPECT_LE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&b));
for(size_t i = 0; i < parents.size(); i++) { // parent frames
@ -84,6 +100,13 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_2() {
a:
auto raw_trace = cpptrace::generate_raw_trace();
b:
volatile auto x = 0;
if(x) {
goto* &&a;
}
if(x) {
goto* &&b;
}
EXPECT_GE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&a)); // this frame
EXPECT_LE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&b));
for(size_t i = 0; i < parents.size(); i++) { // parent frames
@ -93,19 +116,38 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_2() {
record_parent(reinterpret_cast<uintptr_t>(&&c), reinterpret_cast<uintptr_t>(&&d));
c:
raw_trace_multi_precise_3();
d:;
d:
if(x) {
goto* &&c;
}
if(x) {
goto* &&d;
}
}
CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_1() {
a:
auto raw_trace = cpptrace::generate_raw_trace();
b:
volatile auto x = 0;
if(x) {
goto* &&a;
}
if(x) {
goto* &&b;
}
EXPECT_GE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&a));
EXPECT_LE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(&&b));
record_parent(reinterpret_cast<uintptr_t>(&&c), reinterpret_cast<uintptr_t>(&&d));
c:
raw_trace_multi_precise_2();
d:;
d:
if(x) {
goto* &&c;
}
if(x) {
goto* &&d;
}
}
#endif

View File

@ -42,7 +42,9 @@ TEST(Stacktrace, Basic) {
CPPTRACE_FORCE_NO_INLINE void stacktrace_multi_3(std::vector<int>& line_numbers) {
// NOTE: returning something and then return stacktrace_multi_3(line_numbers) * 2; later helps prevent the call from
// being optimized to a jmp
CPPTRACE_FORCE_NO_INLINE int stacktrace_multi_3(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
auto trace = cpptrace::generate_trace();
int i = 0;
@ -61,16 +63,17 @@ CPPTRACE_FORCE_NO_INLINE void stacktrace_multi_3(std::vector<int>& line_numbers)
EXPECT_THAT(trace.frames[i].filename, testing::EndsWith("stacktrace.cpp"));
EXPECT_EQ(trace.frames[i].line.value(), line_numbers[i]);
EXPECT_THAT(trace.frames[i].symbol, testing::HasSubstr("Stacktrace_MultipleFrames_Test::TestBody"));
return 2;
}
CPPTRACE_FORCE_NO_INLINE void stacktrace_multi_2(std::vector<int>& line_numbers) {
CPPTRACE_FORCE_NO_INLINE int stacktrace_multi_2(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
stacktrace_multi_3(line_numbers);
return stacktrace_multi_3(line_numbers) * 2;
}
CPPTRACE_FORCE_NO_INLINE void stacktrace_multi_1(std::vector<int>& line_numbers) {
CPPTRACE_FORCE_NO_INLINE int stacktrace_multi_1(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
stacktrace_multi_2(line_numbers);
return stacktrace_multi_2(line_numbers) * 2;
}
TEST(Stacktrace, MultipleFrames) {
@ -121,7 +124,8 @@ TEST(Stacktrace, RawTraceResolution) {
CPPTRACE_FORCE_NO_INLINE void stacktrace_inline_resolution_3(std::vector<int>& line_numbers) {
#ifndef _MSC_VER
CPPTRACE_FORCE_NO_INLINE int stacktrace_inline_resolution_3(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
auto trace = cpptrace::generate_trace();
int i = 0;
@ -152,16 +156,17 @@ CPPTRACE_FORCE_NO_INLINE void stacktrace_inline_resolution_3(std::vector<int>& l
EXPECT_FALSE(trace.frames[i].is_inline);
EXPECT_NE(trace.frames[i].raw_address, 0);
EXPECT_NE(trace.frames[i].object_address, 0);
return 2;
}
CPPTRACE_FORCE_INLINE void stacktrace_inline_resolution_2(std::vector<int>& line_numbers) {
CPPTRACE_FORCE_INLINE int stacktrace_inline_resolution_2(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
stacktrace_inline_resolution_3(line_numbers);
return stacktrace_inline_resolution_3(line_numbers) * 2;
}
CPPTRACE_FORCE_NO_INLINE void stacktrace_inline_resolution_1(std::vector<int>& line_numbers) {
CPPTRACE_FORCE_NO_INLINE int stacktrace_inline_resolution_1(std::vector<int>& line_numbers) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
stacktrace_inline_resolution_2(line_numbers);
return stacktrace_inline_resolution_2(line_numbers) * 2;
}
TEST(Stacktrace, InlineResolution) {
@ -169,3 +174,4 @@ TEST(Stacktrace, InlineResolution) {
line_numbers.insert(line_numbers.begin(), __LINE__ + 1);
stacktrace_inline_resolution_1(line_numbers);
}
#endif