#define TEST_NO_MAIN #include "acutest.h" #include #include #include #include "../include/ShaderManager.h" #include "../include/ModelManager.h" #include "../include/MaterialManager.h" #include "../include/scripting/ScriptEngine.h" #include "../include/scripting/ResourceBindings.h" #include "raylib.h" static bool HasDisplay() { #if defined(_WIN32) return true; #elif defined(__APPLE__) return true; #else const char* display = std::getenv("DISPLAY"); const char* wayland = std::getenv("WAYLAND_DISPLAY"); return (display && *display) || (wayland && *wayland); #endif } static bool InitRaylibHidden() { const char* forceHeadless = std::getenv("SIMIAN_HEADLESS"); if (forceHeadless && forceHeadless[0] == '1') { return false; } if (!HasDisplay()) { return false; } if (!IsWindowReady()) { SetConfigFlags(FLAG_WINDOW_HIDDEN); InitWindow(1, 1, "simian_test"); SetTargetFPS(60); } return IsWindowReady(); } static void ShutdownRaylibHidden() { if (IsWindowReady()) { CloseWindow(); } } static std::filesystem::path WriteTempShader(const std::filesystem::path& dir, const std::string& name, const std::string& code) { std::filesystem::path path = dir / name; std::ofstream ofs(path); ofs << code; return path; } void test_shader_manager(void) { if (!InitRaylibHidden()) { TEST_SKIP("No display available for raylib"); return; } std::filesystem::path tmpDir = std::filesystem::current_path() / "tmp_shader"; std::filesystem::create_directories(tmpDir); const std::string vsCode = "#version 330\n" "layout(location = 0) in vec3 vertexPosition;\n" "uniform mat4 mvp;\n" "void main() {\n" " gl_Position = mvp * vec4(vertexPosition, 1.0);\n" "}\n"; const std::string fsCode = "#version 330\n" "out vec4 fragColor;\n" "void main() {\n" " fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n"; auto vsPath = WriteTempShader(tmpDir, "test.vs", vsCode); auto fsPath = WriteTempShader(tmpDir, "test.fs", fsCode); ShaderManager shaderManager; unsigned int shaderId = shaderManager.Load(vsPath.string(), fsPath.string()); TEST_CHECK(shaderId != 0); TEST_CHECK(shaderManager.Get(shaderId) != nullptr); shaderManager.Unload(shaderId); TEST_CHECK(shaderManager.Get(shaderId) == nullptr); std::filesystem::remove(vsPath); std::filesystem::remove(fsPath); std::filesystem::remove(tmpDir); ShutdownRaylibHidden(); } void test_model_manager(void) { if (!InitRaylibHidden()) { TEST_SKIP("No display available for raylib"); return; } ModelManager modelManager; Mesh mesh = GenMeshCube(1.0f, 1.0f, 1.0f); unsigned int modelId = modelManager.LoadFromMesh(mesh); TEST_CHECK(modelId != 0); TEST_CHECK(modelManager.Get(modelId) != nullptr); modelManager.Unload(modelId); TEST_CHECK(modelManager.Get(modelId) == nullptr); ShutdownRaylibHidden(); } void test_material_manager(void) { MaterialManager materialManager; Color albedo = {1, 2, 3, 4}; unsigned int materialId = materialManager.Create(7, albedo); TEST_CHECK(materialId != 0); MaterialData* data = materialManager.Get(materialId); TEST_CHECK(data != nullptr); TEST_CHECK(data->shaderId == 7); TEST_CHECK(data->albedo.r == 1); TEST_CHECK(data->albedo.g == 2); TEST_CHECK(data->albedo.b == 3); TEST_CHECK(data->albedo.a == 4); materialManager.SetShader(materialId, 42); TEST_CHECK(data->shaderId == 42); Color newAlbedo = {10, 20, 30, 40}; materialManager.SetAlbedo(materialId, newAlbedo); TEST_CHECK(data->albedo.r == 10); TEST_CHECK(data->albedo.g == 20); TEST_CHECK(data->albedo.b == 30); TEST_CHECK(data->albedo.a == 40); materialManager.Remove(materialId); TEST_CHECK(materialManager.Get(materialId) == nullptr); } void test_resource_bindings_script(void) { if (!InitRaylibHidden()) { TEST_SKIP("No display available for raylib"); return; } std::filesystem::path tmpDir = std::filesystem::current_path() / "tmp_resource"; std::filesystem::create_directories(tmpDir); const std::string vsCode = "#version 330\n" "layout(location = 0) in vec3 vertexPosition;\n" "uniform mat4 mvp;\n" "void main() {\n" " gl_Position = mvp * vec4(vertexPosition, 1.0);\n" "}\n"; const std::string fsCode = "#version 330\n" "out vec4 fragColor;\n" "void main() {\n" " fragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" "}\n"; auto vsPath = WriteTempShader(tmpDir, "script.vs", vsCode); auto fsPath = WriteTempShader(tmpDir, "script.fs", fsCode); std::filesystem::path scriptPath = tmpDir / "resource_test.as"; { std::ofstream script(scriptPath); script << "uint shaderId = 0;\n"; script << "uint modelId = 0;\n"; script << "uint materialId = 0;\n"; script << "void Init() {\n"; script << " shaderId = Shader::Load(\"" << vsPath.generic_string() << "\", \"" << fsPath.generic_string() << "\");\n"; script << " modelId = Model::LoadCube(1.0f, 1.0f, 1.0f);\n"; script << " materialId = Material::Create(shaderId, 255, 0, 0, 255);\n"; script << "}\n"; } ShaderManager shaderManager; ModelManager modelManager; MaterialManager materialManager; SetResourceManagers(&shaderManager, &modelManager, &materialManager); ScriptEngine se; TEST_CHECK(se.Initialize() == true); bool compiled = se.CompileScript(scriptPath.string()); TEST_CHECK(compiled == true); asIScriptFunction* initFunc = se.GetInitFunction(); TEST_CHECK(initFunc != nullptr); se.CallScriptFunction(initFunc); asIScriptEngine* engine = se.GetEngine(); TEST_CHECK(engine != nullptr); asIScriptModule* module = engine ? engine->GetModule("main") : nullptr; TEST_CHECK(module != nullptr); auto fetchUInt = [module](const char* name) -> unsigned int { int idx = module->GetGlobalVarIndexByName(name); TEST_CHECK_(idx >= 0, "Global '%s' not found", name); if (idx < 0) return 0; void* address = module->GetAddressOfGlobalVar(idx); TEST_CHECK_(address != nullptr, "Global '%s' address null", name); if (!address) return 0; return *static_cast(address); }; unsigned int shaderId = fetchUInt("shaderId"); unsigned int modelId = fetchUInt("modelId"); unsigned int materialId = fetchUInt("materialId"); TEST_CHECK(shaderId != 0); TEST_CHECK(modelId != 0); TEST_CHECK(materialId != 0); se.Shutdown(); std::filesystem::remove(scriptPath); std::filesystem::remove(vsPath); std::filesystem::remove(fsPath); std::filesystem::remove(tmpDir); ShutdownRaylibHidden(); }