test: integration-test the mode persist-on-unload wiring (#14)

The post-/runda DA pass on 4cd574b found the persist-on-unload wiring
(quit + project switch calling Database::set_mode) had no integration
test — only the db-level set_mode behaviour was covered, not that the
runtime actually invokes it on unload.

Add runtime::switch_persists_the_outgoing_projects_mode, driving the
real handle_project_switch end-to-end and asserting the outgoing
project's project.yaml recorded the mode it was left in. Red-first
verified: with the set_mode call disabled it fails (None vs
Some(Advanced)). The quit unload site shares the same set_mode call;
Action::Quit emission is already covered in app tests.

Updates ADR-0015 Amendment 1 coverage note.
This commit is contained in:
claude@clouddev1
2026-06-02 08:06:48 +00:00
parent 4cd574b909
commit 516848ff63
2 changed files with 62 additions and 3 deletions
+7 -3
View File
@@ -677,9 +677,13 @@ time").
(the teacher-export round-trip); `cli` `--mode` parse/precedence; (the teacher-export round-trip); `cli` `--mode` parse/precedence;
`app::{mode_command_changes_mode_and_emits_persist_action, `app::{mode_command_changes_mode_and_emits_persist_action,
mode_command_via_one_shot_escape_persists_advanced, mode_command_via_one_shot_escape_persists_advanced,
project_switched_event_restores_the_stored_mode}`. The runtime's project_switched_event_restores_the_stored_mode}`;
unload call sites (quit + `handle_project_switch`) are thin `runtime::switch_persists_the_outgoing_projects_mode` — an
wiring over the tested `Database::set_mode`. integration test driving the real `handle_project_switch` to
prove the unload wiring calls `set_mode` (red-first verified).
The quit unload site shares that `set_mode` call; the
`Action::Quit` emission is covered by `app`'s
`quit_command_returns_quit_action` / `ctrl_c_returns_quit_action`.
### Relationship to the Iteration 6 backlog ### Relationship to the Iteration 6 backlog
+55
View File
@@ -3434,4 +3434,59 @@ mod tests {
"single-line FK echo when the child column already existed", "single-line FK echo when the child column already existed",
); );
} }
#[tokio::test]
async fn switch_persists_the_outgoing_projects_mode() {
// ADR-0015 mode-restore amendment (issue #14), persist on
// unload — exercised through the real `handle_project_switch`
// path, not just the db-level `set_mode`. Proves the wiring
// calls `set_mode` on the outgoing project before it is
// dropped. The outgoing project is *named* so it survives the
// switch (an unmodified temp would be cleaned up, taking its
// project.yaml with it). Without the unload persist the
// outgoing skeleton carries no `mode:` → `None`.
use super::{handle_project_switch, Session, SwitchRequest};
use crate::db::Database;
use crate::mode::Mode;
use crate::persistence::Persistence;
use crate::project::{projects_dir, Project};
use tokio::sync::mpsc;
let data_root = tempfile::tempdir().unwrap();
let projects = projects_dir(data_root.path());
std::fs::create_dir_all(&projects).unwrap();
let outgoing_path = projects.join("Outgoing");
let outgoing = Project::create_named(&outgoing_path).unwrap();
let db_path = outgoing.db_path();
let persistence =
Persistence::new(outgoing.path().to_path_buf()).with_mode(Mode::Advanced);
let database =
Database::open_with_persistence_and_undo(&db_path, persistence, true).unwrap();
let mut session = Session {
project: Some(outgoing),
database: Some(database),
data_root: data_root.path().to_path_buf(),
};
// Keep the receiver alive so the switch's events aren't sent
// into a closed channel.
let (tx, _rx) = mpsc::channel(64);
// Switch away to a fresh temp; the App's live mode here is
// Advanced (the outgoing project's mode).
handle_project_switch(
&mut session,
SwitchRequest::NewTemp,
"new".to_string(),
&tx,
true,
Mode::Advanced,
)
.await;
assert_eq!(
Persistence::read_stored_mode(&outgoing_path),
Some(Mode::Advanced),
"switching away must persist the outgoing project's mode",
);
}
} }