use super::*;
use crate::editor::inject;
use crate::editor::registry::Panel;
use crate::test_support::isolate_state_dir;
fn hook() -> EditorHook {
EditorHook::new("unused.jsonl".to_string(), Vec::new())
}
fn injected_world() -> World {
let mut world = World::new();
inject::editor_hud(&mut world);
world
}
fn open_every_panel(h: &mut EditorHook, world: &mut World) {
for p in registry::view_toggles() {
if !p.is_open(h) {
p.toggle(h, world);
}
}
h.selected_type = Some("Sprite".to_string());
h.view_open = true;
h.open_template = Some(0);
h.palette_open = true;
}
fn show_every_element(p: &dyn Panel, world: &mut World) {
for id in p.sprite_ids() {
widget::set_sprite_visible(world, id, true);
}
for id in p.label_ids() {
widget::set_label_visible(world, id, true);
}
for (id, _) in p.field_ids() {
widget::show_field(world, id, [0.0, 0.0, 10.0, 10.0], false);
}
}
fn visible_sprites(p: &dyn Panel, world: &World) -> Vec<AssetId> {
let ids = p.sprite_ids();
world
.query::<crate::components::Sprite>()
.filter(|s| s.visible && ids.contains(&s.asset_id))
.map(|s| s.asset_id)
.collect()
}
#[test]
fn hide_blanks_every_declared_element() {
let mut world = injected_world();
for key in PanelKey::ALL {
let p = registry::panel(key);
show_every_element(p, &mut world);
p.hide(&mut world);
for id in p.sprite_ids() {
let s = world
.query::<crate::components::Sprite>()
.find(|s| s.asset_id == id)
.unwrap_or_else(|| panic!("{key:?} declares sprite {id:?} but injection has none"));
assert!(!s.visible, "{key:?} left sprite {id:?} visible after hide");
}
for id in p.label_ids() {
let l = world
.query::<crate::components::TextLabel>()
.find(|l| l.asset_id == id)
.unwrap_or_else(|| panic!("{key:?} declares label {id:?} but injection has none"));
assert!(!l.visible, "{key:?} left label {id:?} visible after hide");
}
for (id, _) in p.field_ids() {
let t = world
.query::<crate::components::TextInput>()
.find(|t| t.asset_id == id)
.unwrap_or_else(|| panic!("{key:?} declares field {id:?} but injection has none"));
assert!(!t.visible, "{key:?} left field {id:?} visible after hide");
}
}
}
#[test]
fn default_size_fits_within_max_size() {
let h = hook();
for key in PanelKey::ALL {
let p = registry::panel(key);
let s = p.size(&h);
let max = p.max_size(&h);
assert!(
s[0] > 0.0 && s[1] > 0.0,
"{key:?} has a degenerate default size {s:?}"
);
assert!(
s[0] <= max[0] && s[1] <= max[1],
"{key:?} default size {s:?} exceeds its max {max:?}"
);
}
}
#[test]
fn effective_size_clamps_a_stored_override() {
for key in PanelKey::ALL {
let mut h = hook();
let d = h.default_size(key);
let max = registry::panel(key).max_size(&h);
h.sizes[key.index()] = Some([1.0, 1.0]);
assert_eq!(
h.effective_size(key),
d,
"{key:?} let an override shrink it below its default"
);
h.sizes[key.index()] = Some([1.0e6, 1.0e6]);
let grown = h.effective_size(key);
assert!(
grown[0] >= d[0] && grown[1] >= d[1],
"{key:?} grew below its default"
);
for axis in 0..2 {
if max[axis].is_finite() {
assert_eq!(
grown[axis],
max[axis].max(d[axis]),
"{key:?} grew past its max on axis {axis}"
);
}
}
}
}
#[test]
fn every_panel_origin_stays_on_screen() {
let h = hook();
for vp in [[1280.0, 720.0], [800.0, 600.0], [3840.0, 2160.0]] {
for key in PanelKey::ALL {
let o = h.origin(key, vp);
let s = h.effective_size(key);
assert!(o[0] >= 0.0, "{key:?} sits off the left edge at {vp:?}");
assert!(
o[1] >= hud::BAR_H,
"{key:?} sits under the top bar at {vp:?}"
);
if s[0] <= vp[0] {
assert!(
o[0] + s[0] <= vp[0],
"{key:?} overhangs the right edge at {vp:?}"
);
}
if s[1] <= vp[1] - hud::BAR_H {
assert!(
o[1] + s[1] <= vp[1],
"{key:?} overhangs the bottom edge at {vp:?}"
);
}
}
}
}
#[test]
fn every_view_toggle_opens_and_closes_its_panel() {
isolate_state_dir();
let mut world = injected_world();
let mut h = hook();
for p in registry::view_toggles() {
let key = p.key();
p.close(&mut h, &mut world);
assert!(!p.is_open(&h), "{key:?} did not close on its title-bar X");
p.toggle(&mut h, &mut world);
assert!(p.is_open(&h), "{key:?} did not open on its View row");
p.toggle(&mut h, &mut world);
assert!(!p.is_open(&h), "{key:?} did not close on its View row");
}
}
#[test]
fn close_shuts_every_open_panel() {
isolate_state_dir();
let mut world = injected_world();
let mut h = hook();
for key in PanelKey::ALL {
open_every_panel(&mut h, &mut world);
let p = registry::panel(key);
assert!(p.is_open(&h), "{key:?} did not open for the close sweep");
p.close(&mut h, &mut world);
assert!(!p.is_open(&h), "{key:?} stayed open after close");
}
}
#[test]
fn a_press_clear_of_the_footprint_falls_through() {
isolate_state_dir();
let mut world = injected_world();
let mut h = hook();
open_every_panel(&mut h, &mut world);
let vp = [1280.0, 720.0];
for key in PanelKey::ALL {
let p = registry::panel(key);
let o = h.origin(key, vp);
let s = h.effective_size(key);
let (mx, my) = (o[0] + s[0] + 40.0, o[1] + s[1] + 40.0);
assert!(
!p.press(&mut h, &mut world, mx, my, o),
"{key:?} claimed a press outside its footprint"
);
assert!(
!p.wheel_over(&h, &world, mx, my, o),
"{key:?} claimed a wheel outside its footprint"
);
}
}
#[test]
fn scrolling_past_either_end_stays_in_bounds() {
isolate_state_dir();
let mut world = injected_world();
let mut h = hook();
open_every_panel(&mut h, &mut world);
for key in PanelKey::ALL {
let p = registry::panel(key);
for _ in 0..32 {
p.scroll(&mut h, &mut world, 1.0);
}
for _ in 0..64 {
p.scroll(&mut h, &mut world, -1.0);
}
for _ in 0..64 {
p.scroll(&mut h, &mut world, 1.0);
}
}
}
#[test]
fn draw_shows_chrome_that_hide_takes_back() {
isolate_state_dir();
let mut world = injected_world();
let mut h = hook();
open_every_panel(&mut h, &mut world);
let vp = [1280.0, 720.0];
for key in PanelKey::ALL {
let p = registry::panel(key);
let o = h.origin(key, vp);
p.hide(&mut world);
p.draw(&h, &mut world, o, [o[0] + 4.0, o[1] + 4.0]);
assert!(
!visible_sprites(p, &world).is_empty(),
"{key:?} drew no chrome while open"
);
p.hide(&mut world);
assert!(
visible_sprites(p, &world).is_empty(),
"{key:?} left chrome behind after hide"
);
}
}
#[test]
fn overlay_ids_are_declared_elements() {
let mut h = hook();
h.field_dropdown = None;
for key in PanelKey::ALL {
let p = registry::panel(key);
let declared = p.sprite_ids();
let labels = p.label_ids();
for id in p.overlay_ids(&h) {
assert!(
declared.contains(&id) || labels.contains(&id),
"{key:?} overlay id {id:?} is not among its injected elements"
);
}
}
}