Skip to content

Testing

Snowpulse's automated suite is platform-neutral by default. Tests exercise engine contracts with generated data or small fixtures under snowpulse/tests/fixtures; they must not depend on an application in examples/ or on application-owned assets.

Engine contributor guide

This page documents Snowpulse's own regression suite and requires a full engine source checkout. Running or extending this suite is not part of creating and building a standalone client game. For the normal SDK project workflow, begin with Getting Started and use the build instructions generated in your game's README.md.

Run the Suite

Tests are enabled by default for a native repository build. Configure, build, and run them through CTest:

cmake -S . -B cmake-build-debug \
    -DCMAKE_BUILD_TYPE=Debug \
    -DSNOWPULSE_BUILD_TESTS=ON
cmake --build cmake-build-debug --target snowpulse_tests -j4
ctest --test-dir cmake-build-debug --output-on-failure

CTest also registers SDK/CLI integration tests when Bash is available, web-bridge tests when Node.js is available, and structural documentation and asset-pack tests when Python 3 is available. List exactly what the current machine can run with:

ctest --test-dir cmake-build-debug --show-only
ctest --test-dir cmake-build-debug --print-labels

Use labels for a focused pass:

ctest --test-dir cmake-build-debug -L native --output-on-failure
ctest --test-dir cmake-build-debug -L web --output-on-failure
ctest --test-dir cmake-build-debug -L docs --output-on-failure
ctest --test-dir cmake-build-debug -L snowgears --output-on-failure
ctest --test-dir cmake-build-debug -L sdk --output-on-failure

snowpulse_web_tests is an optional convenience build target for running all Node.js bridge scripts directly. CTest remains the canonical full-suite runner.

Coverage Map

The suite is split by public contract so a future change has an obvious place for regression coverage.

Area Representative coverage
Runtime Node hierarchy, reparenting, component registries, active traversal, transforms, deferred destruction, update/late-update ordering
Actions Every action factory, easing endpoints, sequence/parallel behavior, callbacks, runner mutation and clearing
Events Immediate and queued dispatch, subscription lifetime, filtering, reentrancy, unsubscribe and clear behavior
Input Key/action/axis state, mouse buttons and wheel, multi-touch, primary-touch compatibility, cancel and per-frame reset
UI Anchors, fixed/responsive canvases, stack/grid layout, ordering, clipping, pointer capture, scrolling and deferred destruction
Rendering Primitive, image, font, line, Spine/FBX guards, render-item state, component destruction and default resources
Assets Filesystem and custom sources, manager routing, optional web packs, transitive Tiled pack dependencies, atlas/font/texture loading and PCM conversion
Content runtimes Tiled JSON schemas, references/templates, array/base64 compression, finite/infinite maps, orthogonal/isometric projection, neutral object data and mutation; particle modules and serialization, physics components, audio loading and playback
Services HTTP parameter/result contracts, save synchronization/migration, analytics payloads and bridges, MIDI, portal defaults, application context and utilities
Web portals Analytics, CrazyGames, Playgama and YouTube bridges; initialization, ads, saves, callbacks, failures and banner lifecycle
SDK and CLI Standalone and engine-tree generation, safe updates, managed-file preservation, template refresh and path validation
Documentation Navigation completeness, internal links/anchors, sample presence and project-neutral wording

Platform backends that require an SDK, browser, simulator, device, permissions, or graphics context still need their platform smoke tests. Keep their portable state machines and bridge logic covered here, then record the manual matrix in the relevant platform guide.

For a focused Tiled and packaging pass after configuring, use:

ctest --test-dir cmake-build-debug \
  -R 'tiled|web_asset_packs|zstd_packaging' --output-on-failure

The C++ suites use generated or checked-in fixtures for schema, malformed input, external-reference, compression, chunk-bound, projection, render-data, query, and mutation contracts. The Python web-pack suite independently checks the Tiled dependency graph and pack assignment failures. Platform smoke tests still need an Emscripten browser build, an iOS simulator/device, and Android emulator/device because host tests do not exercise their packaged asset providers or graphics contexts.

Adding a Regression Test

Prefer adding a case to the narrowest existing suite. Create a new executable only when the feature has a distinct public contract or substantially different setup. Register native tests with snowpulse_add_engine_test in snowpulse/tests/CMakeLists.txt; register scripts with add_test and a web or docs label. The structural documentation test rejects any top-level test source or SDK test script that is not registered, preventing silent orphan suites.

Tests should:

  • use CHECK-style assertions that remain active in Release builds;
  • cover success, invalid input, failure recovery, lifetime, and repeat-call behavior where the API supports them;
  • verify externally visible state instead of private implementation details;
  • generate temporary files in a unique directory and clean them up with RAII;
  • use minimal fixtures under snowpulse/tests/fixtures when generated data is impractical;
  • avoid network access, wall-clock sleeps, named applications, and files under examples/.

For example, a new engine contract test follows this shape:

#include <runtime/overlap_checker.h>

#include "test_support.h"

namespace {
bool separatedCirclesDoNotOverlap() {
    snowpulse::OverlapChecker overlap;
    SNOWPULSE_CHECK(!overlap.circleVsCircle(
        { 0.0f, 0.0f }, 1.0f, { 3.0f, 0.0f }, 1.0f));
    return true;
}
}

int main() {
    const snowpulse::test::TestCase tests[] {
        { "separated circles do not overlap", separatedCirclesDoNotOverlap },
    };
    return snowpulse::test::runTests(tests, "overlap regression");
}

Run both Debug and Release after changing assertions, ownership, callbacks, or deferred work. Release catches accidental reliance on the standard assert macro, which is compiled out when NDEBUG is defined.