use super::*;
use crate::components::InputKey;
use crate::editor::palette::{Category, PaletteAction};
fn hook(entries: Vec<serde_json::Value>) -> EditorHook {
EditorHook::new("unused.jsonl".to_string(), entries)
}
fn palette_world() -> World {
let mut world = World::new();
for id in palette_panel::all_field_ids() {
world.add_component(crate::components::TextInput {
asset_id: id,
..Default::default()
});
}
world
}
fn chord(key: InputKey, ctrl: bool, cmd: bool) -> FrameInput {
FrameInput {
captured_key: Some(key),
ctrl,
cmd,
..Default::default()
}
}
#[test]
fn either_platform_modifier_opens_the_palette() {
for (ctrl, cmd) in [(true, false), (false, true)] {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, ctrl, cmd), &mut world);
assert!(h.palette_open, "ctrl={ctrl} cmd={cmd} did not open it");
h.drive_palette_toggle(&chord(InputKey::K, ctrl, cmd), &mut world);
assert!(!h.palette_open);
}
}
#[test]
fn an_unmodified_k_leaves_the_palette_closed() {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, false, false), &mut world);
assert!(!h.palette_open);
}
#[test]
fn opening_blurs_the_query_for_one_frame() {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
assert!(h.palette_blur);
assert!(!h.make_palette_view([0.0, 0.0]).focus, "blurred this frame");
}
#[test]
fn typing_reranks_and_rehomes_the_highlight() {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
let opened = h.palette_matches.len();
assert!(opened > 0, "the launch list is not empty");
h.palette_pick = 3;
widget::seed_field(&mut world, palette_panel::INPUT, "cook");
h.sample_palette_query(&world);
assert_eq!(
h.palette_pick, 0,
"a narrowed list starts at its best answer"
);
assert!(h.palette_matches.len() < opened);
let first = &h.palette_items[h.palette_matches[0]];
assert_eq!(first.label, "/cook");
}
#[test]
fn the_arrows_walk_the_matches_and_stop_at_the_ends() {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
h.palette_keys(&mut world, &chord(InputKey::Down, false, false));
assert_eq!(h.palette_pick, 1);
h.palette_keys(&mut world, &chord(InputKey::Up, false, false));
assert_eq!(h.palette_pick, 0);
h.palette_keys(&mut world, &chord(InputKey::Up, false, false));
assert_eq!(h.palette_pick, 0, "stops at the top");
}
#[test]
fn committing_a_panel_row_opens_it() {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
let at = h
.palette_matches
.iter()
.position(|&i| h.palette_items[i].action == PaletteAction::OpenPanel(PanelKey::Variables))
.expect("the Variables panel is a palette row");
h.palette_pick = at;
h.palette_keys(&mut world, &chord(InputKey::Enter, false, false));
assert!(!h.palette_open, "committing closes the palette");
assert!(h.variables_open, "the panel opened");
assert_eq!(
h.panel_order.last().copied(),
Some(PanelKey::Variables),
"and it is frontmost"
);
}
#[test]
fn committing_an_argument_command_seeds_command_mode() {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
let at = h
.palette_matches
.iter()
.position(|&i| h.palette_items[i].label == "/add")
.expect("/add is a palette row");
h.palette_pick = at;
h.palette_keys(&mut world, &chord(InputKey::Enter, false, false));
assert!(h.palette_open, "the palette stays up for the arguments");
assert_eq!(widget::field_text(&world, palette_panel::INPUT), "/add ");
}
#[test]
fn a_commit_is_remembered_for_the_next_launch_list() {
let mut h = hook(Vec::new());
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
let at = h
.palette_matches
.iter()
.position(|&i| h.palette_items[i].action == PaletteAction::OpenPanel(PanelKey::Variables))
.expect("the Variables panel is a palette row");
let label = h.palette_items[h.palette_matches[at]].label.clone();
h.palette_pick = at;
h.palette_keys(&mut world, &chord(InputKey::Enter, false, false));
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
let first = &h.palette_items[h.palette_matches[0]];
assert_eq!(first.label, label, "the last commit leads the list");
}
#[test]
fn a_press_outside_dismisses_without_reaching_the_world() {
let mut h = hook(Vec::new());
let mut world = palette_world();
let vp = [1280.0, 720.0];
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
let o = h.origin(PanelKey::Palette, vp);
let inside = FrameInput {
mouse_x: o[0] + 20.0,
mouse_y: o[1] + 10.0,
..Default::default()
};
assert!(
!h.route_palette_dismiss(&inside, vp),
"a press on the palette is left to its own hit test"
);
assert!(h.palette_open);
let outside = FrameInput {
mouse_x: o[0] - 40.0,
mouse_y: o[1] + 10.0,
..Default::default()
};
assert!(
h.route_palette_dismiss(&outside, vp),
"the press is claimed"
);
assert!(!h.palette_open);
}
#[test]
fn world_assets_become_rows_routed_by_type() {
let entries = vec![
serde_json::json!({"name": "greeter", "type": "Behavior", "args": {"on": "tick", "do": []}}),
];
let mut h = hook(entries);
let mut world = palette_world();
h.drive_palette_toggle(&chord(InputKey::K, true, false), &mut world);
let row = h
.palette_items
.iter()
.find(|it| it.label == "greeter")
.expect("the authored behavior is a palette row");
assert_eq!(row.category, Category::Asset);
assert_eq!(row.action, PaletteAction::OpenAsset("greeter".to_string()));
}