static void RunStabilityEditorChecks() { SpriteEntry sprite{}; sprite.textureId = 13; Check(GetSpriteEntityType(sprite) == ENTITY_ARCHETYPE_GUARD, "zero flags retain legacy guard fallback"); sprite.flags = 0x06026400; Check(GetSpriteEntityType(sprite) == ENTITY_ARCHETYPE_PROP, "explicit Prop matches ASM despite guard texture"); sprite.textureId = 11; sprite.flags = 0; Check(GetSpriteEntityType(sprite) == ENTITY_ARCHETYPE_BARREL, "zero flags retain new legacy barrel fallback"); sprite.flags = 0x06026400; Check(GetSpriteEntityType(sprite) == ENTITY_ARCHETYPE_PROP, "explicit Prop overrides barrel artwork"); for (int health : {1, 100, 255, 256, 300, 500}) { SetSpriteEntityData(sprite, ENTITY_ARCHETYPE_GUARD, health, 2, 6); Check(GetSpriteHealth(sprite) == (health > 255 ? 255 : health), "health setter clamps before byte packing"); } const auto root = fs::absolute("code fixture"); fs::create_directories(root / "include"); const auto first = root / g_ProjectCodeFiles[0].relativePath; const auto second = root / g_ProjectCodeFiles[1].relativePath; { std::ofstream out(first); out << "original"; } { std::ofstream out(second); out << "second"; } CodeEditorState code; code.LoadFile(0, root.string()); Check(std::string(code.textBuffer.data()) == "original", "IDE opens actual source file"); strcpy_s(code.textBuffer.data(), code.textBuffer.size(), "unsaved source"); code.isModified = true; HANDLE locked = CreateFileA(first.string().c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); Check(locked != INVALID_HANDLE_VALUE, "IDE failure fixture locks destination against replacement"); Check(!code.SaveFile(root.string()) && code.isModified && Bytes(first) == std::vector({'o','r','i','g','i','n','a','l'}), "failed IDE replacement preserves disk and modified buffer"); code.LoadFile(1, root.string()); Check(code.currentFile == 0 && code.isModified && std::string(code.textBuffer.data()) == "unsaved source", "IDE refuses file switch after failed autosave"); code.StartBuild(root.string()); Check(!code.isBuilding && code.isModified, "IDE refuses build after failed save"); CloseHandle(locked); Check(code.SaveFile(root.string()) && !code.isModified && Bytes(first) == std::vector({'u','n','s','a','v','e','d',' ','s','o','u','r','c','e'}), "IDE publishes complete source atomically"); code.LoadFile(1, root.string()); Check(code.currentFile == 1 && std::string(code.textBuffer.data()) == "second", "IDE switches after successful save"); fs::remove(first); code.LoadFile(0, root.string()); Check(code.currentFile == 1 && std::string(code.textBuffer.data()) == "second", "failed IDE load preserves current document"); Check(std::distance(fs::directory_iterator(root / "include"), fs::directory_iterator{}) == 1, "failed IDE saves leave no temporary source files"); { std::ofstream out(root / "build.bat"); out << "@echo off\nfor /L %%i in (1,1,4000) do echo compiler-output-%%i\nexit /b 7\n"; } g_CodeEditor.LoadFile(1, root.string()); g_CodeEditor.StartBuild(root.string()); EditorApp hidden; hidden.showCodeEditorModal = false; const auto deadline = GetTickCount64() + 10000; while (g_CodeEditor.isBuilding && GetTickCount64() < deadline) { hidden.RenderCodeEditorWindow(); if (g_CodeEditor.hBuildProcess) WaitForSingleObject(g_CodeEditor.hBuildProcess, 1); } const bool finished = !g_CodeEditor.isBuilding; if (!finished && g_CodeEditor.hBuildProcess) { TerminateProcess(g_CodeEditor.hBuildProcess, 99); WaitForSingleObject(g_CodeEditor.hBuildProcess, 1000); g_CodeEditor.PollBuild(); } Check(finished && g_CodeEditor.buildExitCode == 7 && g_CodeEditor.buildLog.find("compiler-output-4000") != std::string::npos, "hidden IDE drains output larger than pipe capacity and retains exit code"); }