Prevent tests from writing to user data

This commit is contained in:
2026-02-27 05:39:33 +00:00
parent a088075924
commit da907c0f46
7 changed files with 330 additions and 155 deletions

View File

@@ -0,0 +1,35 @@
# Prevent Tests from Writing to Real User Data
## Context
Two tests in `src/app.rs` (`adaptive_auto_continue_arms_input_lock` and `adaptive_does_not_auto_continue_with_milestones`) call `App::new()` which connects to the real `JsonStore` at `~/.local/share/keydr/`. When they call `finish_drill()``save_data()`, fake drill results get persisted to the user's actual history file. All other app tests also use `App::new()` but happen to not call `finish_drill()`.
## Changes
### 1. Add `#[cfg(not(test))]` gate on `App::new()` (`src/app.rs:293`)
Mark `App::new()` with `#[cfg(not(test))]` so it cannot be called from test code at all. This is a compile-time guarantee — any future test that tries `App::new()` will fail to compile.
### 2. Add `App::new_test()` (`src/app.rs`, in `#[cfg(test)]` block)
Add a `pub fn new_test()` constructor inside a `#[cfg(test)] impl App` block that mirrors `App::new()` but sets `store: None`. This prevents any persistence to disk. All existing fields get their default/empty values (no loading from disk either).
Since most test fields just need defaults and a started drill, the test constructor can be minimal:
- `Config::default()`, `Theme::default()` (leaked), `Menu::new()`, `store: None`
- Default key stats, skill tree, profile, empty drill history
- `Dictionary::load()`, `TransitionTable`, `KeyboardModel` — same as production (needed for `start_drill()`)
- Call `start_drill()` at the end (same as `App::new()`)
### 3. Update all existing tests to use `App::new_test()`
Replace every `App::new()` call in the test module with `App::new_test()`. This covers all 7 tests in `#[cfg(test)] mod tests`.
## File to Modify
- `src/app.rs` — gate `new()`, add `new_test()`, update test calls
## Verification
1. `cargo test` — all tests pass
2. `cargo build` — production build still compiles (ungated `new()` available)
3. Temporarily add `App::new()` in a test → should fail to compile