This is not really nice, but works for my purpose. The idea is to unwind the stack, search for the googletest method that called the test and reset the instruction pointer to that stack frame.
Note that the stack is not properly destroyed, meaning that, e.g., resources can leak.
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <cxxabi.h>
#include <iostream>
#include <gtest/gtest.h>
void skip() {
unw_cursor_t cursor;
unw_context_t context;
unw_getcontext(&context);
unw_init_local(&cursor, &context);
while (unw_step(&cursor)) {
unw_word_t off;
char symbol[256] = {"<unknown>"};
char* name = symbol;
if (!unw_get_proc_name(&cursor, symbol, sizeof(symbol), &off)) {
int status;
if ((name = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) == nullptr) name = symbol;
}
if (std::string(name) == "testing::Test::Run()") {
::testing::internal::AssertHelper(::testing::TestPartResult::kSkip, __FILE__, __LINE__, "skipped") = ::testing::Message();
unw_resume(&cursor);
}
if (name != symbol) free(name);
}
throw std::runtime_error("Did not find test method on the stack, could not skip test");
}
Example test (can be pasted below the code above):
int foo(int x) {
if (x == 3) skip();
return 11;
}
TEST(SkipTest, ShouldNotBeSkipped) {
foo(2);
EXPECT_TRUE(false);
}
TEST(SkipTest, ShouldBeSkipped) {
foo(3);
EXPECT_TRUE(false);
}
TEST(SkipTest, TestExecutionContinues) {
EXPECT_FALSE(false);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Output:
[==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 3 tests from SkipTest
[ RUN ] SkipTest.ShouldNotBeSkipped
skip_test.cpp:44: Failure
Value of: false
Actual: false
Expected: true
[ FAILED ] SkipTest.ShouldNotBeSkipped (0 ms)
[ RUN ] SkipTest.ShouldBeSkipped
[ SKIPPED ] SkipTest.ShouldBeSkipped (0 ms)
[ RUN ] SkipTest.TestExecutionContinues
[ OK ] SkipTest.TestExecutionContinues (0 ms)
[----------] 3 tests from SkipTest (0 ms total)
[----------] Global test environment tear-down
[==========] 3 tests from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
[ SKIPPED ] 1 test, listed below:
[ SKIPPED ] SkipTest.ShouldBeSkipped
[ FAILED ] 1 test, listed below:
[ FAILED ] SkipTest.ShouldNotBeSkipped
1 FAILED TEST