Skip to main content

ferroui_reactiveui_testing/
test_scheduler_extensions.rs

1//! `TestSchedulerExtensions` (`ReactiveUI.Testing.Reactive/TestSchedulerExtensions.cs`).
2
3use ferroui_reactive::{Notification, ObservableError};
4use ferroui_reactive_testing::{duration_to_ticks, Recorded, TestScheduler};
5use std::time::Duration;
6
7/// The ticks of 100 nanoseconds in a millisecond (`TimeSpan.TicksPerMillisecond`).
8const TICKS_PER_MILLISECOND: f64 = 10_000.0;
9
10/// `TestScheduler.FromTimeSpan(TimeSpan.FromMilliseconds(milliseconds))`: the ticks of a time in
11/// milliseconds, truncated to a whole tick as `TimeSpan.FromMilliseconds` does.
12fn ticks_from_milliseconds(milliseconds: f64) -> i64 {
13    (milliseconds * TICKS_PER_MILLISECOND) as i64
14}
15
16/// The virtual time of a [`TestScheduler`] in milliseconds, and recorded notifications at a time in
17/// milliseconds (`TestSchedulerExtensions`, from ReactiveUI.Testing.Reactive).
18///
19/// The functions without a scheduler are called on the type, as upstream's static extension
20/// members are: `TestScheduler::on_next_at(100.0, 42)`.
21///
22/// Not ported: the `ArgumentException` of a time that is not a number and the
23/// `OverflowException` of one too large for a `TimeSpan` - argument validation (the conversion
24/// saturates).
25pub trait TestSchedulerExtensions {
26    /// The ticks of the virtual time of a duration (`FromTimeSpan`).
27    fn from_time_span(span: Duration) -> i64;
28
29    /// A value at a time in milliseconds (`OnNextAt<T>(double, T)`).
30    fn on_next_at<T>(milliseconds: f64, value: T) -> Recorded<Notification<T>>;
31
32    /// An error at a time in milliseconds (`OnErrorAt<T>(double, Exception)`).
33    fn on_error_at<T>(milliseconds: f64, error: ObservableError) -> Recorded<Notification<T>>;
34
35    /// The end of a sequence at a time in milliseconds (`OnCompletedAt<T>(double)`).
36    fn on_completed_at<T>(milliseconds: f64) -> Recorded<Notification<T>>;
37
38    /// Runs the scheduler until its clock reaches the absolute time in milliseconds
39    /// (`AdvanceToMs`).
40    fn advance_to_ms(&self, milliseconds: f64);
41
42    /// Runs the scheduler for a time in milliseconds (`AdvanceByMs`).
43    fn advance_by_ms(&self, milliseconds: f64);
44}
45
46impl TestSchedulerExtensions for TestScheduler {
47    fn from_time_span(span: Duration) -> i64 {
48        duration_to_ticks(span)
49    }
50
51    fn on_next_at<T>(milliseconds: f64, value: T) -> Recorded<Notification<T>> {
52        Recorded::new(ticks_from_milliseconds(milliseconds), Notification::OnNext(value))
53    }
54
55    fn on_error_at<T>(milliseconds: f64, error: ObservableError) -> Recorded<Notification<T>> {
56        Recorded::new(ticks_from_milliseconds(milliseconds), Notification::OnError(error))
57    }
58
59    fn on_completed_at<T>(milliseconds: f64) -> Recorded<Notification<T>> {
60        Recorded::new(ticks_from_milliseconds(milliseconds), Notification::OnCompleted)
61    }
62
63    fn advance_to_ms(&self, milliseconds: f64) {
64        self.advance_to(ticks_from_milliseconds(milliseconds));
65    }
66
67    fn advance_by_ms(&self, milliseconds: f64) {
68        self.advance_by(ticks_from_milliseconds(milliseconds));
69    }
70}