Reactor/tests/test_utilities.cpp
2025-06-27 18:16:01 -05:00

250 lines
5.7 KiB
C++

#include "../lib/Utilities.hpp"
#include <cassert>
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
#include <future>
void test_lock_free_queue()
{
std::cout << "Testing lock-free queue...\n";
reactor::LockFreeQueue<int> queue;
assert(queue.empty());
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
assert(!queue.empty());
int val;
assert(queue.dequeue(val) && val == 1);
assert(queue.dequeue(val) && val == 2);
assert(queue.dequeue(val) && val == 3);
assert(queue.empty());
assert(!queue.dequeue(val));
std::cout << "✓ Lock-free queue basic operations passed\n";
}
void test_lock_free_queue_concurrent()
{
std::cout << "Testing lock-free queue concurrency...\n";
reactor::LockFreeQueue<int> queue;
constexpr int num_items = 1000;
constexpr int num_producers = 4;
constexpr int num_consumers = 2;
std::vector<std::thread> producers;
std::vector<std::thread> consumers;
std::atomic<int> consumed_count{0};
std::atomic<bool> stop_consumers{false};
for (int p = 0; p < num_producers; ++p) {
producers.emplace_back([&queue, p, num_items]() {
for (int i = 0; i < num_items; ++i) {
queue.enqueue(p * num_items + i);
}
});
}
for (int c = 0; c < num_consumers; ++c) {
consumers.emplace_back([&queue, &consumed_count, &stop_consumers]() {
int val;
while (!stop_consumers) {
if (queue.dequeue(val)) {
consumed_count++;
} else {
std::this_thread::yield();
}
}
});
}
for (auto& p : producers) {
p.join();
}
while (consumed_count < num_producers * num_items) {
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
stop_consumers = true;
for (auto& c : consumers) {
c.join();
}
assert(consumed_count == num_producers * num_items);
std::cout << "✓ Lock-free queue concurrency passed\n";
}
void test_object_pool()
{
std::cout << "Testing object pool...\n";
struct TestObject
{
int value = 42;
TestObject() { std::cout << "TestObject constructed\n"; }
~TestObject() { std::cout << "TestObject destructed\n"; }
};
auto pool = std::make_shared<reactor::ObjectPool<TestObject>>();
{
auto obj1 = pool->getObject();
auto obj2 = pool->getObject();
assert(obj1->value == 42);
assert(obj2->value == 42);
assert(obj1.get() != obj2.get());
}
{
auto obj3 = pool->getObject();
assert(obj3->value == 42);
}
std::cout << "✓ Object pool passed\n";
}
void test_logger()
{
std::cout << "Testing logger...\n";
reactor::Logger::setLevel(reactor::LogLevel::DEBUG);
reactor::Logger(reactor::LogLevel::DEBUG) << "Debug message";
reactor::Logger(reactor::LogLevel::INFO) << "Info message with number: " << 42;
reactor::Logger(reactor::LogLevel::WARN) << "Warning message";
reactor::Logger(reactor::LogLevel::ERROR) << "Error message";
reactor::Logger::setLevel(reactor::LogLevel::ERROR);
reactor::Logger(reactor::LogLevel::DEBUG) << "This should not appear";
reactor::Logger(reactor::LogLevel::INFO) << "This should not appear";
reactor::Logger(reactor::LogLevel::ERROR) << "This should appear";
reactor::Logger::setLevel(reactor::LogLevel::DEBUG);
std::cout << "✓ Logger passed\n";
}
void test_concurrent_task_queue()
{
std::cout << "Testing concurrent task queue...\n";
reactor::ConcurrentTaskQueue queue(2, "TestQueue");
assert(queue.getName() == "TestQueue");
std::atomic<int> counter{0};
std::promise<void> all_done;
auto future = all_done.get_future();
for (int i = 0; i < 10; ++i) {
queue.runTaskInQueue([&counter, i, &all_done]() {
counter++;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if (counter == 10) {
all_done.set_value();
}
});
}
future.wait();
assert(counter == 10);
std::cout << "✓ Concurrent task queue passed\n";
}
void test_sync_task()
{
std::cout << "Testing sync task execution...\n";
reactor::ConcurrentTaskQueue queue(1, "SyncTest");
bool task_executed = false;
queue.syncTaskInQueue([&task_executed]() {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
task_executed = true;
});
assert(task_executed);
std::cout << "✓ Sync task execution passed\n";
}
void test_utility_functions()
{
std::cout << "Testing utility functions...\n";
std::size_t seed = 0;
reactor::hashCombine(seed, 42);
reactor::hashCombine(seed, std::string("test"));
assert(seed != 0);
std::string text = "hello,world,test,data";
auto parts = reactor::splitString(text, ",");
assert(parts.size() == 4);
assert(parts[0] == "hello");
assert(parts[1] == "world");
assert(parts[2] == "test");
assert(parts[3] == "data");
auto single = reactor::splitString("single", ",");
assert(single.size() == 1);
assert(single[0] == "single");
std::cout << "✓ Utility functions passed\n";
}
void test_network_utilities()
{
std::cout << "Testing network utilities...\n";
uint64_t original = 0x123456789ABCDEF0ULL;
uint64_t network = reactor::hton64(original);
uint64_t back = reactor::ntoh64(network);
assert(back == original);
std::cout << "✓ Network utilities passed\n";
}
void test_non_copyable()
{
std::cout << "Testing NonCopyable...\n";
class TestClass : public reactor::NonCopyable
{
public:
int value = 42;
TestClass() = default;
TestClass(TestClass&& other) noexcept : value(other.value) { other.value = 0; }
};
TestClass obj1;
TestClass obj2 = std::move(obj1);
assert(obj2.value == 42);
assert(obj1.value == 0);
std::cout << "✓ NonCopyable passed\n";
}
int main()
{
std::cout << "=== Utilities Tests ===\n";
test_lock_free_queue();
test_lock_free_queue_concurrent();
test_object_pool();
test_logger();
test_concurrent_task_queue();
test_sync_task();
test_utility_functions();
test_network_utilities();
test_non_copyable();
std::cout << "All utilities tests passed! ✓\n";
return 0;
}