feat(tests): added parenting tests
This commit is contained in:
parent
47ad44bb83
commit
e6a1e6f57b
6 changed files with 138 additions and 16 deletions
|
|
@ -7,6 +7,11 @@ class NoSuchInstance : public Error {
|
||||||
inline NoSuchInstance(std::string className) : Error("NoSuchInstance", "Cannot create instance of unknown type " + className) {}
|
inline NoSuchInstance(std::string className) : Error("NoSuchInstance", "Cannot create instance of unknown type " + className) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NotCreatableInstance : public Error {
|
||||||
|
public:
|
||||||
|
inline NotCreatableInstance(std::string className) : Error("NotCreatableInstance", "Instance class " + className + " is not creatable") {}
|
||||||
|
};
|
||||||
|
|
||||||
class NoSuchService : public Error {
|
class NoSuchService : public Error {
|
||||||
public:
|
public:
|
||||||
inline NoSuchService(std::string className) : Error("NoSuchService", "Unknown service type " + className) {}
|
inline NoSuchService(std::string className) : Error("NoSuchService", "Unknown service type " + className) {}
|
||||||
|
|
|
||||||
|
|
@ -524,4 +524,17 @@ std::string Instance::GetFullName() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentName;
|
return currentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
result<std::shared_ptr<Instance>, NoSuchInstance, NotCreatableInstance> Instance::New(std::string className) {
|
||||||
|
const InstanceType* type = INSTANCE_MAP[className];
|
||||||
|
|
||||||
|
if (type == nullptr) {
|
||||||
|
return NoSuchInstance(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type->flags & (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE) || type->constructor == nullptr)
|
||||||
|
return NotCreatableInstance(className);
|
||||||
|
|
||||||
|
return type->constructor();
|
||||||
}
|
}
|
||||||
|
|
@ -114,6 +114,9 @@ public:
|
||||||
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
inline void AddChild(std::shared_ptr<Instance> object) { object->SetParent(this->shared_from_this()); }
|
||||||
nullable std::shared_ptr<Instance> FindFirstChild(std::string);
|
nullable std::shared_ptr<Instance> FindFirstChild(std::string);
|
||||||
std::string GetFullName();
|
std::string GetFullName();
|
||||||
|
|
||||||
|
// Dynamically create an instance
|
||||||
|
static result<std::shared_ptr<Instance>, NoSuchInstance, NotCreatableInstance> New(std::string className);
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
result<Variant, MemberNotFound> GetProperty(std::string name);
|
result<Variant, MemberNotFound> GetProperty(std::string name);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ add_executable(obtest
|
||||||
src/lua/luasched.cpp
|
src/lua/luasched.cpp
|
||||||
src/lua/luasignal.cpp
|
src/lua/luasignal.cpp
|
||||||
src/lua/luageneric.cpp
|
src/lua/luageneric.cpp
|
||||||
|
src/objectmodel/basic.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(obtest PRIVATE openblocks Catch2::Catch2WithMain)
|
target_link_libraries(obtest PRIVATE openblocks Catch2::Catch2WithMain)
|
||||||
target_include_directories(obtest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
target_include_directories(obtest PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,6 @@ public:
|
||||||
void testRunStarting(Catch::TestRunInfo const&) override {
|
void testRunStarting(Catch::TestRunInfo const&) override {
|
||||||
// TODO: Make physicsInit optional in headless environments
|
// TODO: Make physicsInit optional in headless environments
|
||||||
physicsInit();
|
physicsInit();
|
||||||
|
|
||||||
gTestModel = DataModel::New();
|
|
||||||
gTestModel->Init(true);
|
|
||||||
Logger::initTest(&testLogOutput);
|
Logger::initTest(&testLogOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,21 +30,12 @@ public:
|
||||||
void testCasePartialStarting(const Catch::TestCaseInfo &testInfo, uint64_t partNumber) override {
|
void testCasePartialStarting(const Catch::TestCaseInfo &testInfo, uint64_t partNumber) override {
|
||||||
// Clear the log output prior to each test
|
// Clear the log output prior to each test
|
||||||
testLogOutput.str("");
|
testLogOutput.str("");
|
||||||
|
|
||||||
|
gTestModel = DataModel::New();
|
||||||
|
gTestModel->Init(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testCasePartialEnded(const Catch::TestCaseStats &testCaseStats, uint64_t partNumber) override {
|
void testCasePartialEnded(const Catch::TestCaseStats &testCaseStats, uint64_t partNumber) override {
|
||||||
auto ctx = gTestModel->GetService<ScriptContext>();
|
|
||||||
ctx->DebugClearSleepingThreads();
|
|
||||||
|
|
||||||
// Clean up remaining scripts from ServerScriptService
|
|
||||||
for (auto& obj : gTestModel->GetService<ServerScriptService>()->GetChildren()) {
|
|
||||||
obj->Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also clear workspace
|
|
||||||
for (auto& obj : gTestModel->GetService<Workspace>()->GetChildren()) {
|
|
||||||
obj->Destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
112
tests/src/objectmodel/basic.cpp
Normal file
112
tests/src/objectmodel/basic.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Basic operations such as instantiation, re-parenting, and destruction
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "error/instance.h"
|
||||||
|
#include "objects/model.h"
|
||||||
|
#include "objects/part/part.h"
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
static auto& m = gDataModel;
|
||||||
|
|
||||||
|
TEST_CASE("Construction") {
|
||||||
|
auto folder = Model::New();
|
||||||
|
m->AddChild(folder);
|
||||||
|
|
||||||
|
SECTION("Constructing container") {
|
||||||
|
bool found = false;
|
||||||
|
for (auto& obj : m->GetChildren()) {
|
||||||
|
if (obj == folder) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(found);
|
||||||
|
REQUIRE(folder->GetParent() != nullptr);
|
||||||
|
REQUIRE(folder->GetParent() == m);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Constructing Part") {
|
||||||
|
auto part = Part::New();
|
||||||
|
folder->AddChild(part);
|
||||||
|
|
||||||
|
REQUIRE(folder->GetChildren().size() == 1);
|
||||||
|
REQUIRE(folder->GetChildren()[0] == part);
|
||||||
|
REQUIRE(part->GetParent() != nullptr);
|
||||||
|
REQUIRE(part->GetParent() == folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Dynamic construction of part") {
|
||||||
|
auto result = Instance::New("Part");
|
||||||
|
REQUIRE(result.isSuccess());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Invalid construction of service") {
|
||||||
|
auto result = Instance::New("Workspace");
|
||||||
|
REQUIRE(result.isError());
|
||||||
|
REQUIRE(std::holds_alternative<NotCreatableInstance>(result.error().value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Invalid construction of nonexistent type") {
|
||||||
|
auto result = Instance::New("__INVALID");
|
||||||
|
REQUIRE(result.isError());
|
||||||
|
REQUIRE(std::holds_alternative<NoSuchInstance>(result.error().value()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Parenting") {
|
||||||
|
auto folder = Model::New();
|
||||||
|
m->AddChild(folder);
|
||||||
|
|
||||||
|
SECTION("Reparent part to another folder") {
|
||||||
|
auto folder2 = Model::New();
|
||||||
|
m->AddChild(folder2);
|
||||||
|
|
||||||
|
auto part = Part::New();
|
||||||
|
folder->AddChild(part);
|
||||||
|
|
||||||
|
// Verify initial folder
|
||||||
|
REQUIRE(folder->GetChildren().size() == 1);
|
||||||
|
REQUIRE(folder->GetChildren()[0] == part);
|
||||||
|
REQUIRE(part->GetParent() != nullptr);
|
||||||
|
REQUIRE(part->GetParent() == folder);
|
||||||
|
|
||||||
|
folder2->AddChild(part); // AddChild just internally calls SetParent, so it should automatically take care of cleanup
|
||||||
|
|
||||||
|
// Verify new folder
|
||||||
|
REQUIRE(folder->GetChildren().size() == 0);
|
||||||
|
REQUIRE(folder2->GetChildren().size() == 1);
|
||||||
|
REQUIRE(folder2->GetChildren()[0] == part);
|
||||||
|
REQUIRE(part->GetParent() != nullptr);
|
||||||
|
REQUIRE(part->GetParent() == folder2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Unparenting") {
|
||||||
|
auto part = Part::New();
|
||||||
|
folder->AddChild(part);
|
||||||
|
|
||||||
|
part->SetParent(nullptr);
|
||||||
|
REQUIRE(folder->GetChildren().size() == 0);
|
||||||
|
REQUIRE(part->GetParent() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Nested reparent") {
|
||||||
|
auto folder2 = Model::New();
|
||||||
|
m->AddChild(folder2);
|
||||||
|
|
||||||
|
auto part = Part::New();
|
||||||
|
folder->AddChild(part);
|
||||||
|
auto part2 = Part::New();
|
||||||
|
part->AddChild(part2);
|
||||||
|
|
||||||
|
REQUIRE(part->GetChildren().size() == 1);
|
||||||
|
REQUIRE(part->GetChildren()[0] == part2);
|
||||||
|
REQUIRE(part2->GetParent() == part);
|
||||||
|
|
||||||
|
folder2->AddChild(part); // AddChild just internally calls SetParent, so it should automatically take care of cleanup
|
||||||
|
|
||||||
|
// Make sure nothing changed
|
||||||
|
REQUIRE(part->GetChildren().size() == 1);
|
||||||
|
REQUIRE(part->GetChildren()[0] == part2);
|
||||||
|
REQUIRE(part2->GetParent() == part);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue