Reactor/tests/test_core.cpp
2025-06-28 15:30:14 -05:00

305 lines
6.4 KiB
C++

#include "../lib/Core.hpp"
#include <cassert>
#include <iostream>
#include <thread>
#include <chrono>
#include <sys/eventfd.h>
#include <unistd.h>
#include <atomic>
#include <vector>
class TestEventLoop
{
private:
std::unique_ptr<reactor::EventLoop> loop_;
std::thread thread_;
public:
TestEventLoop()
{
thread_ = std::thread([this]() {
loop_ = std::make_unique<reactor::EventLoop>();
loop_->loop();
});
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
~TestEventLoop()
{
if (loop_) {
loop_->quit();
}
if (thread_.joinable()) {
thread_.join();
}
}
reactor::EventLoop* getLoop() { return loop_.get(); }
};
void test_timer_basic()
{
std::cout << "Testing basic timer functionality...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
bool timer_fired = false;
[[maybe_unused]] auto timer_id = loop->runAfter(reactor::Duration(50), [&timer_fired]() {
timer_fired = true;
});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
assert(timer_fired);
std::cout << "✓ Basic timer passed\n";
}
void test_timer_cancellation()
{
std::cout << "Testing timer cancellation...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
bool timer_fired = false;
auto timer_id = loop->runAfter(reactor::Duration(100), [&timer_fired]() {
timer_fired = true;
});
loop->cancel(timer_id);
std::this_thread::sleep_for(std::chrono::milliseconds(150));
assert(!timer_fired);
std::cout << "✓ Timer cancellation passed\n";
}
void test_repeating_timer()
{
std::cout << "Testing repeating timer...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
int count = 0;
auto timer_id = loop->runEvery(reactor::Duration(20), [&count]() {
count++;
});
std::this_thread::sleep_for(std::chrono::milliseconds(85));
loop->cancel(timer_id);
assert(count >= 3 && count <= 5);
std::cout << "✓ Repeating timer passed (count: " << count << ")\n";
}
void test_run_in_loop()
{
std::cout << "Testing runInLoop functionality...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
bool task_executed = false;
loop->runInLoop([&task_executed]() {
task_executed = true;
});
std::this_thread::sleep_for(std::chrono::milliseconds(50));
assert(task_executed);
std::cout << "✓ runInLoop passed\n";
}
void test_queue_in_loop()
{
std::cout << "Testing queueInLoop functionality...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
std::vector<int> execution_order;
loop->queueInLoop([&execution_order]() {
execution_order.push_back(1);
});
loop->queueInLoop([&execution_order]() {
execution_order.push_back(2);
});
loop->runInLoop([&execution_order]() {
execution_order.push_back(3);
});
std::this_thread::sleep_for(std::chrono::milliseconds(50));
assert(execution_order.size() == 3);
assert(execution_order[0] == 1 || execution_order[0] == 2 || execution_order[0] == 3);
std::cout << "✓ queueInLoop passed\n";
}
void test_channel_basic()
{
std::cout << "Testing basic channel functionality...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
int event_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
assert(event_fd >= 0);
auto channel = std::make_unique<reactor::Channel>(loop, event_fd);
bool read_callback_called = false;
channel->setReadCallback([&read_callback_called]() {
read_callback_called = true;
});
channel->enableReading();
uint64_t val = 1;
write(event_fd, &val, sizeof(val));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
assert(read_callback_called);
channel->disableAll();
channel->remove();
close(event_fd);
std::cout << "✓ Basic channel passed\n";
}
void test_channel_write_events()
{
std::cout << "Testing channel write events...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
int event_fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
assert(event_fd >= 0);
auto channel = std::make_unique<reactor::Channel>(loop, event_fd);
bool write_callback_called = false;
channel->setWriteCallback([&write_callback_called]() {
write_callback_called = true;
});
channel->enableWriting();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
assert(write_callback_called);
channel->disableAll();
channel->remove();
close(event_fd);
std::cout << "✓ Channel write events passed\n";
}
void test_multiple_timers()
{
std::cout << "Testing multiple timers...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
std::vector<bool> timer_states(5, false);
for (int i = 0; i < 5; ++i) {
loop->runAfter(reactor::Duration(10 + i * 20), [&timer_states, i]() {
timer_states[i] = true;
});
}
std::this_thread::sleep_for(std::chrono::milliseconds(120));
for (bool state : timer_states) {
assert(state);
}
std::cout << "✓ Multiple timers passed\n";
}
void test_timer_precision()
{
std::cout << "Testing timer precision...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
auto start_time = std::chrono::steady_clock::now();
bool timer_fired = false;
loop->runAfter(reactor::Duration(100), [&timer_fired, start_time]() {
auto end_time = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
timer_fired = true;
assert(duration.count() >= 90 && duration.count() <= 150);
});
std::this_thread::sleep_for(std::chrono::milliseconds(150));
assert(timer_fired);
std::cout << "✓ Timer precision passed\n";
}
void test_event_loop_thread_safety()
{
std::cout << "Testing event loop thread safety...\n";
TestEventLoop test_loop;
auto loop = test_loop.getLoop();
std::atomic<int> counter{0};
constexpr int num_tasks = 100;
std::vector<std::thread> threads;
for (int t = 0; t < 4; ++t) {
threads.emplace_back([loop, &counter, num_tasks]() {
for (int i = 0; i < num_tasks; ++i) {
loop->queueInLoop([&counter]() {
counter++;
});
}
});
}
for (auto& thread : threads) {
thread.join();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
assert(counter == 4 * num_tasks);
std::cout << "✓ Event loop thread safety passed\n";
}
int main()
{
std::cout << "=== Core Tests ===\n";
test_timer_basic();
test_timer_cancellation();
test_repeating_timer();
test_run_in_loop();
test_queue_in_loop();
test_channel_basic();
test_channel_write_events();
test_multiple_timers();
test_timer_precision();
test_event_loop_thread_safety();
std::cout << "All core tests passed! ✓\n";
return 0;
}