1#![allow(clippy::missing_const_for_fn)]
2#![allow(clippy::missing_fields_in_debug)]
3#![allow(clippy::struct_excessive_bools)]
4#![allow(clippy::many_single_char_names)]
5#![allow(clippy::too_many_arguments)]
6#![allow(clippy::should_implement_trait)]
7#![allow(clippy::trivially_copy_pass_by_ref)]
8#![allow(clippy::fn_params_excessive_bools)]
9#![allow(clippy::type_complexity)]
10#![allow(clippy::match_same_arms)]
11#![allow(clippy::unreadable_literal)]
12#![allow(clippy::manual_clamp)]
13#![allow(clippy::unnecessary_wraps)]
14#![allow(clippy::match_like_matches_macro)]
15#![allow(clippy::struct_field_names)]
16#![allow(clippy::needless_pass_by_value)]
17#![allow(clippy::cast_possible_wrap)]
18pub mod accessibility;
65pub mod animation;
66pub mod binding;
67pub mod cache;
68mod canvas;
69pub mod chart;
70pub mod clipboard;
71mod color;
72mod constraints;
73pub mod diff;
74pub mod dnd;
75pub mod draw;
76mod event;
77mod geometry;
78pub mod gesture;
79pub mod history;
80pub mod lifecycle;
81mod runtime;
82pub mod shortcut;
83pub mod simd;
84
85pub use simd::{
87 batch_mean_f64, batch_min_max_f64, batch_scale_f64, batch_scale_offset_f64, batch_stddev_f64,
88 batch_sum_f64, batch_variance_f64, histogram_f64, normalize_f64, normalize_with_range_f64,
89 percentile_sorted_f64, weighted_sum_f64,
90};
91mod state;
92pub mod streaming;
93pub mod theme;
94pub mod validation;
95pub mod virtualization;
96pub mod widget;
97
98pub mod brick_widget;
100
101pub use accessibility::{
102 AccessibilityTree, AccessibilityTreeBuilder, AccessibleNode, AccessibleNodeId, CheckedState,
103 HitTester, LiveRegion,
104};
105pub use animation::{
106 AnimColor, AnimatedValue, AnimationController, EasedValue, Easing, Interpolate, Keyframe,
107 KeyframeTrack, Spring, SpringConfig,
108};
109pub use cache::{
110 CacheBuilder, CacheCallback, CacheConfig, CacheEvent, CacheKey, CacheMetadata, CacheOptions,
111 CacheSize, CacheState, CacheStats, DataCache, StringCache,
112};
113pub use canvas::RecordingCanvas;
114pub use chart::{
115 ArcGeometry, CatmullRom, CubicBezier, CubicSpline, DataNormalizer, DrawBatch, HistogramBins,
116 Interpolator, LinearInterpolator, PathTessellator, Point2D,
117};
118pub use clipboard::{
119 Clipboard, ClipboardData, ClipboardEvent, ClipboardFormat, ClipboardHistory,
120 ClipboardOperation, ClipboardResult,
121};
122pub use color::{Color, ColorParseError};
123pub use constraints::Constraints;
124pub use diff::{diff_trees, DiffNode, DiffOp, DiffResult, TreeDiffer, WidgetKey};
125pub use dnd::{
126 DragData, DragDataType, DragDropManager, DragId, DragPayload, DragPhase, DragState, DropEffect,
127 DropResult, DropTarget,
128};
129pub use draw::{
130 BoxStyle, DrawCommand, FillRule, LineCap, LineJoin, PathRef, Sampling, Shadow, StrokeStyle,
131 TensorRef, Transform2D as DrawTransform,
132};
133pub use event::{Event, GestureState, Key, MouseButton, PointerId, PointerType, TouchId};
134pub use geometry::{CornerRadius, Point, Rect, Size};
135pub use gesture::{
136 GestureConfig, GestureRecognizer, PointerGestureRecognizer, PointerInfo, RecognizedGesture,
137 TouchPoint,
138};
139pub use history::{
140 Checkpoint, CheckpointId, Command as HistoryCommand, CommandHistory, CommandId, CommandResult,
141 CompositeCommand, GroupId, HistoryCallback, HistoryConfig, HistoryEvent, SetValueCommand,
142};
143pub use lifecycle::{
144 Effect, EffectManager, HookId, LifecycleEvent, LifecycleManager, LifecyclePhase,
145};
146pub use runtime::{
147 default_executor, AnimatedProperty, AnimationId, AnimationInstance, AnimationState, Animator,
148 CommandExecutor, DataRefreshManager, EasingFunction, ExecutionResult, ExecutorConfig,
149 FocusDirection, FocusManager, FocusTrap, FrameTimer, MemoryRouter, MemoryStorage, RefreshTask,
150 Router, SpringAnimation, Storage, Timer, TransitionConfig, Tween,
151};
152pub use shortcut::{
153 Modifiers, Shortcut, ShortcutBuilder, ShortcutContext, ShortcutId, ShortcutManager,
154 ShortcutPriority,
155};
156pub use state::{Command, CounterMessage, CounterState, State, Store};
157pub use streaming::{
158 ConnectionState, DataStream, MessageBuffer, RateLimiter, ReconnectConfig, StreamConfig,
159 StreamMessage, StreamSubscription,
160};
161pub use theme::{ColorPalette, ContrastCheck, Radii, Shadows, Spacing, Theme, Typography};
162pub use validation::{
163 FieldConfig, FieldState, FormValidator, MaxLength, MinLength, Pattern, PatternType, Range,
164 Required, ValidateOn, ValidationResult, Validator,
165};
166pub use virtualization::{
167 CellLayout, GridCell, ItemIndex, ItemLayout, ScrollAlign, VirtualGrid, VirtualGridConfig,
168 VirtualList, VirtualListConfig, VisibleGridRange, VisibleRange,
169};
170pub use widget::{
171 AccessibleRole, Canvas, FontStyle, FontWeight, LayoutResult, TextStyle, Transform2D, TypeId,
172 Widget, WidgetId,
173};
174
175pub use widget::{
177 Brick, BrickAssertion, BrickBudget, BrickError, BrickPhase, BrickResult, BrickVerification,
178 BudgetViolation,
179};
180
181pub use brick_widget::{BrickWidgetExt, DefaultBrick, SimpleBrick};
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187
188 mod color_tests {
193 use super::*;
194 use proptest::prelude::*;
195
196 #[test]
197 fn test_color_new_clamps_values() {
198 let c = Color::new(1.5, -0.5, 0.5, 2.0);
199 assert_eq!(c.r, 1.0);
200 assert_eq!(c.g, 0.0);
201 assert_eq!(c.b, 0.5);
202 assert_eq!(c.a, 1.0);
203 }
204
205 #[test]
206 fn test_color_from_rgb() {
207 let c = Color::rgb(0.5, 0.5, 0.5);
208 assert_eq!(c.r, 0.5);
209 assert_eq!(c.g, 0.5);
210 assert_eq!(c.b, 0.5);
211 assert_eq!(c.a, 1.0);
212 }
213
214 #[test]
215 fn test_color_from_hex() {
216 let c = Color::from_hex("#ff0000").unwrap();
217 assert_eq!(c.r, 1.0);
218 assert_eq!(c.g, 0.0);
219 assert_eq!(c.b, 0.0);
220
221 let c2 = Color::from_hex("#00ff00").unwrap();
222 assert_eq!(c2.g, 1.0);
223
224 let c3 = Color::from_hex("0000ff").unwrap();
225 assert_eq!(c3.b, 1.0);
226 }
227
228 #[test]
229 fn test_color_from_hex_with_alpha() {
230 let c = Color::from_hex("#ff000080").unwrap();
231 assert_eq!(c.r, 1.0);
232 assert!((c.a - 0.502).abs() < 0.01); }
234
235 #[test]
236 fn test_color_from_hex_invalid() {
237 assert!(Color::from_hex("invalid").is_err());
238 assert!(Color::from_hex("#gg0000").is_err());
239 assert!(Color::from_hex("#ff").is_err());
240 }
241
242 #[test]
243 fn test_color_relative_luminance_black() {
244 let black = Color::rgb(0.0, 0.0, 0.0);
245 assert_eq!(black.relative_luminance(), 0.0);
246 }
247
248 #[test]
249 fn test_color_relative_luminance_white() {
250 let white = Color::rgb(1.0, 1.0, 1.0);
251 assert!((white.relative_luminance() - 1.0).abs() < 0.001);
252 }
253
254 #[test]
255 fn test_color_contrast_ratio_black_white() {
256 let black = Color::rgb(0.0, 0.0, 0.0);
257 let white = Color::rgb(1.0, 1.0, 1.0);
258 let ratio = black.contrast_ratio(&white);
259 assert!((ratio - 21.0).abs() < 0.1); }
261
262 #[test]
263 fn test_color_contrast_ratio_wcag_aa() {
264 let dark = Color::rgb(0.0, 0.0, 0.0);
266 let light = Color::rgb(0.5, 0.5, 0.5);
267 let ratio = dark.contrast_ratio(&light);
268 assert!(ratio >= 4.5, "Contrast ratio {ratio} should be >= 4.5");
269 }
270
271 #[test]
272 fn test_color_contrast_ratio_symmetric() {
273 let c1 = Color::rgb(0.2, 0.4, 0.6);
274 let c2 = Color::rgb(0.8, 0.6, 0.4);
275 assert_eq!(c1.contrast_ratio(&c2), c2.contrast_ratio(&c1));
276 }
277
278 #[test]
279 fn test_color_to_hex() {
280 let c = Color::rgb(1.0, 0.0, 0.0);
281 assert_eq!(c.to_hex(), "#ff0000");
282
283 let c2 = Color::new(0.0, 1.0, 0.0, 0.5);
284 assert_eq!(c2.to_hex_with_alpha(), "#00ff0080");
285 }
286
287 #[test]
288 fn test_color_lerp() {
289 let black = Color::rgb(0.0, 0.0, 0.0);
290 let white = Color::rgb(1.0, 1.0, 1.0);
291
292 let mid = black.lerp(&white, 0.5);
293 assert!((mid.r - 0.5).abs() < 0.001);
294 assert!((mid.g - 0.5).abs() < 0.001);
295 assert!((mid.b - 0.5).abs() < 0.001);
296 }
297
298 proptest! {
299 #[test]
300 fn prop_color_clamps_to_valid_range(r in -1.0f32..2.0, g in -1.0f32..2.0, b in -1.0f32..2.0, a in -1.0f32..2.0) {
301 let c = Color::new(r, g, b, a);
302 prop_assert!(c.r >= 0.0 && c.r <= 1.0);
303 prop_assert!(c.g >= 0.0 && c.g <= 1.0);
304 prop_assert!(c.b >= 0.0 && c.b <= 1.0);
305 prop_assert!(c.a >= 0.0 && c.a <= 1.0);
306 }
307
308 #[test]
309 fn prop_contrast_ratio_always_positive(
310 r1 in 0.0f32..1.0, g1 in 0.0f32..1.0, b1 in 0.0f32..1.0,
311 r2 in 0.0f32..1.0, g2 in 0.0f32..1.0, b2 in 0.0f32..1.0
312 ) {
313 let c1 = Color::rgb(r1, g1, b1);
314 let c2 = Color::rgb(r2, g2, b2);
315 prop_assert!(c1.contrast_ratio(&c2) >= 1.0);
316 }
317
318 #[test]
319 fn prop_lerp_at_zero_returns_self(r in 0.0f32..1.0, g in 0.0f32..1.0, b in 0.0f32..1.0) {
320 let c1 = Color::rgb(r, g, b);
321 let c2 = Color::rgb(1.0 - r, 1.0 - g, 1.0 - b);
322 let result = c1.lerp(&c2, 0.0);
323 prop_assert!((result.r - c1.r).abs() < 0.001);
324 prop_assert!((result.g - c1.g).abs() < 0.001);
325 prop_assert!((result.b - c1.b).abs() < 0.001);
326 }
327
328 #[test]
329 fn prop_lerp_at_one_returns_other(r in 0.0f32..1.0, g in 0.0f32..1.0, b in 0.0f32..1.0) {
330 let c1 = Color::rgb(r, g, b);
331 let c2 = Color::rgb(1.0 - r, 1.0 - g, 1.0 - b);
332 let result = c1.lerp(&c2, 1.0);
333 prop_assert!((result.r - c2.r).abs() < 0.001);
334 prop_assert!((result.g - c2.g).abs() < 0.001);
335 prop_assert!((result.b - c2.b).abs() < 0.001);
336 }
337 }
338 }
339
340 mod geometry_tests {
345 use super::*;
346 use proptest::prelude::*;
347
348 #[test]
349 fn test_point_new() {
350 let p = Point::new(10.0, 20.0);
351 assert_eq!(p.x, 10.0);
352 assert_eq!(p.y, 20.0);
353 }
354
355 #[test]
356 fn test_point_origin() {
357 let p = Point::ORIGIN;
358 assert_eq!(p.x, 0.0);
359 assert_eq!(p.y, 0.0);
360 }
361
362 #[test]
363 fn test_point_distance() {
364 let p1 = Point::new(0.0, 0.0);
365 let p2 = Point::new(3.0, 4.0);
366 assert!((p1.distance(&p2) - 5.0).abs() < 0.001);
367 }
368
369 #[test]
370 fn test_point_add() {
371 let p1 = Point::new(1.0, 2.0);
372 let p2 = Point::new(3.0, 4.0);
373 let sum = p1 + p2;
374 assert_eq!(sum.x, 4.0);
375 assert_eq!(sum.y, 6.0);
376 }
377
378 #[test]
379 fn test_point_sub() {
380 let p1 = Point::new(5.0, 7.0);
381 let p2 = Point::new(2.0, 3.0);
382 let diff = p1 - p2;
383 assert_eq!(diff.x, 3.0);
384 assert_eq!(diff.y, 4.0);
385 }
386
387 #[test]
388 fn test_size_new() {
389 let s = Size::new(100.0, 200.0);
390 assert_eq!(s.width, 100.0);
391 assert_eq!(s.height, 200.0);
392 }
393
394 #[test]
395 fn test_size_zero() {
396 let s = Size::ZERO;
397 assert_eq!(s.width, 0.0);
398 assert_eq!(s.height, 0.0);
399 }
400
401 #[test]
402 fn test_size_area() {
403 let s = Size::new(10.0, 20.0);
404 assert_eq!(s.area(), 200.0);
405 }
406
407 #[test]
408 fn test_size_aspect_ratio() {
409 let s = Size::new(16.0, 9.0);
410 assert!((s.aspect_ratio() - 16.0 / 9.0).abs() < 0.001);
411 }
412
413 #[test]
414 fn test_size_contains() {
415 let s = Size::new(100.0, 100.0);
416 let smaller = Size::new(50.0, 50.0);
417 let larger = Size::new(150.0, 50.0);
418 assert!(s.contains(&smaller));
419 assert!(!s.contains(&larger));
420 }
421
422 #[test]
423 fn test_rect_new() {
424 let r = Rect::new(10.0, 20.0, 100.0, 200.0);
425 assert_eq!(r.x, 10.0);
426 assert_eq!(r.y, 20.0);
427 assert_eq!(r.width, 100.0);
428 assert_eq!(r.height, 200.0);
429 }
430
431 #[test]
432 fn test_rect_from_points() {
433 let r = Rect::from_points(Point::new(10.0, 20.0), Point::new(110.0, 220.0));
434 assert_eq!(r.x, 10.0);
435 assert_eq!(r.y, 20.0);
436 assert_eq!(r.width, 100.0);
437 assert_eq!(r.height, 200.0);
438 }
439
440 #[test]
441 fn test_rect_from_size() {
442 let r = Rect::from_size(Size::new(100.0, 200.0));
443 assert_eq!(r.x, 0.0);
444 assert_eq!(r.y, 0.0);
445 assert_eq!(r.width, 100.0);
446 assert_eq!(r.height, 200.0);
447 }
448
449 #[test]
450 fn test_rect_origin_and_size() {
451 let r = Rect::new(10.0, 20.0, 100.0, 200.0);
452 assert_eq!(r.origin(), Point::new(10.0, 20.0));
453 assert_eq!(r.size(), Size::new(100.0, 200.0));
454 }
455
456 #[test]
457 fn test_rect_corners() {
458 let r = Rect::new(10.0, 20.0, 100.0, 200.0);
459 assert_eq!(r.top_left(), Point::new(10.0, 20.0));
460 assert_eq!(r.top_right(), Point::new(110.0, 20.0));
461 assert_eq!(r.bottom_left(), Point::new(10.0, 220.0));
462 assert_eq!(r.bottom_right(), Point::new(110.0, 220.0));
463 }
464
465 #[test]
466 fn test_rect_center() {
467 let r = Rect::new(0.0, 0.0, 100.0, 100.0);
468 assert_eq!(r.center(), Point::new(50.0, 50.0));
469 }
470
471 #[test]
472 fn test_rect_contains_point() {
473 let r = Rect::new(10.0, 10.0, 100.0, 100.0);
474 assert!(r.contains_point(&Point::new(50.0, 50.0)));
475 assert!(r.contains_point(&Point::new(10.0, 10.0))); assert!(!r.contains_point(&Point::new(5.0, 50.0)));
477 assert!(!r.contains_point(&Point::new(111.0, 50.0)));
478 }
479
480 #[test]
481 fn test_rect_intersects() {
482 let r1 = Rect::new(0.0, 0.0, 100.0, 100.0);
483 let r2 = Rect::new(50.0, 50.0, 100.0, 100.0);
484 let r3 = Rect::new(200.0, 200.0, 100.0, 100.0);
485
486 assert!(r1.intersects(&r2));
487 assert!(!r1.intersects(&r3));
488 }
489
490 #[test]
491 fn test_rect_intersection() {
492 let r1 = Rect::new(0.0, 0.0, 100.0, 100.0);
493 let r2 = Rect::new(50.0, 50.0, 100.0, 100.0);
494
495 let inter = r1.intersection(&r2).unwrap();
496 assert_eq!(inter.x, 50.0);
497 assert_eq!(inter.y, 50.0);
498 assert_eq!(inter.width, 50.0);
499 assert_eq!(inter.height, 50.0);
500 }
501
502 #[test]
503 fn test_rect_union() {
504 let r1 = Rect::new(0.0, 0.0, 50.0, 50.0);
505 let r2 = Rect::new(25.0, 25.0, 50.0, 50.0);
506
507 let union = r1.union(&r2);
508 assert_eq!(union.x, 0.0);
509 assert_eq!(union.y, 0.0);
510 assert_eq!(union.width, 75.0);
511 assert_eq!(union.height, 75.0);
512 }
513
514 #[test]
515 fn test_rect_inset() {
516 let r = Rect::new(10.0, 10.0, 100.0, 100.0);
517 let inset = r.inset(5.0);
518 assert_eq!(inset.x, 15.0);
519 assert_eq!(inset.y, 15.0);
520 assert_eq!(inset.width, 90.0);
521 assert_eq!(inset.height, 90.0);
522 }
523
524 #[test]
525 fn test_corner_radius() {
526 let uniform = CornerRadius::uniform(10.0);
527 assert_eq!(uniform.top_left, 10.0);
528 assert_eq!(uniform.top_right, 10.0);
529 assert_eq!(uniform.bottom_left, 10.0);
530 assert_eq!(uniform.bottom_right, 10.0);
531
532 let custom = CornerRadius::new(1.0, 2.0, 3.0, 4.0);
533 assert_eq!(custom.top_left, 1.0);
534 assert_eq!(custom.top_right, 2.0);
535 assert_eq!(custom.bottom_right, 3.0);
536 assert_eq!(custom.bottom_left, 4.0);
537 }
538
539 proptest! {
540 #[test]
541 fn prop_point_distance_non_negative(x1 in -1000.0f32..1000.0, y1 in -1000.0f32..1000.0, x2 in -1000.0f32..1000.0, y2 in -1000.0f32..1000.0) {
542 let p1 = Point::new(x1, y1);
543 let p2 = Point::new(x2, y2);
544 prop_assert!(p1.distance(&p2) >= 0.0);
545 }
546
547 #[test]
548 fn prop_point_distance_symmetric(x1 in -1000.0f32..1000.0, y1 in -1000.0f32..1000.0, x2 in -1000.0f32..1000.0, y2 in -1000.0f32..1000.0) {
549 let p1 = Point::new(x1, y1);
550 let p2 = Point::new(x2, y2);
551 prop_assert!((p1.distance(&p2) - p2.distance(&p1)).abs() < 0.001);
552 }
553
554 #[test]
555 fn prop_rect_area_non_negative(x in -1000.0f32..1000.0, y in -1000.0f32..1000.0, w in 0.0f32..1000.0, h in 0.0f32..1000.0) {
556 let r = Rect::new(x, y, w, h);
557 prop_assert!(r.area() >= 0.0);
558 }
559
560 #[test]
561 fn prop_rect_contains_center(x in -1000.0f32..1000.0, y in -1000.0f32..1000.0, w in 1.0f32..1000.0, h in 1.0f32..1000.0) {
562 let r = Rect::new(x, y, w, h);
563 prop_assert!(r.contains_point(&r.center()));
564 }
565
566 #[test]
567 fn prop_rect_intersects_self(x in -1000.0f32..1000.0, y in -1000.0f32..1000.0, w in 0.1f32..1000.0, h in 0.1f32..1000.0) {
568 let r = Rect::new(x, y, w, h);
569 prop_assert!(r.intersects(&r));
570 }
571 }
572 }
573
574 mod constraints_tests {
579 use super::*;
580
581 #[test]
582 fn test_constraints_tight() {
583 let c = Constraints::tight(Size::new(100.0, 200.0));
584 assert_eq!(c.min_width, 100.0);
585 assert_eq!(c.max_width, 100.0);
586 assert_eq!(c.min_height, 200.0);
587 assert_eq!(c.max_height, 200.0);
588 }
589
590 #[test]
591 fn test_constraints_loose() {
592 let c = Constraints::loose(Size::new(100.0, 200.0));
593 assert_eq!(c.min_width, 0.0);
594 assert_eq!(c.max_width, 100.0);
595 assert_eq!(c.min_height, 0.0);
596 assert_eq!(c.max_height, 200.0);
597 }
598
599 #[test]
600 fn test_constraints_unbounded() {
601 let c = Constraints::unbounded();
602 assert_eq!(c.min_width, 0.0);
603 assert_eq!(c.max_width, f32::INFINITY);
604 assert_eq!(c.min_height, 0.0);
605 assert_eq!(c.max_height, f32::INFINITY);
606 }
607
608 #[test]
609 fn test_constraints_constrain() {
610 let c = Constraints::new(50.0, 150.0, 50.0, 150.0);
611
612 assert_eq!(
614 c.constrain(Size::new(100.0, 100.0)),
615 Size::new(100.0, 100.0)
616 );
617
618 assert_eq!(c.constrain(Size::new(10.0, 10.0)), Size::new(50.0, 50.0));
620
621 assert_eq!(
623 c.constrain(Size::new(200.0, 200.0)),
624 Size::new(150.0, 150.0)
625 );
626 }
627
628 #[test]
629 fn test_constraints_is_tight() {
630 let tight = Constraints::tight(Size::new(100.0, 100.0));
631 let loose = Constraints::loose(Size::new(100.0, 100.0));
632
633 assert!(tight.is_tight());
634 assert!(!loose.is_tight());
635 }
636
637 #[test]
638 fn test_constraints_has_bounded_width() {
639 let bounded = Constraints::new(0.0, 100.0, 0.0, f32::INFINITY);
640 let unbounded = Constraints::unbounded();
641
642 assert!(bounded.has_bounded_width());
643 assert!(!unbounded.has_bounded_width());
644 }
645 }
646
647 mod event_tests {
652 use super::*;
653
654 #[test]
655 fn test_event_mouse_move() {
656 let e = Event::MouseMove {
657 position: Point::new(100.0, 200.0),
658 };
659 if let Event::MouseMove { position } = e {
660 assert_eq!(position.x, 100.0);
661 assert_eq!(position.y, 200.0);
662 } else {
663 panic!("Expected MouseMove event");
664 }
665 }
666
667 #[test]
668 fn test_event_mouse_button() {
669 let e = Event::MouseDown {
670 position: Point::new(50.0, 50.0),
671 button: MouseButton::Left,
672 };
673 if let Event::MouseDown { button, .. } = e {
674 assert_eq!(button, MouseButton::Left);
675 } else {
676 panic!("Expected MouseDown event");
677 }
678 }
679
680 #[test]
681 fn test_event_key() {
682 let e = Event::KeyDown { key: Key::Enter };
683 if let Event::KeyDown { key } = e {
684 assert_eq!(key, Key::Enter);
685 } else {
686 panic!("Expected KeyDown event");
687 }
688 }
689
690 #[test]
691 fn test_event_scroll() {
692 let e = Event::Scroll {
693 delta_x: 0.0,
694 delta_y: -10.0,
695 };
696 if let Event::Scroll { delta_y, .. } = e {
697 assert_eq!(delta_y, -10.0);
698 } else {
699 panic!("Expected Scroll event");
700 }
701 }
702
703 #[test]
704 fn test_event_text_input() {
705 let e = Event::TextInput {
706 text: "hello".to_string(),
707 };
708 if let Event::TextInput { text } = e {
709 assert_eq!(text, "hello");
710 } else {
711 panic!("Expected TextInput event");
712 }
713 }
714 }
715}