test: introduce a GoogleTest unit-test harness covering the engine-logic core - #181
Merged
Conversation
Introduce a unit-test suite under tests/, built on GoogleTest (fetched from source via FetchContent, matching the SDL3/GLM/glslang approach) and registered with ctest. A standalone AlphaEngineTests executable compiles the device-free subsystem sources directly, so the suite links no GPU or window code and runs headless. Coverage (all device-free): - core/math: vec2/3/4, mat3/4, quat, aabb, sphere, frustum, scalar lerp - core::pool: insert/get/erase, generation invalidation, slot recycling - core::event_bus: emit, type keying, enqueue/flush ordering and deferral - core::jobs: parallel_for coverage/correctness, dispatch + wait_idle Gated behind ALPHAENGINE_BUILD_TESTS (default ON). tests/ is kept out of the clang-format/clang-tidy scope.
The asset cache and the reference-counted asset handles (texture_asset, mesh_asset) reached the gpu device through the runtime::current_engine() global, including from their destructors. That coupled the whole asset layer — and anything linking it — to the engine, the window, and both gpu backends. Route them through a small accessor instead: rendering_engine::asset_device(), installed by the engine via set_asset_device() once the device is live and cleared as it is torn down. Production behaviour is unchanged (the accessor returns the engine's device), but the asset layer can now be exercised against a fake device with no engine, window, or backend present.
runtime::node: parent/child links and re-parenting, cached world matrices, world_position/set_world_position, find, active/effective-active flags, and the component-store attach/get/remove path — all device-free. asset_cache: dedup by structural key, builder-runs-only-on-miss, collect_unused weak-ref semantics, and that a mesh_asset frees its GPU buffers when the last handle drops. A test_support::fake_device implements the gpu device interface with recording stubs and is installed via set_asset_device, so the cache is exercised headless with no engine or backend linked.
TommyRadan
force-pushed
the
test/unit-test-harness
branch
from
June 16, 2026 20:49
6dc3420 to
9bd1db8
Compare
M_PI is a POSIX extension that MSVC does not define without _USE_MATH_DEFINES, so the math tests failed to compile in the Windows CI build. Use a local constexpr pi constant instead.
SDL3 is built from source via FetchContent and its CMake requires X11 (or Wayland) development libraries on Linux, or configure fails — even though the device-free tests never open a window. Install the X11 dev packages so the job configures.
CI build artifactsWindows Debug and Release builds are attached to the workflow run summary under Artifacts:
Run #243 — commit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a unit-test suite under
tests/, built on GoogleTest (fetched from source viaFetchContent, matching the SDL3/GLM/glslang approach) and registered with ctest. A standaloneAlphaEngineTestsexecutable compiles the device-free subsystem sources directly, so the suite links no GPU or window code and runs headless. Gated behindALPHAENGINE_BUILD_TESTS(defaultON); a new Linux CI job builds and runs it on every push/PR.This is a pure addition (plus one small, behaviour-preserving refactor noted below) — no engine behaviour changes.
Coverage (97 tests, all device-free)
core/math—vec2/3/4,mat3/4,quat,aabb,sphere,frustum, scalarlerpcore::pool— insert/get/erase, generation-based handle invalidation, slot recyclingcore::event_bus—emit, type keying,enqueue/flushFIFO ordering and in-flush deferralcore::jobs—parallel_forcoverage/correctness,dispatch+wait_idleruntime::node— transform hierarchy, cached world matrices,find, active/effective-active flags, component-store attach/get/removeasset_cache— dedup by key, builder-runs-only-on-miss,collect_unused()weak-ref semantics, GPU-buffer release on last-handle dropThe one refactor
To exercise the asset layer headless,
asset_cacheand the reference-counted asset handles (texture_asset,mesh_asset) now resolve their gpu device through a small accessor —rendering_engine::asset_device()— instead of reaching into theruntime::current_engine()global. The engine installs the live device viaset_asset_device()(identical production behaviour); tests install a lightweighttest_support::fake_device. This keeps the cache tests in the same lean, headless binary rather than dragging both gpu backends + glslang into the test target.Conventions
tests/is intentionally kept out of the clang-format/clang-tidy scope (GoogleTest macros don't fit thesnake_casegate). Documented indocs/testing.mdandCLAUDE.md.snake_caseand follow the surrounding Allman/4-space style.Validation
AlphaEnginebinary builds and links cleanly with the asset-device refactor.Not in scope (follow-ups)
asset_cache::load_texture/load_fontdecode paths (need fixture files) — only the mesh path is tested.core::settings/core::time(trivially device-free, just not in issue 166's target list).Closes #166