What to test after changing X

CNA snapshot c1c316b9  ·  Development › Human Takeover  ·  source links pinned to c1c316b9

✓

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:

PresetConfigurationUse it for
unitDebug, 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.
testsDebug, OPENGLES3, tests and examples on; needs the submodules.The full local corpus including the audio suites; run CnaTests directly.
multi-rendererHEADLESS 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.
cnaextDebug, 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-ubsanDebug, OPENGLES3, tests, CNA_DEVICES=ON, with the named sanitizer.Devices and sensor lifetime and race work; not a universal sanitizer matrix.
macos, ios, ios-simulatorApple 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 one renderers group; anything else forms integration) and each group is compiled once into an object library cna_<group>_test_objects. The same objects feed both the aggregate and the group's focused executable.
  • Aggregate and focused targets. CnaTests links every group; the focused executables (CnaCoreTests, CnaMathTests, CnaGraphicsTests, CnaContentTests, CnaRuntimeTests, CnaStorageTests, CnaDevicesTests, CnaDevicesExtTests, CnaAudioTests, CnaInputModuleTests, CnaPlatformModuleTests and the others) are EXCLUDE_FROM_ALL iteration 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 in CnaTests as its own test at test time, with the source directory as working directory so fixture assets resolve; the discovered cases exist only once CnaTests is built. Separate explicit entries run a filtered subset with their own environment, timeout and labels: CnaInputTests (label input, shuffled and repeated), CnaAudioPlatformTests and CnaAudioAlsaTests (audio, platform), the CnaPlatform* entries (among them CnaPlatformSdl3X11Tests and CnaPlatformSdl3WaylandTests), the CnaGltfConformance* ladder, the CnaXnb* conformance entries, the configuration-policy entries (label configuration), the CApi_* tests and each renderer family's example tests (Software_*, Vulkan_*, Headless_*, Stub_Smoke and so on, labelled by family).
  • Source filters. Whole test files are dropped by the configuration: the Sdl3 platform tests exist only when SDL3 is the selected CNA_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 from ctest -N is 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 areaFast feedbackBroader evidence before merge
Math or corecmake --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 componentsUnit 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 resourcescmake --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 familyA 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 rendererIts 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 TerminalCnaPlatformTests (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 formatcmake --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 callbacksSoundEffect 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 ABIEnable 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 registryConfigure 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 harnessesConfigure 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.cmake sets CNA_TEST_DISPLAY empty by default, so a test inherits the caller's DISPLAY and where windows appear is decided by how the run is launched. A value naming the live display (:0) is honoured only with CNA_TEST_ALLOW_LIVE_DISPLAY=ON and 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 explicit WAYLAND_DISPLAY is exported.
  • Private GPU display. run_gpu_tests_private.sh runs 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 forces CNA_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. CnaPlatformSdl3X11Tests runs the SDL3 window suites with SDL_VIDEODRIVER=x11 on a private Xvfb started by tools/platform/x11_test_server.sh, and CnaPlatformSdl3WaylandTests with SDL_VIDEODRIVER=wayland on a private headless Weston started by tools/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 windows video driver is exercised by the native MSVC job in platform-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 levelWhat it can establishWhat it cannot establish
STUBSelected 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 modesSelected 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.
SOFTWAREImplemented 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 hostReal 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.

The same subsystem is explained at four altitudes. These are the neighbouring pages at each one.

Architecture
Architecture