Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests to slider #692

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 174 additions & 6 deletions src/views/slider.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! A toggle button widget. An example can be found in widget-gallery/button in the floem examples.

use floem_reactive::{create_effect, SignalGet, SignalUpdate};
use floem_reactive::{create_updater, SignalGet, SignalUpdate};
use floem_winit::keyboard::{Key, NamedKey};
use peniko::kurbo::{Circle, Point, RoundedRect};
use peniko::{Brush, Color};
Expand Down Expand Up @@ -316,16 +316,21 @@ impl Slider {
/// ```
pub fn new<P: Into<Pct>>(percent: impl Fn() -> P + 'static) -> Self {
let id = ViewId::new();
create_effect(move |_| {
let percent = percent().into();
id.update_state(SliderUpdate::Percent(percent.0));
});
let percent = create_updater(
move || {
let percent = percent().into();
percent.0
},
move |percent| {
id.update_state(SliderUpdate::Percent(percent));
},
);
Slider {
id,
onchangepx: None,
onchangepct: None,
held: false,
percent: 0.0,
percent,
prev_percent: 0.0,
handle: Default::default(),
base_bar_style: Default::default(),
Expand Down Expand Up @@ -499,3 +504,166 @@ impl SliderCustomStyle {
self
}
}

#[cfg(test)]
mod test {

use crate::{
context::{EventCx, UpdateCx},
event::Event,
pointer::{PointerButton, PointerInputEvent, PointerMoveEvent},
AppState,
};

use super::*;

// Test helper to create a minimal AppState
fn create_test_app_state(view_id: ViewId) -> AppState {
AppState::new(view_id)
}

// Test helper to create UpdateCx
fn create_test_update_cx(view_id: ViewId) -> UpdateCx<'static> {
UpdateCx {
app_state: Box::leak(Box::new(create_test_app_state(view_id))),
}
}

// Test helper to create EventCx
fn create_test_event_cx(view_id: ViewId) -> EventCx<'static> {
EventCx {
app_state: Box::leak(Box::new(create_test_app_state(view_id))),
}
}

// Helper to directly update slider value
fn update_slider_value(slider: &mut Slider, value: f64) {
let mut cx = create_test_update_cx(slider.id());
let state = Box::new(SliderUpdate::Percent(value));
slider.update(&mut cx, state);
}

#[test]
fn test_slider_initial_value() {
let percent = 53.0;
let slider = Slider::new(move || percent);
assert_eq!(slider.percent, percent as f64);
}

#[test]
fn test_slider_bounds() {
let mut slider = Slider::new(|| 0.0);

// Test upper bound
update_slider_value(&mut slider, 150.0);
slider.update_restrict_position();
assert_eq!(slider.percent, 100.0);

// Test lower bound
update_slider_value(&mut slider, -50.0);
slider.update_restrict_position();
assert_eq!(slider.percent, 0.0);
}

#[test]
fn test_slider_pointer_events() {
let mut slider = Slider::new(|| 0.0);
let mut cx = create_test_event_cx(slider.id());

// Set initial size for pointer calculations
slider.size = taffy::prelude::Size {
width: 100.0,
height: 20.0,
};

// Test pointer down at 75%
let pointer_down = Event::PointerDown(PointerInputEvent {
count: 1,
pos: Point::new(75.0, 10.0),
button: PointerButton::Primary,
modifiers: Default::default(),
});

slider.event_before_children(&mut cx, &pointer_down);
slider.update_restrict_position();

assert_eq!(slider.percent, 75.0);
assert!(slider.held);
assert_eq!(cx.app_state.active, Some(slider.id()));
}

#[test]
fn test_slider_drag_state() {
let mut slider = Slider::new(|| 50.0);
let mut cx = create_test_event_cx(slider.id());

slider.size = taffy::prelude::Size {
width: 100.0,
height: 20.0,
};

// Start drag
let pointer_down = Event::PointerDown(PointerInputEvent {
pos: Point::new(50.0, 10.0),
button: PointerButton::Primary,
count: 1,
modifiers: Default::default(),
});

slider.event_before_children(&mut cx, &pointer_down);
assert!(slider.held);
assert_eq!(cx.app_state.active, Some(slider.id()));

// Move while dragging
let pointer_move = Event::PointerMove(PointerMoveEvent {
pos: Point::new(75.0, 10.0),
modifiers: Default::default(),
});

slider.event_before_children(&mut cx, &pointer_move);
assert_eq!(slider.percent, 75.0);

// End drag
let pointer_up = Event::PointerUp(PointerInputEvent {
pos: Point::new(75.0, 10.0),
button: PointerButton::Primary,
count: 1,
modifiers: Default::default(),
});

slider.event_before_children(&mut cx, &pointer_up);
assert!(!slider.held);
}

#[test]
fn test_callback_handling() {
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

let callback_called = Arc::new(AtomicBool::new(false));
let callback_called_clone = callback_called.clone();

let mut slider = Slider::new(|| 0.0).on_change_pct(move |_| {
callback_called_clone.store(true, Ordering::SeqCst);
});

let mut cx = create_test_event_cx(slider.id());

slider.size = taffy::prelude::Size {
width: 100.0,
height: 20.0,
};

let pointer_event = Event::PointerDown(PointerInputEvent {
pos: Point::new(60.0, 10.0),
button: PointerButton::Primary,
count: 1,
modifiers: Default::default(),
});

slider.event_before_children(&mut cx, &pointer_event);
slider.update_restrict_position();

assert!(callback_called.load(Ordering::SeqCst));
}
}