ElyShow: a slide size the kernel did not take stops showing (S-09)

This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 21:23:25 -04:00
1 parent da81ebd777
commit f01150be05
7 files changed
+82 -13

No files matched your search

+2 -6
View File
@@ -220,6 +220,7 @@ impl Deck {
}
(tab.extra.reading, tab.extra.read) = (true, Some(seen));
let landed = tab.extra.transition_landed(view.read(cx));
let sized = tab.extra.size_landed(view.read(cx));
let doc = tab.doc.clone();
ely_lok::read_off(
&self.core.worker,
@@ -296,12 +297,6 @@ impl Deck {
{
tab.extra.stale = tab.extra.thumbs.keys().cloned().collect();
}
let read = crate::design::mm100(size);
if tab.extra.size_asked.is_some_and(|(w, h)| {
(w - read.0).abs() <= 50 && (h - read.1).abs() <= 50
}) {
tab.extra.size_asked = None;
}
(tab.extra.slides, tab.extra.design) = (slides, Some(design));
tab.extra.objects = Some(objects);
(tab.extra.notes, tab.extra.remarks) = (Some(notes), remarks);
@@ -309,6 +304,7 @@ impl Deck {
tab.extra.settle_transition(landed);
tab.extra.reads += 1;
tab.extra.size = size;
tab.extra.settle_size(sized);
tab.extra.failed.clear();
deck.paint_next(id, cx);
deck.read_fonts(id, cx);
+12 -3
View File
@@ -59,9 +59,18 @@ impl Deck {
log::info!("show: the slides already measure {w} x {h}");
return;
}
tab.extra.size_asked = Some((w, h));
let (w, h) = (w.to_string(), h.to_string());
self.design_command("slide.size", &[&w, &h, "true"], cx);
let (id, view) = (tab.id, tab.view.clone());
let before = view.read(cx).sent();
tab.extra.size_asked = Some(((w, h), before + 1));
let (sw, sh) = (w.to_string(), h.to_string());
self.run_in(Some(id), "slide.size", &[&sw, &sh, "true"], cx);
// Refused before sending: run_in said so already.
if view.read(cx).sent() == before
&& let Some(tab) = self.tab_mut(id)
{
tab.extra.size_asked = None;
}
self.force_reread(id, cx);
}
/// Enters or leaves the master view.
+19 -3
View File
@@ -37,8 +37,8 @@ pub struct Extra {
pub size: (i64, i64),
/// Undo and redo lists at the last read.
pub history: Option<(Vec<Step>, Vec<Step>)>,
/// A size sent, in 1/100 mm, until read back.
pub size_asked: Option<(i64, i64)>,
/// A size sent (1/100 mm) and its input, until read.
pub size_asked: Option<((i64, i64), u64)>,
/// A transition sent for a slide, until read back.
pub transition_asked: Option<(String, ely_lok::show::Transition, u64)>,
/// Pictures by slide name; stale ones show until repainted.
@@ -60,6 +60,22 @@ impl Extra {
/// The size to show, in 1/100 mm: asked, else read.
pub fn shown_size(&self) -> (i64, i64) {
self.size_asked
.unwrap_or_else(|| crate::design::mm100(self.size))
.map_or_else(|| crate::design::mm100(self.size), |(size, _)| size)
}
/// The size input that landed before this read began.
pub fn size_landed(&self, view: &ely_lok::LokView) -> Option<u64> {
let (_, seq) = self.size_asked?;
view.reached(seq).then_some(seq)
}
/// Forgets the asked size once read back, taken or refused.
pub fn settle_size(&mut self, landed: Option<u64>) {
let read = crate::design::mm100(self.size);
if self.size_asked.is_some_and(|((w, h), seq)| {
landed == Some(seq) || (w - read.0).abs() <= 50 && (h - read.1).abs() <= 50
}) {
self.size_asked = None;
}
}
}
+44
View File
@@ -417,3 +417,47 @@ fn a_check_row_does_not_jump_among_masters() {
});
assert!(cx.update(|app| deck.read(app).dialog.is_some()), "the check stays open");
}
#[test]
fn a_refused_size_does_not_stay_shown() {
let dir = tempfile::tempdir().expect("a temp dir");
let mut cx = TestAppContext::single();
let Some(deck) = blank(&mut cx, dir.path()) else {
eprintln!("SKIP: no LOK build");
return;
};
let before = cx.update(|app| deck.read(app).active_tab().expect("a tab").extra.size);
update(&mut cx, &deck, |deck, cx| deck.resize((-500, -500), cx));
settle(&cx, |app| {
deck.read(app).active_tab().is_some_and(|tab| tab.extra.size_asked.is_none())
});
let extra = cx.update(|app| {
let tab = deck.read(app).active_tab().expect("a tab");
(tab.extra.size, tab.extra.shown_size())
});
assert_eq!(extra.0, before, "the kernel kept its size");
assert_eq!(extra.1, crate::design::mm100(before), "the fields show it");
}
#[test]
fn a_size_the_kernel_does_not_take_clears_after_its_read() {
let dir = tempfile::tempdir().expect("a temp dir");
let mut cx = TestAppContext::single();
let Some(deck) = blank(&mut cx, dir.path()) else {
eprintln!("SKIP: no LOK build");
return;
};
update(&mut cx, &deck, |deck, cx| {
deck.resize((30_000, 19_050), cx);
// As if the kernel refused: it keeps another size.
let id = deck.core.active.expect("a tab");
let tab = deck.tab_mut(id).expect("a tab");
let (_, seq) = tab.extra.size_asked.expect("asked");
tab.extra.size_asked = Some(((40_000, 19_050), seq));
});
settle(&cx, |app| {
deck.read(app).active_tab().is_some_and(|tab| tab.extra.size_asked.is_none())
});
let read = cx.update(|app| crate::design::mm100(deck.read(app).active_tab().expect("a tab").extra.size));
assert!((read.0 - 30_000).abs() <= 50, "the kernel's own size shows: {read:?}");
}
+1 -1
View File
@@ -31,7 +31,7 @@
- [x] S-06 导出或打印的“从–到”填 0 时导出全部幻灯片 — 键入的页码夹到 1..=末页;R1 PASS
- [x] S-07 母版视图下演示检查的行按幻灯片序号跳转 — 母版视图下点行提示先关母版,不跳;R1 PASS
- [x] S-08 刚编辑过幻灯片就进备注栏键入,备注可能丢 — 发出的备注待读回确认,键入中读回只移基线不动草稿;R2 PASS
- [ ] S-09 改尺寸失败后 `size_asked` 一直留着
- [x] S-09 改尺寸失败后 `size_asked` 一直留着 — 所要尺寸带输入序号,发送前先记、未入队即清,命令落地后的读回即清;R2 PASS
- [ ] S-10 开始放映的两处拒绝无提示(规则 2)
- [x] P-01 文件系统的 `PermissionDenied` 被拼成不存在的文案键,应用崩溃 — worker 的拒绝改为自有错误类型 Refused;R1 测试不跨平台、不看提示;组件库 f834f55 加 Toaster::shown;R2 PASS
- [x] P-02 每次编辑落地清掉全部图块与缩略图,页面空白、刚画的墨迹消失 — 图块随 R2.6;缩略图在编辑后留到重画;R1、R2 测试未证实际绘制;R3 PASS
+3
View File
@@ -0,0 +1,3 @@
FAIL
apps/ely-show/src/tests/slides.rs:430:回归覆盖遗漏了已排队尺寸命令失败后的清理。`(-500, -500)` 在参数校验阶段即被拒绝,只验证 `design.rs` 的立即清理。具体复现:在隔离副本中移除 `extra.rs:76` 的 `landed == Some(seq) ||`,现有四项尺寸测试仍全部通过;通过临时 IPC 代理对已排队的合法尺寸 `(30000, 19050)` 返回 ERR,原实现通过,变异实现因 `size_asked` 持续存在而超时,重现 S-09。修复方向:补充已排队命令被拒绝的回归测试,断言命令后的回读清除待定尺寸、保留内核尺寸,并让上述变异触发测试失败。证据:`/tmp/S-09-r1-size-tests.log`、`/tmp/S-09-r1-mutated-size-tests.log`、`/tmp/S-09-r1-queued-baseline.log`、`/tmp/S-09-r1-queued-mutated.log`。
+1
View File
@@ -0,0 +1 @@
PASS