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 c1c316b9; unless a sentence says otherwise, nothing here was built or executed. Commands, presets, test names and CMake behaviour were read at c1c316b9; 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 c1c316b9; 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 CNAEXT graphics-extension suites (the ASCII, CRT and colour-depth effects and DebugDraw). |
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*entries (among themCnaPlatformSdl3X11TestsandCnaPlatformSdl3WaylandTests), 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 platform tests exist only when
SDL3is the selectedCNA_PLATFORM, the Terminal tests only off Windows, the Inspector tests only with the Inspector, the shutdown-ordering suite not on Windows, Emscripten, Android or iOS, 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 DIRECTX9 labels). | The common contract, second-frame, reset and dispose checks and a second-renderer comparison, on a CI host capable of that native API. Configurations that can create a Vulkan device carry the [Vulkan Validation] output gate on every registered renderer test. |
| Platform interface, SDL3, Headless or Terminal | CnaPlatformTests (the display-independent contract, shuffled and repeated, including the SDL3 event-mapper suites) plus CnaPlatformWindowTests. | HEADLESS plus the actual backend host, input snapshot tests, logical and drawable resize and a renderer surface smoke; CnaPlatformSdl3X11Tests and CnaPlatformSdl3WaylandTests for anything that depends on SDL’s video driver; the SDL-free cell when a shared path is touched. A private Xvfb or headless Weston is not a real desktop (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 exercises 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; the maintained C# 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 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. - SDL3 on real window systems.
CnaPlatformSdl3X11Testsruns the SDL3 window suites withSDL_VIDEODRIVER=x11on a private Xvfb started bytools/platform/x11_test_server.sh, andCnaPlatformSdl3WaylandTestswithSDL_VIDEODRIVER=waylandon a private headless Weston started bytools/platform/wayland_test_server.sh; each exits 77 where its server is missing. A result must name the server it came from: an Xvfb or a headless Weston proves protocol behaviour only (no GPU, compositor effects or real input), Xwayland is not native Xorg, and a software renderer must be labelled as one. - Windows. The SDL3 platform’s
windowsvideo driver is exercised by the native MSVC job inplatform-ci.yml, which runs on manual dispatch only; per-monitor DPI, real keyboard and IME stacks and clipboard interoperability on a physical desktop remain things only a person on Windows hardware establishes. - 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 and iOS. 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 or browser run engaged.
- Test populations, counts and structural gates — Which test layer produced a CNA result, what each static count at c1c316b9 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 c1c316b9 and how to report it.
Known issues in this area
Current defects, gaps and limitations at this snapshot that touch this subject.
- CNA-VGAP-016: A plain ctest run of the tests preset is not a trustworthy result — The tests preset builds only CnaTests, yet ctest also runs the display-dependent smoke executables the same configuration registers and reports the unbuilt ones as failed, so CNA's own preset calls a direct CnaTests run
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