use super::*;
fn tokens(d: TargetDensity) -> InputTokens {
InputTokens::for_density(d)
}
#[test]
fn a_mouse_has_no_slop_at_any_density() {
for d in [
TargetDensity::Compact,
TargetDensity::Comfortable,
TargetDensity::Touch,
] {
let s = HitSlop::for_pointer(PointerKind::Mouse, &tokens(d));
assert!(s.is_none(), "{d:?}: mouse slop was {s:?}");
assert_eq!(s.outset_for(Size::new(4.0, 4.0)), 0.0);
}
}
#[test]
fn the_budget_caps_a_coarse_pointer_only() {
let mut t = tokens(TargetDensity::Compact);
t.slop_budget = 3.0;
assert_eq!(HitSlop::for_pointer(PointerKind::Touch, &t).radius, 3.0);
assert_eq!(
HitSlop::for_pointer(PointerKind::Pen(teksilo_tokens::PenKind::Pen), &t).radius,
2.0
);
}
#[test]
fn compact_still_affords_a_budget() {
assert_eq!(tokens(TargetDensity::Compact).slop_budget, 12.0);
let s = HitSlop::for_pointer(PointerKind::Touch, &tokens(TargetDensity::Compact));
assert_eq!(s.radius, 8.0, "touch profile 8 dp, under the 12 dp budget");
}
#[test]
fn a_large_node_earns_no_outset() {
let s = HitSlop {
radius: 8.0,
up_to: 44.0,
};
assert_eq!(s.outset_for(Size::new(1000.0, 800.0)), 0.0);
assert_eq!(s.outset_for(Size::new(44.0, 44.0)), 0.0);
assert_eq!(s.outset_for(Size::new(1000.0, 44.0)), 0.0);
assert_eq!(s.outset_for(Size::new(1000.0, 2.0)), 8.0);
}
#[test]
fn the_outset_is_half_the_shortfall_clamped() {
let s = HitSlop {
radius: 8.0,
up_to: 24.0,
};
assert_eq!(s.outset_for(Size::new(16.0, 16.0)), 4.0);
assert_eq!(s.outset_for(Size::new(20.0, 20.0)), 2.0);
assert_eq!(s.outset_for(Size::new(0.0, 0.0)), 8.0);
}
#[test]
fn degenerate_sizes_and_radii_are_inert() {
let s = HitSlop {
radius: f32::NAN,
up_to: 24.0,
};
assert_eq!(s.outset_for(Size::new(4.0, 4.0)), 0.0);
let s = HitSlop {
radius: 8.0,
up_to: 24.0,
};
assert_eq!(s.outset_for(Size::new(f32::NAN, f32::NAN)), 8.0);
assert_eq!(s.outset_for(Size::new(-5.0, -5.0)), 8.0);
}
#[test]
fn rect_distance_is_zero_inside_and_euclidean_outside() {
let r = Rect::new(10.0, 10.0, 20.0, 20.0);
assert_eq!(rect_distance(r, Point::new(15.0, 15.0)), 0.0);
assert_eq!(rect_distance(r, Point::new(34.0, 20.0)), 4.0);
assert_eq!(rect_distance(r, Point::new(20.0, 6.0)), 4.0);
assert!((rect_distance(r, Point::new(33.0, 34.0)) - 5.0).abs() < 1e-4);
}
#[test]
fn circle_distance_follows_the_silhouette() {
let c = Point::new(0.0, 0.0);
assert_eq!(circle_distance(c, 10.0, Point::new(3.0, 4.0)), 0.0);
assert!((circle_distance(c, 10.0, Point::new(13.0, 0.0)) - 3.0).abs() < 1e-4);
let corner = circle_distance(c, 10.0, Point::new(10.0, 10.0));
assert!((corner - (200.0_f32.sqrt() - 10.0)).abs() < 1e-3);
}
#[test]
fn min_singular_value_of_the_usual_transforms() {
assert!((min_singular_value(&Transform2D::IDENTITY) - 1.0).abs() < 1e-5);
assert!((min_singular_value(&Transform2D::translate(50.0, -9.0)) - 1.0).abs() < 1e-5);
assert!((min_singular_value(&Transform2D::rotate(0.7)) - 1.0).abs() < 1e-5);
assert!((min_singular_value(&Transform2D::scale(2.0, 2.0)) - 2.0).abs() < 1e-5);
assert!((min_singular_value(&Transform2D::scale(3.0, 0.5)) - 0.5).abs() < 1e-5);
let t = Transform2D::scale(4.0, 0.25).then(&Transform2D::rotate(1.1));
assert!((min_singular_value(&t) - 0.25).abs() < 1e-4);
assert_eq!(min_singular_value(&Transform2D::scale(1.0, 0.0)), 0.0);
}
#[test]
fn the_mouse_context_disables_the_slop_pass() {
let ctx = HitContext::mouse();
assert_eq!(ctx.kind(), PointerKind::Mouse);
assert_eq!(ctx.tokens().density, TargetDensity::Compact);
assert!(!ctx.slop_enabled());
assert_eq!(ctx.layout_direction(), LayoutDirection::LeftToRight);
}
#[test]
fn a_touch_context_enables_the_pass_and_carries_its_probe() {
let t = tokens(TargetDensity::Touch);
let seven: WidgetId = slotmap::KeyData::from_ffi(7).into();
let eight: WidgetId = slotmap::KeyData::from_ffi(8).into();
let probe = |id: WidgetId| id == seven;
let ctx = HitContext::new(PointerKind::Touch, &t)
.direction(LayoutDirection::RightToLeft)
.read_only_probe(&probe);
assert!(ctx.slop_enabled());
assert_eq!(ctx.layout_direction(), LayoutDirection::RightToLeft);
assert!(ctx.is_read_only(seven));
assert!(!ctx.is_read_only(eight));
}