From 73698677dd105bc39e02647115f36241157b2735 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Sun, 23 Aug 2026 15:36:05 +0800 Subject: [PATCH] test(session): hold the layout readable by the build that has to read it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Session` carries `#[serde(default)]` on the struct, so a field missing there falls back. `SessionPane` and `RemoteTarget` are enums and `RouteSnapshot` is a plain struct, and none of them inherits that — their field defaults are the whole of what stands between an older `session.json` and a window that opens without the layout it saved. Four such fields, held by nothing: a split's ratio, and the user and port on both a direct SSH target and the route cached beside a window. Pinned as the shapes older builds wrote, and re-swept: none of the nine load-bearing defaults in the file can be removed now without failing. `ssh_profile.rs` looked like three more and is not: `SshProfile` has a struct-level `#[serde(default)]`, so removing a field-level one falls through to the `Default` impl, which supplies the same id, port and integration flag. Equivalent mutations, checked rather than assumed — the existing test already decodes a profile with none of those keys. --- crates/tty7-core/src/core/session.rs | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/crates/tty7-core/src/core/session.rs b/crates/tty7-core/src/core/session.rs index 32a6fa27..8cef3ba2 100644 --- a/crates/tty7-core/src/core/session.rs +++ b/crates/tty7-core/src/core/session.rs @@ -568,6 +568,46 @@ mod tests { )) } + /// The session shapes an older build wrote still load. + /// + /// `Session` carries `#[serde(default)]` on the struct, so a missing field + /// there falls back. `SessionPane` and `RemoteTarget` are enums and + /// `RouteSnapshot` is a plain struct — none of them inherits that, so the + /// field defaults on those are what stands between an older + /// `session.json` and a window that opens without the layout it saved. + /// + /// Removing any of the four fails here; nothing held them before. + #[test] + fn a_session_written_by_an_older_build_still_loads() { + // A split written before it recorded a ratio. + let pane: SessionPane = serde_json::from_str( + r#"{"Split":{"axis":"Horizontal","a":{"Leaf":{}},"b":{"Leaf":{}}}}"#, + ) + .expect("a split that predates its ratio still loads"); + match pane { + SessionPane::Split { ratio, .. } => { + assert!(ratio > 0.0 && ratio < 1.0, "and lands on a usable one") + } + other => panic!("expected a split, got {other:?}"), + } + + // A direct SSH target written before it recorded a user or a port. + let target: RemoteTarget = serde_json::from_str(r#"{"kind":"direct","host":"h"}"#) + .expect("a direct target that predates user and port still loads"); + match target { + RemoteTarget::Direct { user, host, port } => { + assert_eq!((user.as_str(), host.as_str(), port), ("", "h", 22)); + } + other => panic!("expected a direct target, got {other:?}"), + } + + // The route cached beside a window, from before it named a user. + let route: RouteSnapshot = serde_json::from_str(r#"{"name":"n","host":"h"}"#) + .expect("a route snapshot that predates user and port still loads"); + assert_eq!(route.user, ""); + assert_eq!(route.port, 22); + } + #[test] fn views_saved_before_the_snapshot_existed_still_load() { // #485 added `RemoteRef.via`; a views file written before it has no