227 lines
4.6 KiB
C++
227 lines
4.6 KiB
C++
|
|
#include <gtest/gtest.h>
|
||
|
|
#include <XCEngine/Core/RefCounted.h>
|
||
|
|
#include <XCEngine/Core/SmartPtr.h>
|
||
|
|
#include <XCEngine/Core/Event.h>
|
||
|
|
#include <XCEngine/Core/Types.h>
|
||
|
|
|
||
|
|
#include <string>
|
||
|
|
#include <thread>
|
||
|
|
#include <atomic>
|
||
|
|
|
||
|
|
using namespace XCEngine::Core;
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
class TestRefCounted : public RefCounted {
|
||
|
|
public:
|
||
|
|
TestRefCounted() : value(42) {}
|
||
|
|
int value;
|
||
|
|
};
|
||
|
|
|
||
|
|
TEST(Core_RefCounted, DefaultConstructor) {
|
||
|
|
TestRefCounted* obj = new TestRefCounted();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 1);
|
||
|
|
delete obj;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_RefCounted, AddRef) {
|
||
|
|
TestRefCounted* obj = new TestRefCounted();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 1);
|
||
|
|
|
||
|
|
obj->AddRef();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 2);
|
||
|
|
|
||
|
|
obj->Release();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 1);
|
||
|
|
delete obj;
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_RefCounted, Release) {
|
||
|
|
TestRefCounted* obj = new TestRefCounted();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 1);
|
||
|
|
|
||
|
|
obj->AddRef();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 2);
|
||
|
|
|
||
|
|
obj->Release();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 1);
|
||
|
|
|
||
|
|
obj->Release();
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_RefCounted, ChainedRefs) {
|
||
|
|
TestRefCounted* obj = new TestRefCounted();
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 1);
|
||
|
|
|
||
|
|
for (int i = 0; i < 5; i++) {
|
||
|
|
obj->AddRef();
|
||
|
|
}
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 6);
|
||
|
|
|
||
|
|
for (int i = 0; i < 5; i++) {
|
||
|
|
obj->Release();
|
||
|
|
}
|
||
|
|
EXPECT_EQ(obj->GetRefCount(), 1);
|
||
|
|
delete obj;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct TestStruct {
|
||
|
|
int value = 100;
|
||
|
|
std::string name = "test";
|
||
|
|
};
|
||
|
|
|
||
|
|
TEST(Core_SmartPtr, MakeRef) {
|
||
|
|
auto ref = MakeRef<TestStruct>();
|
||
|
|
EXPECT_NE(ref, nullptr);
|
||
|
|
EXPECT_EQ(ref->value, 100);
|
||
|
|
EXPECT_EQ(ref->name, "test");
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_SmartPtr, Ref_NullCheck) {
|
||
|
|
Ref<TestStruct> ref = nullptr;
|
||
|
|
EXPECT_EQ(ref, nullptr);
|
||
|
|
EXPECT_FALSE(ref);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_SmartPtr, Ref_Dereference) {
|
||
|
|
auto ref = MakeRef<TestStruct>();
|
||
|
|
ref->value = 200;
|
||
|
|
EXPECT_EQ(ref->value, 200);
|
||
|
|
EXPECT_EQ((*ref).value, 200);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_SmartPtr, Ref_Copy) {
|
||
|
|
auto ref1 = MakeRef<TestStruct>();
|
||
|
|
ref1->value = 300;
|
||
|
|
|
||
|
|
auto ref2 = ref1;
|
||
|
|
EXPECT_EQ(ref1.use_count(), 2);
|
||
|
|
EXPECT_EQ(ref2.use_count(), 2);
|
||
|
|
EXPECT_EQ(ref2->value, 300);
|
||
|
|
|
||
|
|
ref2->value = 400;
|
||
|
|
EXPECT_EQ(ref1->value, 400);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_SmartPtr, Ref_Move) {
|
||
|
|
auto ref1 = MakeRef<TestStruct>();
|
||
|
|
ref1->value = 500;
|
||
|
|
|
||
|
|
auto ref2 = std::move(ref1);
|
||
|
|
EXPECT_EQ(ref1, nullptr);
|
||
|
|
EXPECT_NE(ref2, nullptr);
|
||
|
|
EXPECT_EQ(ref2->value, 500);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_SmartPtr, MakeUnique) {
|
||
|
|
auto unique = MakeUnique<TestStruct>();
|
||
|
|
EXPECT_NE(unique, nullptr);
|
||
|
|
EXPECT_EQ(unique->value, 100);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_SmartPtr, UniqueRef_Ownership) {
|
||
|
|
auto unique1 = MakeUnique<TestStruct>();
|
||
|
|
unique1->value = 600;
|
||
|
|
|
||
|
|
auto unique2 = std::move(unique1);
|
||
|
|
EXPECT_EQ(unique1, nullptr);
|
||
|
|
EXPECT_NE(unique2, nullptr);
|
||
|
|
EXPECT_EQ(unique2->value, 600);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_Event, Subscribe) {
|
||
|
|
Event<> event;
|
||
|
|
bool called = false;
|
||
|
|
|
||
|
|
uint64_t id = event.Subscribe([&called]() {
|
||
|
|
called = true;
|
||
|
|
});
|
||
|
|
|
||
|
|
EXPECT_NE(id, 0u);
|
||
|
|
|
||
|
|
event.Invoke();
|
||
|
|
EXPECT_TRUE(called);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_Event, Invoke_NoArgs) {
|
||
|
|
Event<> event;
|
||
|
|
int count = 0;
|
||
|
|
|
||
|
|
event.Subscribe([&count]() { count++; });
|
||
|
|
event.Subscribe([&count]() { count++; });
|
||
|
|
|
||
|
|
event.Invoke();
|
||
|
|
EXPECT_EQ(count, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_Event, Invoke_WithArgs) {
|
||
|
|
Event<int, std::string> event;
|
||
|
|
int result = 0;
|
||
|
|
std::string text;
|
||
|
|
|
||
|
|
event.Subscribe([&result, &text](int v, const std::string& s) {
|
||
|
|
result = v;
|
||
|
|
text = s;
|
||
|
|
});
|
||
|
|
|
||
|
|
event.Invoke(42, "hello");
|
||
|
|
EXPECT_EQ(result, 42);
|
||
|
|
EXPECT_EQ(text, "hello");
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_Event, Unsubscribe) {
|
||
|
|
Event<> event;
|
||
|
|
int count = 0;
|
||
|
|
|
||
|
|
uint64_t id = event.Subscribe([&count]() { count++; });
|
||
|
|
event.Subscribe([&count]() { count++; });
|
||
|
|
|
||
|
|
event.Invoke();
|
||
|
|
EXPECT_EQ(count, 2);
|
||
|
|
|
||
|
|
event.Unsubscribe(id);
|
||
|
|
event.Invoke();
|
||
|
|
EXPECT_EQ(count, 3);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_Event, Clear) {
|
||
|
|
Event<> event;
|
||
|
|
int count = 0;
|
||
|
|
|
||
|
|
event.Subscribe([&count]() { count++; });
|
||
|
|
event.Subscribe([&count]() { count++; });
|
||
|
|
|
||
|
|
event.Clear();
|
||
|
|
event.Invoke();
|
||
|
|
EXPECT_EQ(count, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_Event, MultipleListeners) {
|
||
|
|
Event<int> event;
|
||
|
|
std::vector<int> results;
|
||
|
|
|
||
|
|
for (int i = 0; i < 5; i++) {
|
||
|
|
event.Subscribe([&results](int v) {
|
||
|
|
results.push_back(v);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
event.Invoke(10);
|
||
|
|
|
||
|
|
EXPECT_EQ(results.size(), 5);
|
||
|
|
for (int v : results) {
|
||
|
|
EXPECT_EQ(v, 10);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST(Core_Event, ReturnId) {
|
||
|
|
Event<> event;
|
||
|
|
|
||
|
|
uint64_t id1 = event.Subscribe([]() {});
|
||
|
|
uint64_t id2 = event.Subscribe([]() {});
|
||
|
|
|
||
|
|
EXPECT_NE(id1, id2);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|