use super::*;
fn policy_enabled_at(now: Instant) -> AccessibilityPublishPolicy {
let mut policy = AccessibilityPublishPolicy::new();
assert!(policy.update_enabled(true));
assert!(policy.try_begin_publish(now));
policy
}
#[test]
fn disabled_policy_never_publishes_and_arms_no_wake() {
let mut policy = AccessibilityPublishPolicy::new();
let now = Instant::now();
assert!(!policy.try_begin_publish(now));
assert_eq!(policy.wake_deadline(), None);
}
#[test]
fn first_publish_after_enabling_is_immediate() {
let mut policy = AccessibilityPublishPolicy::new();
assert!(policy.update_enabled(true));
assert!(policy.try_begin_publish(Instant::now()));
}
#[test]
fn enabling_twice_reports_the_transition_once() {
let mut policy = AccessibilityPublishPolicy::new();
assert!(policy.update_enabled(true));
assert!(!policy.update_enabled(true));
}
#[test]
fn re_enabling_after_disable_reports_a_fresh_transition() {
let mut policy = AccessibilityPublishPolicy::new();
assert!(policy.update_enabled(true));
assert!(!policy.update_enabled(false));
assert!(policy.update_enabled(true));
}
#[test]
fn publish_inside_the_window_is_refused_with_a_wake_deadline() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
let inside = start + ACCESSIBILITY_PUBLISH_INTERVAL / 2;
assert!(!policy.try_begin_publish(inside));
assert_eq!(
policy.wake_deadline(),
Some(start + ACCESSIBILITY_PUBLISH_INTERVAL)
);
}
#[test]
fn publish_after_the_window_opens_is_allowed_and_clears_the_wake() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
assert!(!policy.try_begin_publish(start + ACCESSIBILITY_PUBLISH_INTERVAL / 2));
let open = start + ACCESSIBILITY_PUBLISH_INTERVAL;
assert!(policy.try_begin_publish(open));
assert_eq!(policy.wake_deadline(), None);
}
#[test]
fn window_open_probe_that_finds_no_change_leaves_no_wake() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
assert!(!policy.try_begin_publish(start + ACCESSIBILITY_PUBLISH_INTERVAL / 2));
assert!(policy.try_begin_publish(start + ACCESSIBILITY_PUBLISH_INTERVAL));
assert_eq!(policy.wake_deadline(), None);
}
#[test]
fn a_probe_consumes_the_window_even_when_nothing_publishes() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
let probe = start + ACCESSIBILITY_PUBLISH_INTERVAL;
assert!(policy.try_begin_publish(probe));
assert!(!policy.try_begin_publish(probe + Duration::from_millis(16)));
assert!(policy.try_begin_publish(probe + ACCESSIBILITY_PUBLISH_INTERVAL));
}
#[test]
fn disabling_clears_a_pending_wake() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
assert!(!policy.try_begin_publish(start + ACCESSIBILITY_PUBLISH_INTERVAL / 2));
assert!(policy.wake_deadline().is_some());
policy.update_enabled(false);
assert_eq!(policy.wake_deadline(), None);
}
#[test]
fn re_enabling_publishes_immediately_even_right_after_a_publish() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
policy.update_enabled(false);
assert!(policy.update_enabled(true));
assert!(policy.try_begin_publish(start + Duration::from_millis(1)));
}
fn publish_waits(start: Instant, publishes: usize, read_after: &[usize]) -> Vec<Duration> {
let mut policy = AccessibilityPublishPolicy::new();
assert!(policy.update_enabled(true));
let mut now = start;
let mut waits = Vec::new();
let mut last = None;
for index in 0..publishes {
while !policy.try_begin_publish(now) {
now = policy
.wake_deadline()
.expect("a refused publish arms a wake");
}
if let Some(last) = last {
waits.push(now - last);
}
last = Some(now);
policy.published(true);
if read_after.contains(&index) {
policy.note_read(now);
}
}
waits
}
#[test]
fn unread_trees_publish_less_often_up_to_the_unread_interval() {
let s = Duration::from_secs;
assert_eq!(
publish_waits(Instant::now(), 6, &[]),
[s(1), s(2), s(4), s(4), s(4)],
"each unread tree doubles the wait from a second, up to four"
);
}
#[test]
fn a_reader_in_use_gets_changes_at_the_interactive_interval() {
let ms = Duration::from_millis;
let mut expected = vec![ms(1000), ms(2000)];
expected.extend([ms(100); 19]);
expected.extend([ms(1000), ms(2000), ms(4000), ms(4000)]);
assert_eq!(publish_waits(Instant::now(), 26, &[2]), expected);
}
#[test]
fn a_screen_reader_keeps_the_publish_interval_without_reads() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
policy.published(false);
let next = start + ACCESSIBILITY_PUBLISH_INTERVAL;
assert!(policy.try_begin_publish(next));
policy.published(false);
assert!(!policy.try_begin_publish(next + ACCESSIBILITY_PUBLISH_INTERVAL / 2));
assert!(policy.try_begin_publish(next + ACCESSIBILITY_PUBLISH_INTERVAL));
}
#[test]
fn a_change_waits_for_the_interval_unless_a_reader_needs_it_now() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
let inside = start + ACCESSIBILITY_PUBLISH_INTERVAL / 2;
assert!(
!policy.try_publish_change(inside, true, false),
"a change nobody needs now waits"
);
assert_eq!(
policy.wake_deadline(),
Some(start + ACCESSIBILITY_PUBLISH_INTERVAL),
"a frame comes when the waiting change is due"
);
assert!(
policy.try_publish_change(inside, true, true),
"a focus move or an edit shows inside the interval"
);
assert_eq!(
policy.wake_deadline(),
None,
"the change it showed leaves nothing to wake for"
);
assert!(
!policy.try_publish_change(inside + Duration::from_millis(16), true, false),
"the next change waits a whole interval after it"
);
}
#[test]
fn an_unchanged_tree_arms_no_wake_inside_the_interval() {
let start = Instant::now();
let mut policy = policy_enabled_at(start);
let inside = start + ACCESSIBILITY_PUBLISH_INTERVAL / 2;
assert!(
!policy.try_publish_change(inside, false, true),
"a focus move or an edit that left the tree as published builds nothing"
);
assert!(!policy.try_publish_change(inside, false, false));
assert_eq!(
policy.wake_deadline(),
None,
"the frames after a burst bring no wake for a tree already published"
);
}