Files
gpui-native-kit/crates/core/tests/command_palette_bench.rs
T
2026-11-10 15:06:16 +07:00

108 lines
3.8 KiB
Rust

use std::cell::RefCell;
use std::rc::Rc;
use gpui::{
AppContext as _, Context, Entity, IntoElement, ParentElement as _, Render, SharedString,
Styled as _, TestAppContext, Window, div,
};
use gpui_native_core::command_palette::{Command, CommandPalette, CommandPaletteState};
use gpui_native_core::init;
fn command(label: &'static str) -> Command {
Command::new(SharedString::from(label), SharedString::from(label))
}
struct Host {
palette: Entity<CommandPaletteState>,
renders: Rc<RefCell<usize>>,
}
impl Render for Host {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
*self.renders.borrow_mut() += 1;
div().size_full().child(self.palette.clone())
}
}
#[test]
fn typing_with_the_palette_open_is_not_pathologically_slow() {
let cx = TestAppContext::single();
cx.update(init);
let (state, renders, window) = cx.update(|cx| {
let renders = Rc::new(RefCell::new(0));
let state_cell: Rc<RefCell<Option<Entity<CommandPaletteState>>>> =
Rc::new(RefCell::new(None));
let renders_for_host = renders.clone();
let cell = state_cell.clone();
let window = cx
.open_window(gpui::WindowOptions::default(), |window, cx| {
let matcher = |query: &str, commands: &[Command]| {
let query = query.to_lowercase();
commands
.iter()
.filter(|command| command.label.to_lowercase().contains(&query))
.cloned()
.collect()
};
let state = cx.new(|cx| {
CommandPaletteState::new(
CommandPalette::new(
"bench-palette",
vec![
command("Open File"),
command("Close Tab"),
command("Save All"),
command("Toggle Theme"),
],
matcher,
),
window,
cx,
)
});
let state_for_host = state.clone();
cell.borrow_mut().replace(state.clone());
cx.new(|_| Host {
palette: state_for_host,
renders: renders_for_host,
})
})
.unwrap();
let state = state_cell.borrow().clone().expect("state captured");
(state, renders, window)
});
let mut visual = gpui::VisualTestContext::from_window(window.into(), &cx);
visual.update(|window, cx| {
state.update(cx, |state, cx| state.open(window, cx));
window.draw(cx).clear(cx);
});
// The open palette must sit idle on executor timers, never frame requests.
let frames = visual.update(|window, cx| window.simulate_next_frame(cx));
assert_eq!(
frames, 0,
"an idle open palette must not request animation frames"
);
for letter in "abcdefghijklmnopqrstuvwxyz".chars() {
visual.simulate_keystrokes(&letter.to_string());
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
}
let total_renders = *renders.borrow();
println!(
"26 real keystrokes with the palette open: {total_renders} host renders ({:.2} per keystroke)",
total_renders as f32 / 26.
);
assert!(
total_renders >= 26,
"every keystroke must redraw the page; got {total_renders} renders"
);
assert!(
total_renders <= 26 * 3,
"typing caused {total_renders} host renders; healthy filtering stays under 3 per keystroke"
);
}