use bevy_ecs::hierarchy::ChildOf;
use bevy_ecs::prelude::*;
use wintf::ecs::pointer::{PointerState, build_bubble_path};
use wintf::ecs::window::{Window, find_owner_window};
#[test]
fn test_find_owner_window_basic() {
let mut world = World::new();
let window_a = world
.spawn(Window {
title: "Window A".to_string(),
..Default::default()
})
.id();
let container_a = world.spawn(ChildOf(window_a)).id();
let widget_a = world.spawn(ChildOf(container_a)).id();
let window_b = world
.spawn(Window {
title: "Window B".to_string(),
..Default::default()
})
.id();
let widget_b = world.spawn(ChildOf(window_b)).id();
assert_eq!(
find_owner_window(&world, widget_a),
Some(window_a),
"widget_a は Window A に属する"
);
assert_eq!(
find_owner_window(&world, container_a),
Some(window_a),
"container_a は Window A に属する"
);
assert_eq!(
find_owner_window(&world, widget_b),
Some(window_b),
"widget_b は Window B に属する"
);
assert_eq!(
find_owner_window(&world, window_a),
Some(window_a),
"Window A 自身は自身を返す"
);
assert_eq!(
find_owner_window(&world, window_b),
Some(window_b),
"Window B 自身は自身を返す"
);
}
#[test]
fn test_find_owner_window_no_window() {
let mut world = World::new();
let layout_root = world.spawn_empty().id();
let orphan = world.spawn(ChildOf(layout_root)).id();
assert_eq!(
find_owner_window(&world, layout_root),
None,
"Window を持たないエンティティは None"
);
assert_eq!(
find_owner_window(&world, orphan),
None,
"Window でないルートの子エンティティは None"
);
}
#[test]
fn test_find_owner_window_isolated_entity() {
let mut world = World::new();
let isolated = world.spawn_empty().id();
assert_eq!(
find_owner_window(&world, isolated),
None,
"孤立エンティティは None"
);
}
#[test]
fn test_build_bubble_path_stops_at_window() {
let mut world = World::new();
let layout_root = world.spawn_empty().id();
let window = world
.spawn((
Window {
title: "Test Window".to_string(),
..Default::default()
},
ChildOf(layout_root),
))
.id();
let container = world.spawn(ChildOf(window)).id();
let widget = world.spawn(ChildOf(container)).id();
let path = build_bubble_path(&world, widget);
assert_eq!(path.len(), 3, "パスの長さは 3(widget, container, window)");
assert_eq!(path[0], widget, "パスの先頭は widget");
assert_eq!(path[1], container, "パスの2番目は container");
assert_eq!(path[2], window, "パスの最後は window");
assert!(
!path.contains(&layout_root),
"LayoutRoot はパスに含まれない"
);
}
#[test]
fn test_build_bubble_path_from_window() {
let mut world = World::new();
let layout_root = world.spawn_empty().id();
let window = world
.spawn((
Window {
title: "Test Window".to_string(),
..Default::default()
},
ChildOf(layout_root),
))
.id();
let path = build_bubble_path(&world, window);
assert_eq!(path.len(), 1, "Window 自身からのパスは長さ 1");
assert_eq!(path[0], window, "パスは [window] のみ");
}
#[test]
fn test_build_bubble_path_no_window() {
let mut world = World::new();
let root = world.spawn_empty().id();
let child = world.spawn(ChildOf(root)).id();
let path = build_bubble_path(&world, child);
assert_eq!(path.len(), 2, "Window なしの場合は全パス");
assert_eq!(path[0], child);
assert_eq!(path[1], root);
}
#[test]
fn test_mouseleave_scoped_pointer_clear() {
let mut world = World::new();
let window_a = world
.spawn(Window {
title: "Window A".to_string(),
..Default::default()
})
.id();
let widget_a = world
.spawn((ChildOf(window_a), PointerState::default()))
.id();
let window_b = world
.spawn(Window {
title: "Window B".to_string(),
..Default::default()
})
.id();
let widget_b = world
.spawn((ChildOf(window_b), PointerState::default()))
.id();
let mut entities_to_clear = Vec::new();
{
let mut query = world.query::<(Entity, &PointerState)>();
for (e, _) in query.iter(&world) {
if find_owner_window(&world, e) == Some(window_a) {
entities_to_clear.push(e);
}
}
}
for entity in entities_to_clear {
if let Ok(mut entity_ref) = world.get_entity_mut(entity) {
entity_ref.remove::<PointerState>();
}
}
assert!(
world.get::<PointerState>(widget_a).is_none(),
"Window A のウィジェットの PointerState は削除された"
);
assert!(
world.get::<PointerState>(widget_b).is_some(),
"Window B のウィジェットの PointerState は維持される"
);
}
#[test]
fn test_drag_hwnd_guard_owner_window_check() {
let mut world = World::new();
let window_a = world
.spawn(Window {
title: "Window A".to_string(),
..Default::default()
})
.id();
let drag_target = world.spawn(ChildOf(window_a)).id();
let window_b = world
.spawn(Window {
title: "Window B".to_string(),
..Default::default()
})
.id();
let drag_entity_owner = find_owner_window(&world, drag_target);
assert_eq!(
drag_entity_owner,
Some(window_a),
"ドラッグ対象は Window A に属する"
);
let should_end_from_b = drag_entity_owner == Some(window_b);
assert!(
!should_end_from_b,
"Window B からのボタンアップではドラッグ終了しない"
);
let should_end_from_a = drag_entity_owner == Some(window_a);
assert!(
should_end_from_a,
"Window A からのボタンアップではドラッグ終了する"
);
}