use super::*;
use std::sync::Arc;
fn database() -> (tempfile::TempDir, Arc<wsb::persist::global::service::DatabaseService>) {
let dir = tempfile::tempdir().expect("a scratch directory");
let config = wsb::persist::global::config::DatabaseConfig {
db_path: dir.path().join("wsb.db").display().to_string(),
db_max_connections: 2,
..Default::default()
};
let service = Arc::new(
wsb::persist::global::service::DatabaseService::new(&config).expect("a database"),
);
service.run_migrations(wsb::persist::global::Schema::Worktree).expect("the schema is current");
(dir, service)
}
fn save(
service: &Arc<wsb::persist::global::service::DatabaseService>,
root: &str,
json: &str,
) {
let conn = service.get_connection().expect("a connection");
conn.execute(
UPSERT_LAYOUT,
rusqlite::params![root, json],
)
.expect("the layout is saved");
}
fn read(
service: &Arc<wsb::persist::global::service::DatabaseService>,
root: &str,
) -> Option<String> {
use rusqlite::OptionalExtension;
let conn = service.get_connection().expect("a connection");
conn.query_row(
SELECT_LAYOUT,
[root],
|row| row.get::<_, String>(0),
)
.optional()
.expect("the read succeeds")
}
#[test]
fn test12026_a_layout_is_saved_and_read_back() {
let (_dir, service) = database();
let root = "/Users/somebody/ws/prj/machinefabric/main-worktree";
assert_eq!(read(&service, root), None, "a fresh workspace has no layout");
save(&service, root, r#"{"groups":[],"active_group_id":"group:1"}"#);
assert_eq!(
read(&service, root).as_deref(),
Some(r#"{"groups":[],"active_group_id":"group:1"}"#)
);
save(&service, root, r#"{"groups":[],"active_group_id":"group:2"}"#);
assert_eq!(
read(&service, root).as_deref(),
Some(r#"{"groups":[],"active_group_id":"group:2"}"#),
"a second save did not replace the first"
);
let conn = service.get_connection().expect("a connection");
let rows: i64 = conn
.query_row("SELECT count(*) FROM workbench_state", [], |row| row.get(0))
.expect("the count reads");
assert_eq!(rows, 1, "saving twice left {rows} rows");
}
#[test]
fn test12027_each_workspace_keeps_its_own_layout() {
let (_dir, service) = database();
save(&service, "/ws/one", r#"{"which":"one"}"#);
save(&service, "/ws/two", r#"{"which":"two"}"#);
assert_eq!(read(&service, "/ws/one").as_deref(), Some(r#"{"which":"one"}"#));
assert_eq!(read(&service, "/ws/two").as_deref(), Some(r#"{"which":"two"}"#));
}
#[test]
fn test12028_a_tabs_opaque_input_is_not_reshaped() {
let (_dir, service) = database();
let root = "/ws/one";
let sent = serde_json::json!({
"groups": [{
"id": "group:1",
"tabs": [{
"id": "op-output:b54a0de8-9784-48a5-9a3d-735b3257ba54",
"label": "suite ยท default",
"description": "Operation output",
"input": {"kind": "op-output", "opId": "b54a0de8", "nested": {"deep": [1, 2]}},
"pinned": false
}],
"active_tab_id": "op-output:b54a0de8-9784-48a5-9a3d-735b3257ba54"
}],
"active_group_id": "group:1",
"sidebar_open": true,
"sidebar_active_container_id": "explorer",
"activity_bar_order": ["explorer"],
"bottom_panel_open": false,
"bottom_panel_height": 200,
"bottom_panel_active_id": "output",
"bottom_panel_order": ["output"],
"expanded_paths": ["src"]
});
let parsed: PersistedWorkbenchState =
serde_json::from_value(sent.clone()).expect("the wire type parses what the frontend sends");
save(
&service,
root,
&serde_json::to_string(&parsed).expect("it serializes"),
);
let back: PersistedWorkbenchState =
serde_json::from_str(&read(&service, root).expect("it was saved")).expect("it reads back");
assert_eq!(back.groups.len(), 1);
let tab = &back.groups[0].tabs[0];
assert_eq!(tab.id, "op-output:b54a0de8-9784-48a5-9a3d-735b3257ba54");
assert_eq!(
tab.input,
serde_json::json!({"kind": "op-output", "opId": "b54a0de8", "nested": {"deep": [1, 2]}}),
"the tab's opaque input was reshaped on the way through"
);
assert_eq!(back.expanded_paths, vec!["src".to_string()]);
}