#include #include #include #include #include #include #include #ifdef _WIN32 #include #endif using namespace XCEngine::Scripting; namespace { std::filesystem::path GetExecutableDirectory() { #ifdef _WIN32 std::wstring buffer(MAX_PATH, L'\0'); const DWORD length = GetModuleFileNameW(nullptr, buffer.data(), static_cast(buffer.size())); if (length == 0 || length >= buffer.size()) { return std::filesystem::current_path(); } buffer.resize(length); return std::filesystem::path(buffer).parent_path(); #else return std::filesystem::current_path(); #endif } std::filesystem::path ResolveProjectManagedOutputDirectory() { constexpr const char* configuredDirectory = XCENGINE_TEST_PROJECT_MANAGED_OUTPUT_DIR; if (configuredDirectory[0] != '\0') { return std::filesystem::path(configuredDirectory); } return (GetExecutableDirectory() / ".." / ".." / "managed" / "ProjectScriptAssemblies").lexically_normal(); } std::filesystem::path ResolveProjectScriptCoreDllPath() { constexpr const char* configuredPath = XCENGINE_TEST_PROJECT_SCRIPT_CORE_DLL; if (configuredPath[0] != '\0') { return std::filesystem::path(configuredPath); } return ResolveProjectManagedOutputDirectory() / "XCEngine.ScriptCore.dll"; } std::filesystem::path ResolveProjectGameScriptsDllPath() { constexpr const char* configuredPath = XCENGINE_TEST_PROJECT_GAME_SCRIPTS_DLL; if (configuredPath[0] != '\0') { return std::filesystem::path(configuredPath); } return ResolveProjectManagedOutputDirectory() / "GameScripts.dll"; } MonoScriptRuntime::Settings CreateProjectMonoSettings() { MonoScriptRuntime::Settings settings; settings.assemblyDirectory = ResolveProjectManagedOutputDirectory(); settings.corlibDirectory = settings.assemblyDirectory; settings.coreAssemblyPath = ResolveProjectScriptCoreDllPath(); settings.appAssemblyPath = ResolveProjectGameScriptsDllPath(); return settings; } class ProjectScriptAssemblyTest : public ::testing::Test { protected: void SetUp() override { ASSERT_TRUE(std::filesystem::exists(ResolveProjectScriptCoreDllPath())); ASSERT_TRUE(std::filesystem::exists(ResolveProjectGameScriptsDllPath())); runtime = std::make_unique(CreateProjectMonoSettings()); ASSERT_TRUE(runtime->Initialize()) << runtime->GetLastError(); } std::unique_ptr runtime; }; TEST_F(ProjectScriptAssemblyTest, InitializesFromProjectScriptAssemblyDirectory) { EXPECT_TRUE(runtime->IsInitialized()); EXPECT_EQ(runtime->GetSettings().assemblyDirectory, ResolveProjectManagedOutputDirectory()); EXPECT_EQ(runtime->GetSettings().appAssemblyPath, ResolveProjectGameScriptsDllPath()); } TEST_F(ProjectScriptAssemblyTest, DiscoversProjectAssetMonoBehaviourClassesAndFieldMetadata) { const std::vector classNames = runtime->GetScriptClassNames("GameScripts"); std::vector classDescriptors; ASSERT_TRUE(runtime->TryGetAvailableScriptClasses(classDescriptors)); EXPECT_TRUE(runtime->IsClassAvailable("GameScripts", "ProjectScripts", "ProjectScriptProbe")); EXPECT_NE( std::find(classNames.begin(), classNames.end(), "ProjectScripts.ProjectScriptProbe"), classNames.end()); EXPECT_NE( std::find( classDescriptors.begin(), classDescriptors.end(), ScriptClassDescriptor{"GameScripts", "ProjectScripts", "ProjectScriptProbe"}), classDescriptors.end()); std::vector fields; ASSERT_TRUE(runtime->TryGetClassFieldMetadata("GameScripts", "ProjectScripts", "ProjectScriptProbe", fields)); const std::vector expectedFields = { {"EnabledOnBoot", ScriptFieldType::Bool}, {"Label", ScriptFieldType::String}, {"Speed", ScriptFieldType::Float}, }; EXPECT_EQ(fields, expectedFields); std::vector defaultValues; ASSERT_TRUE(runtime->TryGetClassFieldDefaultValues("GameScripts", "ProjectScripts", "ProjectScriptProbe", defaultValues)); ASSERT_EQ(defaultValues.size(), 3u); EXPECT_EQ(defaultValues[0].fieldName, "EnabledOnBoot"); EXPECT_EQ(defaultValues[0].type, ScriptFieldType::Bool); EXPECT_EQ(std::get(defaultValues[0].value), true); EXPECT_EQ(defaultValues[1].fieldName, "Label"); EXPECT_EQ(defaultValues[1].type, ScriptFieldType::String); EXPECT_EQ(std::get(defaultValues[1].value), "ProjectScriptProbe"); EXPECT_EQ(defaultValues[2].fieldName, "Speed"); EXPECT_EQ(defaultValues[2].type, ScriptFieldType::Float); EXPECT_FLOAT_EQ(std::get(defaultValues[2].value), 2.5f); } } // namespace