mirror of
https://github.com/hyprwm/hyprutils.git
synced 2026-05-07 13:38:14 +02:00
signals: add a lot of tests
This commit is contained in:
parent
d4ad01f9cf
commit
a3a470a0cd
1 changed files with 209 additions and 0 deletions
209
tests/signal.cpp
209
tests/signal.cpp
|
|
@ -1,11 +1,18 @@
|
|||
#include <any>
|
||||
#include <hyprutils/signal/Signal.hpp>
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
#include <memory>
|
||||
#include "hyprutils/memory/SharedPtr.hpp"
|
||||
#include "hyprutils/signal/Listener.hpp"
|
||||
#include "shared.hpp"
|
||||
|
||||
using namespace Hyprutils::Signal;
|
||||
using namespace Hyprutils::Memory;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
//
|
||||
|
||||
void legacy(int& ret) {
|
||||
CSignal signal;
|
||||
int data = 0;
|
||||
|
|
@ -33,6 +40,27 @@ void legacyListenerEmit(int& ret) {
|
|||
EXPECT(data, 1);
|
||||
}
|
||||
|
||||
void legacyListeners(int& ret) {
|
||||
int data = 0;
|
||||
|
||||
CSignalT<> signal0;
|
||||
CSignalT<int> signal1;
|
||||
|
||||
auto listener0 = signal0.registerListener([&](std::any d) { data += 1; });
|
||||
auto listener1 = signal1.registerListener([&](std::any d) { data += std::any_cast<int>(d); });
|
||||
|
||||
signal0.registerStaticListener([&](void* o, std::any d) { data += 10; }, nullptr);
|
||||
signal1.registerStaticListener([&](void* o, std::any d) { data += std::any_cast<int>(d) * 10; }, nullptr);
|
||||
|
||||
signal0.emit();
|
||||
signal1.emit(2);
|
||||
|
||||
EXPECT(data, 33);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
//
|
||||
|
||||
void empty(int& ret) {
|
||||
int data = 0;
|
||||
|
||||
|
|
@ -76,6 +104,144 @@ void typedMany(int& ret) {
|
|||
EXPECT(data3, 3);
|
||||
}
|
||||
|
||||
void ref(int& ret) {
|
||||
int count = 0;
|
||||
int data = 0;
|
||||
|
||||
CSignalT<int&> signal;
|
||||
auto l1 = signal.listen([&](int& v) { v += 1; });
|
||||
auto l2 = signal.listen([&](int v) { count += v; });
|
||||
signal.emit(data);
|
||||
|
||||
CSignalT<const int&> constSignal;
|
||||
auto l3 = constSignal.listen([&](const int& v) { count += v; });
|
||||
auto l4 = constSignal.listen([&](int v) { count += v; });
|
||||
constSignal.emit(data);
|
||||
|
||||
EXPECT(data, 1);
|
||||
EXPECT(count, 3);
|
||||
}
|
||||
|
||||
void refMany(int& ret) {
|
||||
int count = 0;
|
||||
int data1 = 0;
|
||||
int data2 = 10;
|
||||
|
||||
CSignalT<int&, const int&> signal;
|
||||
auto l1 = signal.listen([&](int& v, const int&) { v += 1; });
|
||||
auto l2 = signal.listen([&](int v1, int v2) { count += v1 + v2; });
|
||||
|
||||
signal.emit(data1, data2);
|
||||
EXPECT(data1, 1);
|
||||
EXPECT(count, 11);
|
||||
}
|
||||
|
||||
void listenerAdded(int& ret) {
|
||||
int count = 0;
|
||||
|
||||
CSignalT<> signal;
|
||||
CHyprSignalListener secondListener;
|
||||
|
||||
auto listener = signal.listen([&] {
|
||||
count += 1;
|
||||
|
||||
if (!secondListener)
|
||||
secondListener = signal.listen([&] { count += 1; });
|
||||
});
|
||||
|
||||
signal.emit();
|
||||
EXPECT(count, 1); // second should NOT be invoked as it was registed during emit
|
||||
|
||||
signal.emit();
|
||||
EXPECT(count, 3); // second should be invoked
|
||||
}
|
||||
|
||||
void lastListenerSwapped(int& ret) {
|
||||
int count = 0;
|
||||
|
||||
CSignalT<> signal;
|
||||
CHyprSignalListener removedListener;
|
||||
CHyprSignalListener addedListener;
|
||||
|
||||
auto firstListener = signal.listen([&] {
|
||||
removedListener.reset(); // dropped and should NOT be invoked
|
||||
|
||||
if (!addedListener)
|
||||
addedListener = signal.listen([&] { count += 2; });
|
||||
});
|
||||
|
||||
removedListener = signal.listen([&] { count += 1; });
|
||||
|
||||
signal.emit();
|
||||
EXPECT(count, 0); // neither the removed nor added listeners should fire
|
||||
|
||||
signal.emit();
|
||||
EXPECT(count, 2); // only the new listener should fire
|
||||
}
|
||||
|
||||
void signalDestroyed(int& ret) {
|
||||
int count = 0;
|
||||
|
||||
auto signal = std::make_unique<CSignalT<>>();
|
||||
|
||||
// This ensures a destructor of a listener called before signal reset is safe.
|
||||
auto preListener = signal->listen([&] { count += 1; });
|
||||
|
||||
auto listener = signal->listen([&] { signal.reset(); });
|
||||
|
||||
// This ensures a destructor of a listener called after signal reset is safe
|
||||
// and gets called.
|
||||
auto postListener = signal->listen([&] { count += 1; });
|
||||
|
||||
signal->emit();
|
||||
EXPECT(count, 2); // all listeners should fire regardless of signal deletion
|
||||
}
|
||||
|
||||
// purely an asan test
|
||||
void signalDestroyedBeforeListener() {
|
||||
CHyprSignalListener listener1;
|
||||
CHyprSignalListener listener2;
|
||||
|
||||
CSignalT<> signal;
|
||||
|
||||
listener1 = signal.listen([] {});
|
||||
listener2 = signal.listen([] {});
|
||||
}
|
||||
|
||||
void signalDestroyedWithAddedListener(int& ret) {
|
||||
int count = 0;
|
||||
|
||||
auto signal = std::make_unique<CSignalT<>>();
|
||||
CHyprSignalListener shouldNotRun;
|
||||
|
||||
auto listener = signal->listen([&] {
|
||||
shouldNotRun = signal->listen([&] { count += 2; });
|
||||
signal.reset();
|
||||
});
|
||||
|
||||
signal->emit();
|
||||
EXPECT(count, 0);
|
||||
}
|
||||
|
||||
void signalDestroyedWithRemovedAndAddedListener(int& ret) {
|
||||
int count = 0;
|
||||
|
||||
auto signal = std::make_unique<CSignalT<>>();
|
||||
CHyprSignalListener removed;
|
||||
CHyprSignalListener shouldNotRun;
|
||||
|
||||
auto listener = signal->listen([&] {
|
||||
removed.reset();
|
||||
shouldNotRun = signal->listen([&] { count += 2; });
|
||||
signal.reset();
|
||||
});
|
||||
|
||||
removed = signal->listen([&] { count += 1; });
|
||||
|
||||
signal->emit();
|
||||
EXPECT(count, 0);
|
||||
}
|
||||
|
||||
void staticListener(int& ret) {
|
||||
int data = 0;
|
||||
|
||||
|
|
@ -86,13 +252,56 @@ void staticListener(int& ret) {
|
|||
EXPECT(data, 1);
|
||||
}
|
||||
|
||||
void staticListenerDestroy(int& ret) {
|
||||
int count = 0;
|
||||
|
||||
auto signal = makeShared<CSignalT<>>();
|
||||
signal->listenStatic([&] { count += 1; });
|
||||
|
||||
signal->listenStatic([&] {
|
||||
// should not fire but SHOULD be freed
|
||||
signal->listenStatic([&] { count += 3; });
|
||||
|
||||
signal.reset();
|
||||
});
|
||||
|
||||
signal->listenStatic([&] { count += 1; });
|
||||
|
||||
signal->emit();
|
||||
EXPECT(count, 2);
|
||||
}
|
||||
|
||||
// purely an asan test
|
||||
void listenerDestroysSelf() {
|
||||
CSignalT<> signal;
|
||||
|
||||
CHyprSignalListener listener;
|
||||
listener = signal.listen([&] { listener.reset(); });
|
||||
|
||||
// the static signal case is taken care of above
|
||||
|
||||
signal.emit();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** envp) {
|
||||
int ret = 0;
|
||||
legacy(ret);
|
||||
legacyListenerEmit(ret);
|
||||
legacyListeners(ret);
|
||||
empty(ret);
|
||||
typed(ret);
|
||||
typedMany(ret);
|
||||
ref(ret);
|
||||
refMany(ret);
|
||||
listenerAdded(ret);
|
||||
lastListenerSwapped(ret);
|
||||
signalDestroyed(ret);
|
||||
signalDestroyedBeforeListener();
|
||||
signalDestroyedWithAddedListener(ret);
|
||||
signalDestroyedWithRemovedAndAddedListener(ret);
|
||||
staticListener(ret);
|
||||
staticListenerDestroy(ret);
|
||||
signalDestroyed(ret);
|
||||
listenerDestroysSelf();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue