What to test after changing X
Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Commands, presets, test names and CMake behaviour were read at 009d40f5; nothing was configured, built or run for this page, and no host-specific result (private display, Wine, Apple, Android, real GPU) is claimed.
Choose tests from the changed contract and host, not from the file extension. A CNA build excludes sources and tests according to its CMake options, so a green run in one configuration says nothing about the others. For every result record the configured platform, audio and renderer axes, the exact test name, the skip count, whether a real native device was used (and which kind), and which other implementations remained untested. Everything on this page was read from the source and CMake at snapshot 009d40f5; none of the commands was run for it.
A repeatable local baseline
# From a CNA checkout with prerequisites and submodules installed:
cmake --preset unit
cmake --build --preset unit
./cmake-build-unit/CnaTests
ctest --test-dir cmake-build-unit -N
The unit configure and build presets select Debug, the STUB renderer, tests on, and examples, C API, networking, FFmpeg video and Draco off (CMakePresets.json). The direct binary runs the aggregate GoogleTest corpus in one process; ctest -N shows what that configured tree registers. The presets define no test presets, so CTest is driven with ctest --test-dir. These commands are source-verified from the preset file, not executed across host types in this documentation pass. Because the STUB renderer draws nothing, a unit run cannot establish rendering behaviour; the oracle choices are in the graphics section below.
For the desktop tests preset, the preset's own description recommends running the CnaTests binary directly, with SDL_AUDIODRIVER=dummy, because ctest runs each discovered case as its own short-lived process, which reports every unbuilt display-dependent graphics smoke executable as failed and races tests that share hard-coded fixture paths. Use CTest for a deliberately selected registered test, label or renderer oracle, and inspect its registration first. A test that exits with code 77 is reported as skipped, not passed (see below); a GTEST_SKIP() inside a GoogleTest binary prints [ SKIPPED ]. Read the skip counts, not the exit colour.
The presets that matter for validation, with the full table in the Building CNA presets section:
| Preset | Configuration | Use it for |
|---|---|---|
unit | Debug, STUB, tests on, no examples or optional modules; the default SDL3 platform is kept, so the SDL submodules are still needed and window-creating tests need a display. Build presets unit (CnaTests), unit-core, unit-math, unit-content, unit-graphics (the focused targets). | Fast, display-free feedback for core, math, content and neutral graphics logic. |
tests | Debug, OPENGLES3, tests and examples on; needs the submodules. | The full local corpus including the audio suites; run CnaTests directly. |
multi-renderer | HEADLESS default with HEADLESS;SOFTWARE;STUB compiled in, chosen at run time; no window, GPU or third-party closure. | Runtime renderer selection and no-display CI. |
cnaext | Debug, OPENGLES3, CNA_CNAEXT=ON, tests on. | The engine-layer (CNAEXT) suites. |
devices-asan, devices-tsan, devices-ubsan | Debug, OPENGLES3, tests, CNA_DEVICES=ON, with the named sanitizer. | Devices and sensor lifetime and race work; not a universal sanitizer matrix. |
macos, ios, ios-simulator | Apple builds; the iOS presets have tests off. The device build is documented as not run on a physical device. | Apple configuration checks; runtime evidence comes from the Apple CI job (the simulator preset's description says it launches the app for one framework frame) and CNA's recorded notes (apple-platforms.md). |
How the test targets are assembled
Read UnitTests.cmake before assuming which tests a configuration contains.
- Object groups. Test sources are globbed from
modules/*/tests(every renderer family's tests form onerenderersgroup; anything else formsintegration) and each group is compiled once into an object librarycna_<group>_test_objects. The same objects feed both the aggregate and the group's focused executable. - Aggregate and focused targets.
CnaTestslinks every group; the focused executables (CnaCoreTests,CnaMathTests,CnaGraphicsTests,CnaContentTests,CnaRuntimeTests,CnaStorageTests,CnaDevicesTests,CnaDevicesExtTests,CnaAudioTests,CnaInputModuleTests,CnaPlatformModuleTestsand the others) areEXCLUDE_FROM_ALLiteration targets. By the file's own comment they are not additional CTest registrations, so the aggregate stays the single default suite in CI. - Two kinds of CTest entry.
gtest_discover_tests(... DISCOVERY_MODE PRE_TEST)registers every case inCnaTestsas its own test at test time, with the source directory as working directory so fixture assets resolve; the discovered cases exist only onceCnaTestsis built. Separate explicit entries run a filtered subset with their own environment, timeout and labels:CnaInputTests(labelinput, shuffled and repeated),CnaAudioPlatformTestsandCnaAudioAlsaTests(audio,platform), theCnaPlatform*,CnaX11*andCnaWayland*entries, theCnaGltfConformance*ladder, theCnaXnb*conformance entries, the configuration-policy entries (labelconfiguration), theCApi_*tests and each renderer family's example tests (Software_*,Vulkan_*,Headless_*,Stub_Smokeand so on, labelled by family). - Source filters. Whole test files are dropped by the configuration: the Sdl3, Sdl2, X11 and Wayland platform tests exist only when that
CNA_PLATFORMis selected, the Inspector tests only with the Inspector, the shutdown-ordering suite not on Windows, Emscripten, Android, iOS or an SDL2-only selection, and so on. Absence fromctest -Nis information; confirm it before reporting a suite as run.
The deeper explanation, with the CI roles, is on Test architecture and change recipes; the generated Test target index lists the declarations.
Minimum loop and broader gate
| Changed area | Fast feedback | Broader evidence before merge |
|---|---|---|
| Math or core | cmake --build --preset unit-math or unit-core; run the focused binary with a filter. | Aggregate CnaTests; the affected graphics or content oracle when coordinates or binary layout change; the C ABI header baseline when a math value's layout is public; more than one compiler for public headers. |
| Game, frame or components | Unit aggregate filtered to GameTest.* and GamePlatformOwnershipTest.*; reproduce removal, failed construction and loading-thread addition explicitly. | Unfiltered CnaTests; one live platform loop; ASan for lifetime and a TSan configuration where races are the concern (thread map); the Emscripten loop route if loop semantics change, because its design note says that a page that merely compiles does not verify it. |
| GraphicsDevice or resources | cmake --build --preset unit-graphics; a focused CnaGraphicsTests filter for the target, state or resource case. | All neutral graphics tests; Software, GL and explicit-GPU comparison; disposal, resize and second-frame oracles; validation layers if GPU-native work changed; a background load and a frame on the GL renderers if the context lease is involved. |
| Vulkan family | A VULKAN-default configuration with examples and tests; the focused Vulkan_* CTest entries under the private GPU wrapper (below). | The relevant family oracle set, the validation and lifetime trace, the neutral graphics tests and one independent renderer; skipped GPU tests reported. The Vulkan output gate fails any CTest whose output contains [Vulkan Validation]. |
| One other renderer | Its family example target or test under the correct default identity, including a pixel assertion where one exists (for example the Software_* entries and the SdlGpu, WebGPU and OpenGL4 labels). | The common contract, second-frame, reset and dispose checks and a second-renderer comparison, on a CI host capable of that native API. OpenGL4 configurations carry the [OpenGL4 GL Error] output gate. |
| Platform interface, Win32, X11, Wayland or SDL | CnaPlatformTests (the display-independent contract, shuffled and repeated) plus the owning event or service mapper fixture (CnaX11MappingTests, CnaWaylandMappingTests, CnaPlatformWindowTests). | HEADLESS plus the actual backend host, input snapshot tests, logical and drawable resize and a renderer surface smoke; the SDL-free X11 cell when a shared path is touched. Win32 under Wine is not native-Windows proof (below). |
| ContentManager or content format | cmake --build --preset unit-content; targeted content tests and malformed input. | Importer, processor, writer and runtime-reader round trip; cache unload; old-format and asset fixtures; GPU resource disposal if textures changed; the CnaXnb* conformance entries. |
| Audio or callbacks | SoundEffect and instance, mixer and device-conformance filters under the selected audio axis (CnaAudioPlatformTests, AudioDeviceConformanceTests). | SDL3 and ALSA where available, since only they carry a mixer; NULL and SDL2 exercise the device contract but not playback; the callback Stop/Close barrier under ASan; the standalone mixer-destroy harnesses (SDL3 audio only, Harnesses.cmake); an actual output-device smoke only where the change claims audible output. |
| C API or public ABI | Enable and build the C API (CNA_BUILD_C_API; the unit preset leaves it off); the pure-C header, handle, error and family tests (CApi_*). | The ELF export check (CApi_Exports), the header baseline (CApiAbiHeaderBaseline, no build needed) and, on a built ELF library, CApiAbiBaseline and CApiDeclaredExports; the wasm link contract; the version policy in ABI_VERSIONING.md; each maintained binding's own tests at its pinned revision. No claim from native CnaTests alone, and no CI workflow builds the C library at this snapshot (CI scope). |
| CMake selector or registry | Configure the expected valid and invalid platform, audio and renderer combinations; inspect the generated registry and ctest -N. | Single- and multi-renderer final links (the multi-renderer preset), fallback and runtime-identity smoke, the SDL-free gate (CnaSdlOffFindsNoSdlPackage and the X11 SDL-free CI cell), the descriptor gate, CnaSdlPrebuiltFingerprint when the vendored SDL build inputs change (it checks that the persistent SDL install is rebuilt, not silently reused, when its source, patch series or configure arguments change) and the affected CI matrix. |
| Test helpers, CTest properties or harnesses | Configure two unlike trees and compare ctest -N before and after; run the configuration-labelled entries. | Confirm that the output gates, working directories, display policy and skip code still attach to a sample of registrations (the display-isolation check reads a configured tree's registrations). |
CTest reports a registered test that exits with code 77 as skipped: UnitTests.cmake applies SKIP_RETURN_CODE 77 to every test registered in its scope and module-local files apply the same convention, so a launcher or fixture that finds no display, GPU or server can skip without failing.
Private displays, GPU hosts and native-host caveats
A test that opens a window must not open it on the developer's desktop, and the evidence it produces is only as good as the host it ran on.
- Display policy.
TestDisplayPolicy.cmakesetsCNA_TEST_DISPLAYempty by default, so a test inherits the caller'sDISPLAYand where windows appear is decided by how the run is launched. A value naming the live display (:0) is honoured only withCNA_TEST_ALLOW_LIVE_DISPLAY=ONand is otherwise reset to empty; on non-Windows hosts every test also carries a guard that stops it connecting to the live Wayland compositor unless an explicitWAYLAND_DISPLAYis exported. - Private GPU display.
run_gpu_tests_private.shruns a build's CTest suite (or, with--exec, one command) on a private headless Weston with a private rootful Xwayland that has DRI3 and therefore presents Vulkan on the real GPU, which Xvfb cannot. It refuses a build tree whose cache forcesCNA_TEST_DISPLAY(exit 2), exits 77 when Xwayland or a compositor is missing, warns when the private display has no DRI3, and lists failures that died on a graphics-profile refusal before their first check, which are test defects and not renderer results. The Wine-based XNA interop tests hang in its private runtime directory and must be excluded or run on their own. It does not build the configuration or prove that the expected oracles were registered. - X11 suites. The X11 entries that need a server run through
tools/platform/x11_test_server.shon a private Xvfb (on a display number the launcher searches for), and the launcher exits 77 where Xvfb or the window manager is absent; the exclusive-fullscreen suite changes display modes and runs only there; the touchscreen suite is opt-in.Testing the X11 backend on a real desktopsays a result must name the server it came from: an Xvfb proves protocol behaviour only (no GPU, compositor or real input), Xwayland is not native Xorg, and a software renderer must be labelled as one. - Wayland suites. The protocol suite brings its own compositor inside the test process; live entries run on headless Weston (software renderer and GL renderer variants) or on GNOME's compositor on a private session bus, and each skips (77) where the compositor is not installed. No Wayland test is meant to reach the desktop it runs on. The site's recorded CI scope lists no Wayland workflow (CI scope), so those runs exist only where a developer makes them.
- Win32. CNA's own document states that everything it knew about the Win32 backend had been measured with MinGW cross-builds under Wine on Linux;
Testing the Win32 backend on native Windowslists what only native Windows can establish (per-monitor DPI, real keyboard and IME stacks, clipboard interoperability, device removal on a real driver). A Wine run is not proof of native DPI or input behaviour. - Other hosts. Metal, Apple, Android, browser and hardware-sensor behaviour each need their own host; report them as not run unless they were.
Device and host-service changes
For sensor registration, callback or shutdown work (Devices and sensor lifetime), build CnaDevicesTests or the aggregate CnaTests in a configuration with CNA_DEVICES=ON (the option defaults to OFF). Start with an exact Accelerometer/Gyroscope or Compass/Motion interleaving test and include, when lifetime changed, NoDispatchAfterStop, same-callback Dispose (DisposeFromWithinOwnCallbackDoesNotDeadlock), other-thread Dispose (ConcurrentDisposeFromMultipleThreadsNeverCorruptsInstanceCount) and the platform session-close barrier (SensorSessionContractTests.CallbackMayDestroyItsOwnSession, PlatformSensorMigrationTests.HandlerMayDisposeItsOwnSensorWithoutDeadlock). Use devices-tsan for races and devices-asan for use-after-free; the devices-tsan preset's description records one pre-existing race in Sharp Runtime's TimeSpan copy constructor, but that text describes an older sharp-runtime: the counters became atomic in sharp-runtime 9c2cb0ae (2026-07-07), which every current sharp-runtime branch contains, so with a current checkout classify any such report instead of suppressing it silently, and treat any new one as worth investigating. The separate shutdown-ordering harness (cna_devices_shutdown_ordering_harness, spawned by DevicesShutdownOrderingTest.*) is required for late-singleton and SDL teardown work; it calls the real SDL_Quit(), so it exists only where SDL3 is configured and is excluded on Windows, Emscripten, Android, iOS and SDL2-only selections. A live Android sensor is needed to establish native queue and orientation behaviour: CNA's own event-contract document leaves the Android backend unverified beyond its fake-backend seam.
For camera, dialog or tray work (Device extensions and host services), the focused CnaDevicesExtTests target covers fake-service parameter translation, unavailable behaviour and owned session and icon destruction; run it only after confirming CNA_DEVICES=ON, then test the selected platform service and the native host. Camera frame upload (Camera::TryAcquireFrame fills a Texture2D) additionally needs a graphics texture path on a real renderer. File-dialog continuation changes need a case for the rejection path: when the platform has no dialog service, FileDialog now delivers an empty result to the callback (FileDialogWithoutAServiceTest.TheCallbackStillFiresSoACallerIsNotLeftWaiting), but when the platform service itself throws, the callback has already been moved and the caller sees a dialog that never opened (FileDialog.cpp).
Verified mechanisms, configuration caveats
cmake --build --preset unit-graphics builds CnaGraphicsTests; the unit preset's aggregate CnaTests must be built separately to run CTest-discovered cases. For a specific test, use the focused binary's --gtest_filter='Suite.Case' or ctest --test-dir cmake-build-unit -R '^Suite.Case$' --output-on-failure after the aggregate exists. Confirm CTest's exact names with -N. Use ctest --test-dir <build-dir> -L input for the intentionally shuffled and repeated input route: CNA_INPUT_TEST_FILTER in UnitTests.cmake is the single source of truth for that label (input-build-and-test.md), so when adding an input suite whose name matches none of its tokens, extend that filter or the label silently excludes it. The route is order-independence evidence for process-wide input state, and it leaves the video driver to the runner because the mouse-cursor tests need real cursors.
For native Vulkan tests use tools/platform/run_gpu_tests_private.sh <build-dir> -R '^Vulkan_' as described above. For sanitizers, devices-asan, devices-tsan and devices-ubsan are real presets with CNA_DEVICES=ON; they are not universal sanitizer matrices. If a different backend or subsystem is affected, configure CNA_SANITIZE (a comma-separated list such as address,undefined; AddressSanitizer and ThreadSanitizer cannot be combined; Emscripten and MSVC are refused) in its own build with CNA_SANITIZE_OPTIMIZATION as needed, and verify that instrumentation reached the target (BuildPerformance.cmake). The test architecture page explains object groups, fixture working directories, labels and CI roles; CMake option index locates the options.
Report evidence honestly
A useful validation note says: “CNA commit X; CNA_PLATFORM=…, CNA_AUDIO_PLATFORM=…, default and compiled renderers; focused case N passed; aggregate M passed; named GPU oracle skipped because no adapter; ASan run on build Y; native Windows not run.” A weak note says “tests pass.” Separate what was checked by reading (source verified), what was built, what was run (with the host kind: private Xvfb, Xwayland, real GPU, Wine, native), what was compared against an oracle and what was observed on hardware; never claim a runtime result that was not executed.
The generated Test target index reports the current number of test declarations; that inventory is a source listing of registrations, not a count of tests guaranteed to run in any one build. Find the target there, then follow its CMake registration and inspect the configured CTest and test-binary output. The site's own statement of what CNA's CI gates, and what it does not, is Verification and known issues: CI.
Storage and filesystem changes
Build the focused CnaStorageTests target and run StorageDeviceDeleteContainerTest.* plus the exception cases, but first verify what its fixture will delete: SetUp calls StorageDevice::SetAppNameEXT("CnaTestsContent002StorageDevice") and TearDown runs remove_all on the resolved storage root. That root comes from the same environment chain as production (XDG_DATA_HOME, LOCALAPPDATA, HOME, then the working directory), so point the relevant variable at a disposable directory, or prefer a disposable isolated environment (storage case study: the oracle). For PathContainment changes, run its core tests and every relevant caller, especially recursive delete, file creation and symlink cases, and keep an outside sentinel; the symlink case skips with GTEST_SKIP where directory symlinks cannot be created, so check the skip count. For app-identity changes, assert the Sharp Runtime .cna_isolated_storage override (AppNameAlsoScopesSharpRuntimeIsolatedStorage) and repeat on Windows with non-ASCII paths, since CNA's records report Windows-only containment failures. The existing tests do not prove a race-proof sandbox or concurrent root switching; record those as unverified rather than as a green test.
Choose the graphics oracle by the failure you could have caused
A fast unit run is not a general renderer sign-off. The snapshot contains several implementations with deliberately different observable outputs. Use the smallest one that can fail for the defect you fear, then add a second implementation or host to challenge the abstraction boundary.
| Evidence level | What it can establish | What it cannot establish |
|---|---|---|
| STUB | Selected Game and GraphicsDevice calls reach a minimal renderer, no-window execution continues, and the public neutral checks still run. The renderer keeps no bookkeeping and creates no render targets. | Backend state correctness, resource data, pixel output or GPU lifetime. |
| HEADLESS renderer, mainly in its Validation and Trace modes | Selected argument and state rules (Validation throws a named exception), the live-resource registry with leak assertion, call counts and deterministic call-order drift (Trace); refusal of render-target readback. | Rendered pixels, shader semantics, native surface or synchronization. A shared pixel fixture may pass by asserting refusal. |
| SOFTWARE | Implemented CPU draw, target, resolve and readback pixels; a differential check against a native backend. | GPU driver and API barriers, and Software shader or format paths that are not implemented. |
| Affected native renderer on a supporting host | Real graphics API, shader, surface, present and device-lifetime behaviour for that configured driver, with the renderer's output gate where one applies. | Other renderers or platforms that were not built and run. |
Where a change could alter what a user sees compared with real XNA, the reference-image corpus is a further oracle with its own limits: see Using the XNA oracle as evidence. Neither it nor any row above is established by this page; the tests named here exist in the source and were not executed.
Worked decision. If you change a neutral render-target readback guard, STUB can exercise some argument validation and HEADLESS can prove that a non-rasterizer refuses fabricated data, but neither can prove target color. Run a Software target and readback pixel fixture (ctest -N -R '^Software_' lists the family's entries), then the relevant Vulkan, SDL_gpu or EasyGL native oracle, and inspect ctest -N and the fixture's renderer-specific branches so that “pass” does not secretly mean “pixel check skipped”. If you change a descriptor or no-window construction path, run both Headless_Smoke and Stub_Smoke where configured, then a real-window renderer. Their registration is conditional: the HEADLESS fixtures register only when HEADLESS is the default renderer identity, and Stub_Smoke only when the STUB family is in scope, so confirm with ctest -N. STUB's fixture links SDL3 unconditionally even though the STUB renderer does not, so an SDL-free build must not be reported as having run that test; the HEADLESS fixtures link SDL3 only when it is configured.
Deep dives on this topic
Long-form pages that explain the exact semantics, invariants and evidence behind this subject.
- Compatibility levels and the evidence vector — The distinct levels of XNA compatibility CNA keeps apart, the evidence vocabulary used across the site, what each renderer class can prove, and how to state a verification claim.
- Oracles, tolerances and engagement gates — The oracles CNA uses (real XNA, FNA, derived tables, cross-renderer controls, own goldens), their authority and tolerances, and the gates that prove a Wine, Proton or browser run engaged.
- Test populations, counts and structural gates — Which test layer produced a CNA result, what each static count at 009d40f5 counts, why no CTest total exists, and how identity, containment, inventory and mutation gates work.
- Tests, examples, presets and tools: what each verdict proves — What a green result from CNA's test corpus, examples, golden images, CMake presets and developer tools actually establishes, sorted by authority class, and how to read a result before citing it.
- Verification tiers: evidence forms, oracle authority and CI reporting — A decoding key for CNA verification claims: claim labels, what each evidence form establishes, which authority decides which question, what CI runs at 009d40f5 and how to report it.
Known issues in this area
Current defects, gaps and limitations at this snapshot that touch this subject.
- CNA-BUG-201: StorageDeviceDeleteContainerTest writes to and deletes inside the developer's real per-user data directory — The StorageDevice deletion tests resolve their fixture root from the real XDG_DATA_HOME/LOCALAPPDATA/HOME environment, remove_all() it in TearDown, and then recreate the default game's save directory, while a comment sti
- CNA-VGAP-016: A plain ctest run of the tests preset is not a trustworthy result — CNA's own tests preset records that ctest reports unbuilt display-dependent smoke executables as failed and races tests that share hard-coded /tmp fixture paths across processes, so only a direct CnaTests run is authorit
Related pages
The same subsystem is explained at four altitudes. These are the neighbouring pages at each one.
- User guide
- Building CNA: presets · Building CNA: tests · Verification: CI scope
- Architecture
- Architecture
- Maintainer workflow
- Blast radius and readiness · Thread and callback map · Using the XNA oracle as evidence
- Tests and validation
- Test architecture and change recipes · Testing handbook
- Reference
- Test target index · CMake option index