mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-31 07:38:24 +00:00
Reject legacy workspace stacks beyond the layout depth limit
This commit is contained in:
2 files changed
+43
-2
No files matched your search
@@ -25,6 +25,9 @@ use super::{Snapshot, VERSION};
|
||||
use crate::dock::{Layout, PanelKind, Workspace};
|
||||
use crate::state::UiState;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
enum OldSplitSize {
|
||||
Ratio(f32),
|
||||
@@ -166,7 +169,7 @@ fn node(old: OldNode, depth: usize) -> Result<Node<PanelKind>, String> {
|
||||
first: Box::new(node(*a, depth.saturating_add(1))?),
|
||||
second: Box::new(node(*b, depth.saturating_add(1))?),
|
||||
},
|
||||
OldNode::Stack { entries } => column(entries)?,
|
||||
OldNode::Stack { entries } => column(entries, depth)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -183,7 +186,7 @@ struct Frame {
|
||||
}
|
||||
|
||||
/// A column of stacked frames as tab groups split top to bottom (see the module docs).
|
||||
fn column(entries: Vec<OldStackEntry>) -> Result<Node<PanelKind>, String> {
|
||||
fn column(entries: Vec<OldStackEntry>, depth: usize) -> Result<Node<PanelKind>, String> {
|
||||
let mut frames: Vec<Frame> = Vec::new();
|
||||
// Tabs of closed frames above the first open one.
|
||||
let mut waiting: Vec<PanelKind> = Vec::new();
|
||||
@@ -199,6 +202,9 @@ fn column(entries: Vec<OldStackEntry>) -> Result<Node<PanelKind>, String> {
|
||||
}
|
||||
let active = entry.active.min(panels.len().saturating_sub(1));
|
||||
if entry.open {
|
||||
if depth.saturating_add(frames.len()) > craft_ui::docking::MAX_DEPTH {
|
||||
return Err("workspace dock tree exceeds supported limits".into());
|
||||
}
|
||||
let height = entry.height.filter(|h| h.is_finite() && *h > 0.0).map(|h| h.min(MAX_FRAME));
|
||||
frames.push(Frame { panels, active, height });
|
||||
} else if let Some(above) = frames.last_mut() {
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use super::*;
|
||||
|
||||
fn stack(count: usize) -> OldNode {
|
||||
OldNode::Stack {
|
||||
entries: (0..count).map(|_| OldStackEntry { panel: Some(PanelKind::Info), panels: Vec::new(), active: 0, open: true, height: None }).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stacked_frames_respect_the_remaining_tree_depth() {
|
||||
let limit = craft_ui::docking::MAX_DEPTH;
|
||||
assert!(node(stack(limit + 1), 0).is_ok());
|
||||
assert!(node(stack(limit + 2), 0).is_err());
|
||||
assert!(node(stack(1), limit).is_ok());
|
||||
assert!(node(stack(2), limit).is_err());
|
||||
assert!(node(stack(limit), 2).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oversized_legacy_stack_load_does_not_abort() {
|
||||
const CHILD: &str = "EFFECTCRAFT_TEST_LEGACY_STACK_CHILD";
|
||||
if std::env::var_os(CHILD).is_some() {
|
||||
let entry = serde_json::json!({"panel": "Info", "open": true});
|
||||
let value = serde_json::json!({"workspaces": {"Oversized": {"Stack": {"entries": vec![entry; 20_000]}}}});
|
||||
assert!(serde_json::to_vec(&value).unwrap().len() < super::super::MAX_BYTES);
|
||||
assert!(migrate(value, &UiState::default()).is_err());
|
||||
return;
|
||||
}
|
||||
let output = std::process::Command::new(std::env::current_exe().unwrap())
|
||||
.args(["--exact", "workspace_state::legacy::tests::oversized_legacy_stack_load_does_not_abort", "--nocapture"])
|
||||
.env(CHILD, "1")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(output.status.success(), "{}\n{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
|
||||
}
|
||||
Reference in new issue
Block a user