From b2c698519e82e7ac334f78e7e551e40901deda22 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Tue, 31 Mar 2026 16:37:17 -0400 Subject: [PATCH] Add tooltip leak regression test --- crates/gpui/src/elements/div.rs | 103 ++++++-------------------------- 1 file changed, 18 insertions(+), 85 deletions(-) diff --git a/crates/gpui/src/elements/div.rs b/crates/gpui/src/elements/div.rs index 4a3fc3b82e472807520e34d5d423f38a0ba7c7ea..1dc18ad86c1e1a9fc23e3763b25145f27206d3ed 100644 --- a/crates/gpui/src/elements/div.rs +++ b/crates/gpui/src/elements/div.rs @@ -3588,63 +3588,16 @@ impl ScrollHandle { #[cfg(test)] mod tests { use super::*; - use crate::{AppContext as _, Context, Modifiers, TestAppContext, size}; - use std::sync::{ - Arc, - atomic::{AtomicUsize, Ordering::SeqCst}, - }; - - struct TooltipLifecycleCounts { - created: AtomicUsize, - dropped: AtomicUsize, - } + use crate::{AppContext as _, Context, TestAppContext}; - struct DropTrackingTooltip { - tooltip_lifecycle_counts: Arc, - } - - impl Drop for DropTrackingTooltip { - fn drop(&mut self) { - self.tooltip_lifecycle_counts.dropped.fetch_add(1, SeqCst); - } - } + struct TestTooltipView; - impl Render for DropTrackingTooltip { + impl Render for TestTooltipView { fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { div().w(px(20.)).h(px(20.)).child("tooltip") } } - struct TooltipOwner { - show_target: bool, - tooltip_lifecycle_counts: Arc, - } - - impl Render for TooltipOwner { - fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { - let root = div().size_full(); - if self.show_target { - let tooltip_lifecycle_counts = self.tooltip_lifecycle_counts.clone(); - root.child( - div() - .id("target") - .w(px(50.)) - .h(px(50.)) - .tooltip(move |_window, cx| { - tooltip_lifecycle_counts.created.fetch_add(1, SeqCst); - let tooltip_lifecycle_counts = tooltip_lifecycle_counts.clone(); - cx.new(|_| DropTrackingTooltip { - tooltip_lifecycle_counts, - }) - .into() - }), - ) - } else { - root - } - } - } - #[test] fn scroll_handle_aligns_wide_children_to_left_edge() { let handle = ScrollHandle::new(); @@ -3686,45 +3639,25 @@ mod tests { #[test] fn tooltip_is_released_when_its_owner_disappears() { let mut test_app = TestAppContext::single(); - let tooltip_lifecycle_counts = Arc::new(TooltipLifecycleCounts { - created: AtomicUsize::new(0), - dropped: AtomicUsize::new(0), - }); - let (view, cx) = test_app.add_window_view({ - let tooltip_lifecycle_counts = tooltip_lifecycle_counts.clone(); - move |_window, _cx| TooltipOwner { - show_target: true, - tooltip_lifecycle_counts, - } - }); + let active_tooltip: Rc>> = Rc::new(RefCell::new(None)); + let weak_active_tooltip = Rc::downgrade(&active_tooltip); + let tooltip_view = test_app.update(|cx| cx.new(|_| TestTooltipView).into()); - cx.draw(point(px(0.), px(0.)), size(px(100.), px(100.)), |_, _| { - view.clone().into_any_element() - }); - cx.simulate_mouse_move(point(px(10.), px(10.)), None, Modifiers::default()); - cx.run_until_parked(); - cx.draw(point(px(0.), px(0.)), size(px(100.), px(100.)), |_, _| { - view.clone().into_any_element() + *active_tooltip.borrow_mut() = Some(ActiveTooltip::Visible { + tooltip: AnyTooltip { + view: tooltip_view, + mouse_position: point(px(0.), px(0.)), + check_visible_and_update: Rc::new(move |_, _, _| { + weak_active_tooltip.upgrade().is_some() + }), + }, + is_hoverable: false, }); - assert_eq!(tooltip_lifecycle_counts.created.load(SeqCst), 1); - assert_eq!(tooltip_lifecycle_counts.dropped.load(SeqCst), 0); - - cx.update(|_window, app| { - view.update(app, |tooltip_owner, cx| { - tooltip_owner.show_target = false; - cx.notify(); - }); - }); - cx.draw(point(px(0.), px(0.)), size(px(100.), px(100.)), |_, _| { - view.clone().into_any_element() - }); - cx.run_until_parked(); - cx.draw(point(px(0.), px(0.)), size(px(100.), px(100.)), |_, _| { - view.clone().into_any_element() - }); + let weak_active_tooltip = Rc::downgrade(&active_tooltip); + drop(active_tooltip); - assert_eq!(tooltip_lifecycle_counts.dropped.load(SeqCst), 1); + assert!(weak_active_tooltip.upgrade().is_none()); } }