tests.rs raw

use guiduck_scene::geom::Size;

use super::*;
use crate::clipboard::NoClipboard;
use crate::event::{Modifiers, PointerButton};

fn text() -> TextContext {
    TextContext::hermetic([])
}

fn laid_out(width: f64) -> Slider {
    let mut slider = Slider::new();
    slider.finalize_layout(&mut text(), Size::new(width, 20.0), Size::ZERO);
    slider
}

fn press(slider: &mut Slider, x: f64) {
    slider.on_pointer(
        EventKind::PointerDown,
        &PointerEvent {
            window: Point::new(x, 10.0),
            local: Point::new(x, 10.0),
            button: Some(PointerButton::Left),
            click_count: 1,
        },
        &mut text(),
        &mut NoClipboard,
    );
}

fn arrow(slider: &mut Slider, key: Key) -> bool {
    slider.on_key(
        &KeyInput {
            key,
            modifiers: Modifiers::default(),
            pressed: true,
        },
        &mut text(),
        &mut NoClipboard,
    )
}

#[test]
fn a_programmatic_set_is_silent() {
    let mut slider = Slider::new();
    slider.set_value(0.5);
    assert_eq!(slider.get_value(), 0.5);
    assert!(
        slider.take_emitted().is_empty(),
        "the controlled contract: a binding writing the value must not report it"
    );
}

#[test]
fn dragging_reports_the_new_value() {
    let mut slider = laid_out(100.0);
    press(&mut slider, 50.0);
    assert!(
        (slider.get_value() - 0.5).abs() < 0.05,
        "{}",
        slider.get_value()
    );
    assert!(matches!(
        slider.take_emitted().as_slice(),
        [EventData::ValueChanged(_)]
    ));
}

/// The thumb has width, so the travel is shorter than the track. Without
/// accounting for it the value could never reach either end.
#[test]
fn the_ends_are_reachable() {
    let mut slider = laid_out(100.0);
    press(&mut slider, 0.0);
    assert_eq!(slider.get_value(), 0.0);
    press(&mut slider, 100.0);
    assert_eq!(slider.get_value(), 1.0);
}

#[test]
fn arrows_step_and_stop_at_the_ends() {
    let mut slider = laid_out(100.0);
    slider.set_value(0.5);
    let _ = slider.take_emitted();

    assert!(arrow(&mut slider, Key::Right), "a move consumes the key");
    assert!((slider.get_value() - 0.55).abs() < 1e-9);
    assert!(matches!(
        slider.take_emitted().as_slice(),
        [EventData::ValueChanged(_)]
    ));

    assert!(arrow(&mut slider, Key::End));
    assert_eq!(slider.get_value(), 1.0);
    let _ = slider.take_emitted();

    // At the end there is nowhere to go, so the key is *not* consumed and can
    // still reach Tab or a shortcut.
    assert!(
        !arrow(&mut slider, Key::Right),
        "a key that moves nothing is not consumed"
    );
    assert!(slider.take_emitted().is_empty());
}

#[test]
fn a_slider_announces_a_percentage() {
    let mut slider = Slider::new();
    slider.set_value(0.25);
    let mut node = accesskit::Node::new(accesskit::Role::Slider);
    slider.accessibility(&mut node);
    assert_eq!(node.numeric_value(), Some(25.0));
    assert_eq!(slider.role(), accesskit::Role::Slider);
}