From 003720cf1dc3afa139b953f5bf30b51df4d94b78 Mon Sep 17 00:00:00 2001 From: Maciej Myszkiewicz Date: Sun, 11 Oct 2026 10:13:43 +0200 Subject: [PATCH] test: the shipped layout opens on three full plots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The README and the v0.1.0 notes both promise that the replay opens on GPS position, velocity and the attitude quaternion. Nothing checked it, and the way it would fail is silent: a layout resolves parameters by qualified name, and a name the definition does not declare is dropped with a note rather than an error, because a station that refused to start over a stale layout would be unusable exactly once per mission. So a typo in the shipped file leaves a visitor looking at the empty window the file exists to prevent, and the only sign is a line in the event log. The test restores the layout before the first packet — the order App::new uses, since a parameter's history begins when it is watched — and then asserts all ten plotted parameters hold 7200 points once the recording is decoded. --- crates/xtce-gs-gui/tests/against_a_session.rs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/crates/xtce-gs-gui/tests/against_a_session.rs b/crates/xtce-gs-gui/tests/against_a_session.rs index ce28725..252ffd2 100644 --- a/crates/xtce-gs-gui/tests/against_a_session.rs +++ b/crates/xtce-gs-gui/tests/against_a_session.rs @@ -202,3 +202,72 @@ fn every_panel_fills_from_a_session_that_really_decoded_a_downlink() { events.visible().count() ); } + +/// The layout that ships beside the JPSS definition opens on three full plots. +/// +/// The README and the v0.1.0 notes both say so, which is reason enough to assert it: a layout +/// is resolved by *qualified name* against the definition, and a name that no longer matches +/// is dropped with a note rather than an error — the station starts either way. So a typo in +/// the shipped file would leave a visitor looking at the empty window this layout exists to +/// prevent, and nothing would say why. +#[test] +fn the_shipped_layout_opens_on_three_full_plots() { + let definition = testdata("jpss1_geolocation_xtce_v1.xml"); + let discarded = Layout::load(&definition).expect("the shipped layout is readable"); + assert_eq!( + discarded.note, None, + "the shipped layout was not read whole: {:?}", + discarded.note + ); + let layout = discarded.layout; + assert_eq!( + layout.plots.len(), + 3, + "the README promises position, velocity and the attitude quaternion" + ); + + let (_runtime, session) = replay(); + let db = session.db().clone(); + + // Before the first packet, the order `App::new` uses: history begins when a parameter is + // watched, so restoring after the replay would assert empty plots and pass. + let names: Vec = layout + .plots + .iter() + .flat_map(|plot| plot.parameters.iter().cloned()) + .collect(); + assert_eq!(names.len(), 10, "3 position, 3 velocity, 4 quaternion"); + { + let mut store = session.store().write().expect("store"); + store.set_depth(layout.history_depth); + let resolved = layout.restore(&db, &mut store); + assert_eq!( + resolved, + layout.watched.len() + names.len(), + "the shipped layout names a parameter this definition does not declare" + ); + } + + let deadline = Instant::now() + Duration::from_secs(30); + while Instant::now() < deadline { + if session.stats().snapshot().packets_decoded >= 7200 { + break; + } + std::thread::sleep(Duration::from_millis(20)); + } + assert_eq!(session.stats().snapshot().packets_decoded, 7200); + + let store = session.store().read().expect("store"); + for name in &names { + let parameter = db + .find_parameter(name) + .unwrap_or_else(|| panic!("{name} is not in the definition")); + let depth = store + .history(parameter) + .map_or(0, xtce_gs_core::RingBuffer::len); + assert_eq!( + depth, 7200, + "{name} has {depth} points of history after 7200 packets" + ); + } +}