bread-theme: validate surfaces.*.anchor like its width/layer siblings
anchor was the one enum-shaped schema field taken via unwrap_or_default() with no manifest-time validation, while width and layer both bail! on an unrecognized value (as does bar.window.anchors). A typo'd anchor silently fell through to breadbar's own runtime eprintln + unanchored-window fallback instead of the load-time hard error every other typo'd key gets. Validate against the three shapes breadbar/src/surface.rs actually implements.
This commit is contained in:
parent
470d2aa7e9
commit
a313eb518c
3 changed files with 81 additions and 1 deletions
|
|
@ -414,6 +414,18 @@ fn resolve_surfaces(
|
|||
let mut out = BTreeMap::new();
|
||||
let Some(raw) = raw else { return Ok(out) };
|
||||
for (namespace, s) in raw {
|
||||
let anchor = match s.anchor.as_deref() {
|
||||
Some(a @ ("top_right" | "bottom_centre" | "fill")) => a.to_string(),
|
||||
Some(other) => bail!(
|
||||
"theme '{theme_id}': surfaces.{namespace}.anchor = \"{other}\" is not \
|
||||
top_right|bottom_centre|fill (the only shapes breadbar's satellite \
|
||||
windows implement — see breadbar/src/surface.rs)"
|
||||
),
|
||||
None => bail!(
|
||||
"theme '{theme_id}': surfaces.{namespace} has no anchor set \
|
||||
(expected one of top_right|bottom_centre|fill)"
|
||||
),
|
||||
};
|
||||
let offset = match &s.offset {
|
||||
None => vec![],
|
||||
Some(RawOffset::Single(v)) => vec![*v],
|
||||
|
|
@ -439,7 +451,7 @@ fn resolve_surfaces(
|
|||
out.insert(
|
||||
namespace.clone(),
|
||||
Surface {
|
||||
anchor: s.anchor.clone().unwrap_or_default(),
|
||||
anchor,
|
||||
offset,
|
||||
width,
|
||||
layer,
|
||||
|
|
|
|||
|
|
@ -1035,6 +1035,67 @@ mod tests {
|
|||
assert!(format!("{err:#}").contains("hexagon"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_surface_anchor_is_a_hard_error_not_a_silent_default() {
|
||||
// Before the fix, `surfaces.*.anchor` was the one enum-shaped
|
||||
// field in the whole schema that skipped manifest-time validation
|
||||
// entirely (`unwrap_or_default()`), unlike its siblings `width` and
|
||||
// `layer` which both `bail!`. A typo here must fail exactly like
|
||||
// any other typo'd enum value.
|
||||
let xdg = isolated_xdg();
|
||||
write_theme(
|
||||
&xdg,
|
||||
"badanchor",
|
||||
r#"
|
||||
id = "badanchor"
|
||||
[surfaces."breadbar-notif"]
|
||||
anchor = "top_lft"
|
||||
width = 320
|
||||
layer = "overlay"
|
||||
"#,
|
||||
);
|
||||
let err = load_named("badanchor").expect_err("unknown anchor must be a hard error");
|
||||
assert!(format!("{err:#}").contains("top_lft"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_surface_anchor_is_a_hard_error() {
|
||||
let xdg = isolated_xdg();
|
||||
write_theme(
|
||||
&xdg,
|
||||
"noanchor",
|
||||
r#"
|
||||
id = "noanchor"
|
||||
[surfaces."breadbar-notif"]
|
||||
width = 320
|
||||
layer = "overlay"
|
||||
"#,
|
||||
);
|
||||
let err = load_named("noanchor").expect_err("missing anchor must be a hard error");
|
||||
assert!(format!("{err:#}").contains("no anchor set"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_known_surface_anchor_shape_resolves() {
|
||||
for anchor in ["top_right", "bottom_centre", "fill"] {
|
||||
let xdg = isolated_xdg();
|
||||
write_theme(
|
||||
&xdg,
|
||||
"okanchor",
|
||||
&format!(
|
||||
r#"
|
||||
id = "okanchor"
|
||||
[surfaces."breadbar-notif"]
|
||||
anchor = "{anchor}"
|
||||
"#
|
||||
),
|
||||
);
|
||||
let theme = load_named("okanchor")
|
||||
.unwrap_or_else(|e| panic!("anchor {anchor} should resolve: {e:#}"));
|
||||
assert_eq!(theme.surfaces()["breadbar-notif"].anchor, anchor);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- fallback on broken theme -----------------------------------------
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -200,6 +200,13 @@ pub struct Launcher {
|
|||
/// one lookup.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Surface {
|
||||
/// One of `top_right`/`bottom_centre`/`fill` — validated in
|
||||
/// `manifest.rs::resolve_surfaces` against the shapes
|
||||
/// `breadbar/src/surface.rs::apply` actually implements, the same
|
||||
/// "typo'd key is a hard error" policy this field's siblings
|
||||
/// (`width`, `layer`) already got. Required, not defaulted: a surface
|
||||
/// entry with no anchor at all is as much a hard `theme.toml` error as
|
||||
/// an unrecognized one.
|
||||
pub anchor: String,
|
||||
pub offset: Vec<f64>,
|
||||
pub width: SurfaceWidth,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue