46#include <gtest/gtest.h>
60volatile sig_atomic_t g_signal_received = 0;
61std::atomic<int> g_signal_count{0};
63void test_handler(
int signo)
65 g_signal_received = signo;
66 g_signal_count.fetch_add(1, std::memory_order_relaxed);
69void another_handler(
int signo)
71 g_signal_received = signo + 1000;
75class SignalTestFixture :
public ::testing::Test
80 g_signal_received = 0;
81 g_signal_count.store(0, std::memory_order_relaxed);
101 SignalSet set({SIGUSR1, SIGUSR2, SIGTERM});
103 EXPECT_TRUE(set.contains(SIGUSR1));
104 EXPECT_TRUE(set.contains(SIGUSR2));
105 EXPECT_TRUE(set.contains(SIGTERM));
106 EXPECT_FALSE(set.contains(SIGINT));
121 EXPECT_FALSE(set.
contains(SIGUSR1));
130 EXPECT_FALSE(set.
contains(SIGUSR1));
139 EXPECT_FALSE(set.contains(SIGUSR1));
140 EXPECT_FALSE(set.contains(SIGUSR2));
143 EXPECT_TRUE(set.contains(SIGUSR1));
144 EXPECT_TRUE(set.contains(SIGUSR2));
145 EXPECT_TRUE(set.contains(SIGINT));
151 EXPECT_FALSE(empty.contains(SIGUSR1));
154 EXPECT_TRUE(full.contains(SIGUSR1));
155 EXPECT_TRUE(full.contains(SIGINT));
162 sigset_t * ptr = set.
get();
163 EXPECT_NE(ptr,
nullptr);
164 EXPECT_EQ(sigismember(ptr, SIGUSR1), 1);
171TEST_F(SignalTestFixture, SignalInstallsHandler)
174 Signal sig(SIGUSR1, test_handler);
177 EXPECT_EQ(raise(SIGUSR1), 0);
182 EXPECT_EQ(g_signal_received, SIGUSR1);
186TEST_F(SignalTestFixture, SignalRestoresPreviousHandler)
189 Signal outer(SIGUSR1, test_handler);
193 Signal inner(SIGUSR1, another_handler);
197 EXPECT_EQ(g_signal_received, SIGUSR1 + 1000);
199 g_signal_received = 0;
205 EXPECT_EQ(g_signal_received, SIGUSR1);
208TEST_F(SignalTestFixture, SignalWithSigIgn)
211 Signal sig(SIGUSR1, SIG_IGN);
223 Signal sig(SIGUSR1, test_handler,
false);
233 Signal sig(SIGUSR1, test_handler);
242 EXPECT_EQ(g_signal_received, SIGUSR1);
245 signal(SIGUSR1, SIG_DFL);
248TEST_F(SignalTestFixture, SignalMoveConstruction)
250 Signal sig1(SIGUSR1, test_handler);
253 Signal sig2(std::move(sig1));
260TEST_F(SignalTestFixture, SignalMoveAssignment)
262 Signal sig1(SIGUSR1, test_handler);
263 Signal sig2(SIGUSR2, test_handler);
265 sig2 = std::move(sig1);
272TEST_F(SignalTestFixture, SignalCreateThrowsOnInvalidSignal)
278TEST_F(SignalTestFixture, SignalTryCreateReturnsError)
284 EXPECT_FALSE(sig.is_active());
287TEST_F(SignalTestFixture, SignalCreateSucceeds)
291 EXPECT_TRUE(sig.is_active());
292 EXPECT_EQ(sig.signal_number(), SIGUSR1);
296 EXPECT_EQ(g_signal_received, SIGUSR1);
299TEST_F(SignalTestFixture, SignalPreviousHandler)
301 Signal outer(SIGUSR1, test_handler);
304 Signal inner(SIGUSR1, another_handler);
311 static_assert(!std::is_copy_constructible_v<Signal>);
312 static_assert(!std::is_copy_assignable_v<Signal>);
317 static_assert(std::is_move_constructible_v<Signal>);
318 static_assert(std::is_move_assignable_v<Signal>);
325TEST_F(SignalTestFixture, SignalBlockerBlocksSignal)
327 Signal sig(SIGUSR1, test_handler);
337 EXPECT_EQ(g_signal_received, 0);
341 EXPECT_EQ(g_signal_received, SIGUSR1);
344TEST_F(SignalTestFixture, SignalBlockerWithInitializerList)
346 Signal sig1(SIGUSR1, test_handler);
347 Signal sig2(SIGUSR2, test_handler);
356 EXPECT_EQ(g_signal_count.load(), 0);
361 EXPECT_GE(g_signal_count.load(), 1);
364TEST_F(SignalTestFixture, SignalBlockerWithSignalSet)
366 Signal sig(SIGUSR1, test_handler);
377 EXPECT_EQ(g_signal_received, 0);
381 EXPECT_EQ(g_signal_received, SIGUSR1);
384TEST_F(SignalTestFixture, SignalBlockerRelease)
386 Signal sig(SIGUSR1, test_handler);
396 EXPECT_EQ(g_signal_received, 0);
403 sigprocmask(SIG_SETMASK, empty.
get(),
nullptr);
406TEST_F(SignalTestFixture, SignalBlockerMoveConstruction)
408 Signal sig(SIGUSR1, test_handler);
416 EXPECT_EQ(g_signal_received, 0);
421 static_assert(!std::is_copy_constructible_v<SignalBlocker>);
422 static_assert(!std::is_copy_assignable_v<SignalBlocker>);
425TEST(SignalBlockerTypeTraits, Movable)
427 static_assert(std::is_move_constructible_v<SignalBlocker>);
428 static_assert(std::is_move_assignable_v<SignalBlocker>);
441 EXPECT_STREQ(err.what(),
"Test error");
448TEST(SignalUtilities, SignalName)
457TEST(SignalUtilities, SendSignalToSelf)
459 g_signal_received = 0;
460 Signal sig(SIGUSR1, test_handler);
464 EXPECT_EQ(g_signal_received, SIGUSR1);
471TEST_F(SignalTestFixture, BackwardCompatibleConstructor)
474 const int signo = SIGUSR1;
475 const bool restart =
true;
477 Signal sig(signo, test_handler, restart);
484 EXPECT_EQ(g_signal_received, SIGUSR1);
487TEST_F(SignalTestFixture, BackwardCompatibleDefaultRestartCalls)
490 Signal sig(SIGUSR1, test_handler);
499TEST_F(SignalTestFixture, NestedSignalHandlers)
501 std::vector<int> received_order;
503 auto handler1 = [](int) { g_signal_received = 1; };
504 auto handler2 = [](int) { g_signal_received = 2; };
505 auto handler3 = [](int) { g_signal_received = 3; };
508 Signal sig1(SIGUSR1, handler1);
511 EXPECT_EQ(g_signal_received, 1);
514 Signal sig2(SIGUSR1, handler2);
517 EXPECT_EQ(g_signal_received, 2);
520 Signal sig3(SIGUSR1, handler3);
523 EXPECT_EQ(g_signal_received, 3);
528 EXPECT_EQ(g_signal_received, 2);
533 EXPECT_EQ(g_signal_received, 1);
537int main(
int argc,
char ** argv)
539 ::testing::InitGoogleTest(&argc, argv);
540 return RUN_ALL_TESTS();
POSIX signal handling utilities with RAII semantics.
bool send_signal_to_self(int signo) noexcept
Sends a signal to the current process.
std::string signal_name(int signo)
Returns the name of a signal.
TEST_F(SignalTestFixture, SignalInstallsHandler)
RAII wrapper for temporarily blocking signals.
void release() noexcept
Releases ownership - the mask won't be restored on destruction.
Exception thrown when a signal operation fails.
int signal_number() const noexcept
Returns the signal number involved in the error.
int error_code() const noexcept
Returns the errno value at the time of failure.
C++ wrapper for sigset_t with a fluent interface.
SignalSet & clear() noexcept
Clears the set (removes all signals).
static SignalSet full() noexcept
Creates a full signal set (all signals).
static SignalSet empty() noexcept
Creates an empty signal set.
sigset_t * get() noexcept
Returns a pointer to the underlying sigset_t.
bool contains(int signo) const noexcept
Checks if a signal is in the set.
SignalSet & add(int signo) noexcept
Adds a signal to the set.
SignalSet & remove(int signo) noexcept
Removes a signal from the set.
RAII wrapper for POSIX signal handler registration.
int signal_number() const noexcept
Returns the signal number being handled.
bool restarts_calls() const noexcept
Returns whether SA_RESTART is enabled for this handler.
void release() noexcept
Releases ownership of the signal handler.
static Signal try_create(int signo, Handler func, bool restart_calls, int &error_out)
Attempts to create a Signal object.
bool is_active() const noexcept
Returns whether this object will restore the handler on destruction.
static Signal create(int signo, Handler func, bool restart_calls=true)
Creates a Signal object or throws on failure.
Handler previous_handler() const noexcept
Returns the previous handler that will be restored.