CNA-BUG-201: StorageDeviceDeleteContainerTest writes to and deletes inside the developer's real per-user data directory
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. Nothing on this page was executed unless the Evidence section says so.
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 still reasons about an SDL preference path.
- Identifier
CNA-BUG-201- Category
- Bug
- Subsystem
- Testing & evidence
- Status
- Open
- Verified against
- CNA
009d40f5(009d40f5dd085c4e674d3479675fac84b12b3e0a) - Severity
- Low (a triage suggestion, not a project priority)
- Evidence basis
- Source-verified: read at TARGET, not executed
- Tests touching this area
- Yes: see Current tests
- Affected contract
- StorageDeviceDeleteContainerTest fixture (SetUp, TearDown) in CnaTests
Expected behaviour
The fixture's own comment promises that every test is isolated “to its own real, disposable storage root” and avoids “the real user's storage state”. A test should therefore run inside a sandbox it creates (a temporary directory named through the environment variables StorageDevice reads) and leave nothing behind.
Actual behaviour at TARGET
SetUp sets the application name CnaTestsContent002StorageDevice and takes the root StorageDevice::EnsureStorageRoot resolves from the caller's real environment (XDG_DATA_HOME, LOCALAPPDATA, HOME, else the working directory). TearDown calls std::filesystem::remove_all on it and then SetAppNameEXT(""), which re-resolves the root for the default application name game and creates <data root>/game: the directory every CNA game without an application name saves into. The CnaTests registration sets no storage environment, and concurrent test processes share the fixed directory. The comment in EscapingTitleNameThrowsAndDeletesNothing still justifies its escape path with “a SDL pref-path directory is always several levels deep”, which no longer describes the root.
Source locations
modules/storage/tests/Microsoft/Xna/Framework/Storage/StorageDeviceTests.cpp— StorageDeviceDeleteContainerTest SetUp/TearDown; EscapingTitleNameThrowsAndDeletesNothing commentmodules/storage/src/StorageDevice.cpp— EnsureStorageRoot (environment-derived root, create_directories), SetAppNameEXTmodules/gamer-services/tests/Microsoft/Xna/Framework/GamerServices/GamerServicesGamerTests.cpp— GamerServicesStoreGuard sets a fixed application name under the real rootmodules/gamer-services/src/Internal/LocalGamerServicesStore.cpp— ResetStoreForTestingEXT removes only the GamerServices subdirectorycmake/UnitTests.cmake— CnaTests gtest_discover_tests environment carries no storage variablemodules/c-api/CMakeLists.txt— CApi_StorageSmoke sets XDG_DATA_HOME into the build tree
Evidence
Checked by reading StorageDeviceTests.cpp and StorageDevice.cpp at 009d40f5. The escape assertions stay valid, because extra .. segments stop at the filesystem root; the problem is where the fixture writes, not what it asserts. Not executed.
Independently observed as a separate finding (merged): StorageDeviceDeleteContainerTest and GamerServicesStoreGuard use fixed application names under the real per-user data root, delete their directories and leave others behind, because the CnaTests registration sets no storage environment.
Focused reproduction
Illustrative: with XDG_DATA_HOME unset on Linux, run CnaTests --gtest_filter=StorageDeviceDeleteContainerTest.*; afterwards ~/.local/share/game exists even if it did not before.
Current tests
The fixture itself is the affected code. GamerServicesGamerTests.cpp' store guard, which the fixture cites as its model, is not part of this entry.
Regression test
Make the fixture point XDG_DATA_HOME (and LOCALAPPDATA on Windows) at a fresh temporary directory before the first SetAppNameEXT, restore the previous values afterwards, and assert that the real data root is untouched.
Blast radius
Developers and CI hosts that run CnaTests without redirecting the data root: an empty game directory appears in the real per-user data directory, and parallel test processes race on one fixed directory. The storage implementation itself is not affected.
Workaround
Run CnaTests with XDG_DATA_HOME (Linux) or LOCALAPPDATA (Windows) pointing at a throw-away directory.
Related pages
The same subject is explained at several altitudes. These are the neighbouring pages at each one.
- User guide
- Storage: the storage root
- Internals
- Storage module internals: tests
- Maintainer workflow
- Case study: storage deletion · Validation: storage
- Tests and validation
- Testing: recipes
- Known issues
- Bug index