diff --git a/packages/rsnap-overlay/src/overlay/tests.rs b/packages/rsnap-overlay/src/overlay/tests.rs index da5ae099..75c539a0 100644 --- a/packages/rsnap-overlay/src/overlay/tests.rs +++ b/packages/rsnap-overlay/src/overlay/tests.rs @@ -57,7 +57,7 @@ use crate::overlay::{ SELECTION_SIZE_BADGE_INSIDE_MARGIN_PX, SELECTION_SIZE_BADGE_SCREEN_MARGIN_PX, SelectionDashedBorderCache, SelectionDashedBorderMetrics, SelectionFlowGeometryCache, SelectionSizeBadgeTarget, SurfaceFrameSkipReason, TOOLBAR_CAPTURE_GAP_PX, - TOOLBAR_SCREEN_MARGIN_PX, ToolbarPlacement, Vec2, WindowRenderer, hud_helpers, regular, + TOOLBAR_SCREEN_MARGIN_PX, ToolbarPlacement, Vec2, WindowRenderer, hud_helpers, }; #[cfg(target_os = "macos")] use crate::overlay::{ @@ -1201,26 +1201,6 @@ fn downward_frame_motion_commits_even_with_legacy_upward_input_direction() { ); } -#[cfg(target_os = "macos")] -#[test] -fn positive_pixel_delta_maps_to_upward_scroll_capture() { - assert_eq!( - OverlaySession::scroll_capture_direction_from_wheel_delta(&MouseScrollDelta::PixelDelta( - PhysicalPosition::new(0.0, 2.0) - )), - Some(ScrollDirection::Up) - ); -} - -#[cfg(target_os = "macos")] -#[test] -fn macos_scroll_wheel_events_use_hid_system_source_state() { - assert_eq!( - super::macos_hid_event_source_state_id(), - super::KCG_EVENT_SOURCE_STATE_HID_SYSTEM_STATE - ); -} - #[cfg(target_os = "macos")] #[test] fn pixel_delta_residuals_accumulate_until_whole_pixels_emit() { @@ -1245,48 +1225,6 @@ fn pixel_delta_residuals_accumulate_until_whole_pixels_emit() { assert!((second.residual.y + 0.2).abs() < 1e-9); } -#[test] -fn frozen_toolbar_mode_tools_are_identifiable() { - assert!(FrozenToolbarTool::Pointer.is_mode_tool()); - assert!(FrozenToolbarTool::Pen.is_mode_tool()); - assert!(FrozenToolbarTool::Text.is_mode_tool()); - assert!(FrozenToolbarTool::Mosaic.is_mode_tool()); -} - -#[test] -fn frozen_toolbar_action_tools_are_not_mode_tools() { - assert!(!FrozenToolbarTool::Undo.is_mode_tool()); - assert!(!FrozenToolbarTool::Redo.is_mode_tool()); - assert!(!FrozenToolbarTool::AutoCenter.is_mode_tool()); - assert!(!FrozenToolbarTool::Scroll.is_mode_tool()); - assert!(!FrozenToolbarTool::Copy.is_mode_tool()); - assert!(!FrozenToolbarTool::Save.is_mode_tool()); - #[cfg(target_os = "macos")] - assert!(!FrozenToolbarTool::Ocr.is_mode_tool()); -} - -#[test] -fn frozen_toolbar_scroll_tool_uses_scroll_specific_iconography() { - assert_eq!(FrozenToolbarTool::Scroll.label(), "Scroll Capture"); - assert_eq!(FrozenToolbarTool::Scroll.icon(), regular::MOUSE_SCROLL); -} - -#[test] -fn frozen_toolbar_export_tools_require_final_capture() { - assert!(!FrozenToolbarTool::Pointer.requires_final_capture()); - assert!(!FrozenToolbarTool::Pen.requires_final_capture()); - assert!(!FrozenToolbarTool::Text.requires_final_capture()); - assert!(!FrozenToolbarTool::Mosaic.requires_final_capture()); - assert!(!FrozenToolbarTool::Undo.requires_final_capture()); - assert!(!FrozenToolbarTool::Redo.requires_final_capture()); - assert!(!FrozenToolbarTool::AutoCenter.requires_final_capture()); - assert!(FrozenToolbarTool::Scroll.requires_final_capture()); - assert!(FrozenToolbarTool::Copy.requires_final_capture()); - assert!(FrozenToolbarTool::Save.requires_final_capture()); - #[cfg(target_os = "macos")] - assert!(FrozenToolbarTool::Ocr.requires_final_capture()); -} - #[test] fn frozen_toolbar_selected_mode_uses_fill_without_border() { for theme in [HudTheme::Dark, HudTheme::Light] { diff --git a/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs b/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs index 5c2de2fb..1acb34a9 100644 --- a/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs +++ b/packages/rsnap-overlay/src/overlay/tests/rendering_behaviors.rs @@ -345,227 +345,6 @@ fn scroll_capture_and_export_wait_for_authoritative_frozen_capture() { assert_eq!(session.state.error_message.as_deref(), Some("Preparing capture...")); } -#[test] -fn frozen_selection_scrim_rects_frame_focus_rect_without_covering_it() { - let screen_rect = Rect::from_min_size(Pos2::ZERO, Vec2::new(100.0, 80.0)); - let focus_rect = Rect::from_min_size(Pos2::new(20.0, 10.0), Vec2::new(40.0, 30.0)); - let scrim_rects = WindowRenderer::frozen_selection_scrim_rects(screen_rect, focus_rect); - - assert_eq!( - scrim_rects, - [ - Rect::from_min_max(Pos2::new(0.0, 0.0), Pos2::new(100.0, 10.0)), - Rect::from_min_max(Pos2::new(0.0, 40.0), Pos2::new(100.0, 80.0)), - Rect::from_min_max(Pos2::new(0.0, 10.0), Pos2::new(20.0, 40.0)), - Rect::from_min_max(Pos2::new(60.0, 10.0), Pos2::new(100.0, 40.0)), - ] - ); - assert!(scrim_rects.into_iter().all(|rect| !rect.contains(focus_rect.center()))); -} - -#[test] -fn frozen_selection_scrim_rects_leave_zero_area_regions_at_screen_edges() { - let screen_rect = Rect::from_min_size(Pos2::ZERO, Vec2::new(100.0, 80.0)); - let focus_rect = Rect::from_min_size(Pos2::new(0.0, 10.0), Vec2::new(40.0, 30.0)); - let scrim_rects = WindowRenderer::frozen_selection_scrim_rects(screen_rect, focus_rect); - let non_empty = - scrim_rects.iter().filter(|rect| rect.width() > 0.0 && rect.height() > 0.0).count(); - - assert_eq!(scrim_rects[2].width(), 0.0); - assert_eq!(non_empty, 3); -} - -#[test] -fn frozen_selection_scrim_rects_are_empty_for_fullscreen_rect() { - let screen_rect = Rect::from_min_size(Pos2::ZERO, Vec2::new(100.0, 80.0)); - let scrim_rects = WindowRenderer::frozen_selection_scrim_rects(screen_rect, screen_rect); - - assert!(scrim_rects.into_iter().all(|rect| rect.width() <= 0.0 || rect.height() <= 0.0)); -} - -#[test] -fn selection_dashed_border_rect_is_absent_for_fullscreen_rect() { - let screen_rect = Rect::from_min_size(Pos2::ZERO, Vec2::new(100.0, 80.0)); - let border_outset = - WindowRenderer::selection_dashed_border_outset(SELECTION_DASHED_BORDER_WIDTH_PX, 1.0); - - assert_eq!( - WindowRenderer::selection_dashed_border_rect(screen_rect, screen_rect, border_outset,), - None - ); -} - -#[test] -fn selection_dashed_border_rect_expands_focus_rect_outward() { - let screen_rect = Rect::from_min_size(Pos2::ZERO, Vec2::new(100.0, 80.0)); - let focus_rect = Rect::from_min_size(Pos2::new(20.0, 10.0), Vec2::new(40.0, 30.0)); - let border_outset = - WindowRenderer::selection_dashed_border_outset(SELECTION_DASHED_BORDER_WIDTH_PX, 1.0); - - assert_eq!( - WindowRenderer::selection_dashed_border_rect(screen_rect, focus_rect, border_outset,), - Some(Rect::from_min_max(Pos2::new(18.5, 8.5), Pos2::new(61.5, 41.5),)) - ); -} - -#[test] -fn selection_dashed_border_rect_can_extend_beyond_screen_edge() { - let screen_rect = Rect::from_min_size(Pos2::ZERO, Vec2::new(100.0, 80.0)); - let focus_rect = Rect::from_min_size(Pos2::new(0.0, 10.0), Vec2::new(40.0, 30.0)); - let border_outset = - WindowRenderer::selection_dashed_border_outset(SELECTION_DASHED_BORDER_WIDTH_PX, 1.0); - - assert_eq!( - WindowRenderer::selection_dashed_border_rect(screen_rect, focus_rect, border_outset,), - Some(Rect::from_min_max(Pos2::new(-1.5, 8.5), Pos2::new(41.5, 41.5),)) - ); -} - -#[test] -fn selection_dashed_border_dash_ranges_distribute_remainder_evenly() { - const EPSILON: f32 = 1e-4; - - let rect = Rect::from_min_max(Pos2::new(18.5, 8.5), Pos2::new(61.5, 41.5)); - let perimeter = WindowRenderer::selection_dashed_border_perimeter(rect); - let ranges = WindowRenderer::selection_dashed_border_dash_ranges( - perimeter, - SELECTION_DASHED_BORDER_DASH_LENGTH_PX, - SELECTION_DASHED_BORDER_GAP_LENGTH_PX, - ); - - assert_eq!(ranges.len(), 15); - - let dash_length = ranges[0].1 - ranges[0].0; - let gap_length = ranges[1].0 - ranges[0].1; - - assert!((dash_length - SELECTION_DASHED_BORDER_DASH_LENGTH_PX).abs() < EPSILON); - - for window in ranges.windows(2) { - let current_dash_length = window[0].1 - window[0].0; - let current_gap_length = window[1].0 - window[0].1; - - assert!((current_dash_length - dash_length).abs() < EPSILON); - assert!((current_gap_length - gap_length).abs() < EPSILON); - } - - let seam_gap_length = perimeter - ranges.last().unwrap().1 + ranges[0].0; - - assert!((seam_gap_length - gap_length).abs() < EPSILON); -} - -#[test] -fn selection_dashed_border_segments_split_at_square_corners() { - let rect = Rect::from_min_max(Pos2::new(18.5, 8.5), Pos2::new(38.5, 18.5)); - - assert_eq!( - WindowRenderer::selection_dashed_border_segments(rect, 25.0, 5.0), - vec![ - [Pos2::new(18.5, 8.5), Pos2::new(38.5, 8.5)], - [Pos2::new(38.5, 8.5), Pos2::new(38.5, 13.5)], - [Pos2::new(38.5, 18.5), Pos2::new(18.5, 18.5)], - [Pos2::new(18.5, 18.5), Pos2::new(18.5, 13.5)], - ] - ); -} - -#[test] -fn selection_dashed_border_cache_reuses_geometry_for_same_rect() { - let rect = Rect::from_min_max(Pos2::new(18.5, 8.5), Pos2::new(61.5, 41.5)); - let other_rect = Rect::from_min_max(Pos2::new(18.5, 8.5), Pos2::new(41.5, 41.5)); - let sentinel = [Pos2::new(-1.0, -1.0), Pos2::new(-2.0, -2.0)]; - let mut cache = SelectionDashedBorderCache::default(); - let initial = WindowRenderer::selection_dashed_border_cached_segments( - &mut cache, - rect, - SELECTION_DASHED_BORDER_DASH_LENGTH_PX, - SELECTION_DASHED_BORDER_GAP_LENGTH_PX, - ) - .to_vec(); - - assert!(!initial.is_empty()); - - cache.segments[0] = sentinel; - - let cached = WindowRenderer::selection_dashed_border_cached_segments( - &mut cache, - rect, - SELECTION_DASHED_BORDER_DASH_LENGTH_PX, - SELECTION_DASHED_BORDER_GAP_LENGTH_PX, - ); - - assert_eq!(cached[0], sentinel); - - let rebuilt = WindowRenderer::selection_dashed_border_cached_segments( - &mut cache, - other_rect, - SELECTION_DASHED_BORDER_DASH_LENGTH_PX, - SELECTION_DASHED_BORDER_GAP_LENGTH_PX, - ); - - assert_ne!(rebuilt[0], sentinel); -} - -#[test] -fn selection_dashed_border_outset_accounts_for_feathering() { - assert_eq!( - WindowRenderer::selection_dashed_border_outset(SELECTION_DASHED_BORDER_WIDTH_PX, 1.0), - 1.5 - ); - assert_eq!( - WindowRenderer::selection_dashed_border_outset(SELECTION_DASHED_BORDER_WIDTH_PX, 2.0), - 1.25 - ); -} - -#[test] -fn selection_dashed_border_metrics_track_physical_pixels() { - assert_eq!( - WindowRenderer::selection_dashed_border_metrics(1.0), - SelectionDashedBorderMetrics { stroke_width: 2.0, dash_length: 6.0, gap_length: 4.0 } - ); - assert_eq!( - WindowRenderer::selection_dashed_border_metrics(2.0), - SelectionDashedBorderMetrics { stroke_width: 1.0, dash_length: 3.0, gap_length: 2.0 } - ); - assert_eq!( - WindowRenderer::selection_dashed_border_metrics(1.5), - SelectionDashedBorderMetrics { - stroke_width: 2.0 / 1.5, - dash_length: 6.0 / 1.5, - gap_length: 4.0 / 1.5, - } - ); -} - -#[test] -fn frozen_selection_scrim_is_stronger_than_live_drag_scrim_in_light_theme() { - let frozen_scrim = WindowRenderer::frozen_selection_scrim_color(HudTheme::Light); - let drag_scrim = WindowRenderer::live_drag_selection_scrim_color(HudTheme::Light); - - assert!(frozen_scrim.a() > drag_scrim.a()); -} - -#[test] -fn selection_flow_palette_tracks_hud_theme() { - assert_eq!( - WindowRenderer::selection_flow_palette(HudTheme::Dark), - &crate::overlay::SELECTION_FLOW_PALETTE - ); - assert_eq!( - WindowRenderer::selection_flow_palette(HudTheme::Light), - &crate::overlay::SELECTION_FLOW_LIGHT_PALETTE - ); -} - -#[test] -fn selection_flow_color_can_share_theme_rgb() { - let dark = WindowRenderer::selection_flow_color(0.17, HudTheme::Dark, 0.4, 1.0); - let light = WindowRenderer::selection_flow_color(0.17, HudTheme::Light, 0.4, 1.0); - - assert_eq!((dark.r(), dark.g(), dark.b()), (light.r(), light.g(), light.b())); - assert_eq!(dark.a(), light.a()); -} - #[test] fn frozen_toolbar_default_position_fits_below_capture_rect() { let monitor = Rect::from_min_size(Pos2::ZERO, Vec2::new(800.0, 600.0)); diff --git a/packages/rsnap-overlay/src/scroll_capture/tests.rs b/packages/rsnap-overlay/src/scroll_capture/tests.rs index 0a217593..5a6d00cd 100644 --- a/packages/rsnap-overlay/src/scroll_capture/tests.rs +++ b/packages/rsnap-overlay/src/scroll_capture/tests.rs @@ -2,10 +2,10 @@ use image::Rgba; use crate::scroll_capture::support; use crate::scroll_capture::{ - self, DirectionMatch, DownwardRegistration, DownwardSampleMatch, DownwardSampleMatchSource, - DownwardViewportCandidate, DownwardViewportCandidateSource, DownwardViewportResolution, - MotionObservation, OverlapSearchConfig, PreviewOnlyDownwardLocalSample, ScrollDirection, - ScrollFrameFingerprint, ScrollObserveOutcome, ScrollSession, + self, DirectionMatch, DownwardRegistration, DownwardViewportCandidate, + DownwardViewportCandidateSource, DownwardViewportResolution, MotionObservation, + OverlapSearchConfig, PreviewOnlyDownwardLocalSample, ScrollDirection, ScrollFrameFingerprint, + ScrollObserveOutcome, ScrollSession, }; fn make_test_image(width: u32, rows: &[[u8; 4]]) -> image::RgbaImage { @@ -1286,1591 +1286,6 @@ fn nearby_local_candidate_wins_when_committed_is_only_modestly_better() { ); } -#[test] -fn burst_observed_sample_candidate_is_suppressed_when_it_far_exceeds_local_continuity_budget() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 14; - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(1_219); - session.transient_burst_search_enabled = true; - - assert!(session.should_suppress_observed_sample_candidate(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 419, - motion_rows: 413, - mean_abs_diff_x100: 0, - })); -} - -#[test] -fn burst_observed_sample_candidate_is_kept_when_it_stays_within_local_continuity_budget() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 14; - session.last_motion_rows_hint = Some(9); - session.transient_motion_rows_hint = Some(74); - session.transient_burst_search_enabled = true; - - assert!(!session.should_suppress_observed_sample_candidate(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 30, - motion_rows: 16, - mean_abs_diff_x100: 0, - })); -} - -#[test] -fn burst_observed_sample_candidate_near_recent_continuity_can_exceed_budget_without_suppression() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 130; - session.last_motion_rows_hint = Some(38); - session.transient_motion_rows_hint = Some(1_150); - session.transient_burst_search_enabled = true; - - assert!(!session.should_suppress_observed_sample_candidate(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 162, - motion_rows: 32, - mean_abs_diff_x100: 533, - })); -} - -#[test] -fn burst_observed_sample_candidate_near_recent_continuity_still_suppresses_when_diff_is_too_high() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 14; - session.last_motion_rows_hint = Some(9); - session.transient_motion_rows_hint = Some(1_219); - session.transient_burst_search_enabled = true; - - assert!(session.should_suppress_observed_sample_candidate(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 31, - motion_rows: 17, - mean_abs_diff_x100: 733, - })); -} - -#[test] -fn corroborated_observed_candidate_can_recover_after_initial_continuity_suppression() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 149; - session.last_motion_rows_hint = Some(16); - session.transient_motion_rows_hint = Some(12); - session.transient_burst_search_enabled = true; - - let candidate = DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 169, - motion_rows: 20, - mean_abs_diff_x100: 0, - }; - let mut candidates = vec![DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 169, - motion_rows: 20, - mean_abs_diff_x100: 0, - }]; - - assert!(session.should_suppress_observed_sample_candidate(candidate)); - - session.restore_corroborated_observed_candidate(Some(candidate), &mut candidates); - - assert!(candidates.contains(&candidate)); -} - -#[test] -fn tiny_observed_recovery_fails_closed_during_large_transient_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 261; - session.last_motion_rows_hint = Some(24); - session.transient_motion_rows_hint = Some(86); - session.transient_burst_search_enabled = true; - - assert!(session.should_fail_closed_tiny_observed_recovery_in_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 263, - motion_rows: 2, - mean_abs_diff_x100: 0, - } - )); -} - -#[test] -fn tiny_observed_recovery_does_not_block_when_recent_continuity_is_small() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 14; - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(1_217); - session.transient_burst_search_enabled = true; - - assert!(!session.should_fail_closed_tiny_observed_recovery_in_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 15, - motion_rows: 1, - mean_abs_diff_x100: 0, - } - )); -} - -#[test] -fn outsized_observed_recovery_after_one_pixel_preview_local_commit_fails_closed() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 74; - session.last_motion_rows_hint = Some(1); - session.transient_motion_rows_hint = Some(277); - session.transient_burst_search_enabled = true; - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 74), - growth_rows: 1, - viewport_top_y: 74, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(1), - effective_motion_rows_hint: Some(277), - }); - - assert!( - session.should_fail_closed_outsized_observed_recovery_after_one_pixel_preview_local_commit( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 82, - motion_rows: 8, - mean_abs_diff_x100: 0, - }, - ) - ); -} - -#[test] -fn tiny_observed_burst_block_keeps_preview_local_baseline_stable() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 261; - session.observed_viewport_top_y = 261; - session.last_motion_rows_hint = Some(24); - session.transient_motion_rows_hint = Some(86); - session.transient_burst_search_enabled = true; - - session.refresh_preview_only_downward_local_sample( - &make_sparse_textlike_window(256, 120, 261), - session.stable_preview_only_downward_local_viewport_top_y(), - ); - - assert_eq!( - session - .last_preview_only_downward_local_sample - .as_ref() - .map(|sample| sample.viewport_top_y), - Some(261) - ); -} - -#[test] -fn tiny_preview_only_local_recovery_fails_closed_during_large_transient_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(7); - session.transient_motion_rows_hint = Some(167); - session.transient_burst_search_enabled = true; - - assert!(session.should_fail_closed_tiny_preview_only_local_recovery_in_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 303, - motion_rows: 1, - mean_abs_diff_x100: 232, - } - )); -} - -#[test] -fn tiny_preview_only_local_recovery_does_not_block_recorded_small_commit() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(1_217); - session.transient_burst_search_enabled = true; - - assert!(!session.should_fail_closed_tiny_preview_only_local_recovery_in_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 15, - motion_rows: 1, - mean_abs_diff_x100: 97, - } - )); -} - -#[test] -fn small_preview_only_local_recovery_lagging_recent_continuity_fails_closed_during_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(26); - session.transient_motion_rows_hint = Some(356); - session.transient_burst_search_enabled = true; - - assert!(session.should_fail_closed_tiny_preview_only_local_recovery_in_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 84, - motion_rows: 6, - mean_abs_diff_x100: 0, - } - )); -} - -#[test] -fn preview_only_local_tail_after_unresolved_burst_fails_closed() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 360; - session.last_block_reason = Some("no_downward_viewport_candidate_resolved"); - session.last_motion_rows_hint = Some(9); - session.transient_motion_rows_hint = Some(1_002); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 360), - viewport_top_y: 360, - }); - - assert!(session.should_fail_closed_preview_only_local_tail_after_unresolved_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 378, - motion_rows: 18, - mean_abs_diff_x100: 0, - } - )); -} - -#[test] -fn preview_only_local_tail_after_unresolved_burst_does_not_block_without_extreme_gap() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 360; - session.last_block_reason = Some("no_downward_viewport_candidate_resolved"); - session.last_motion_rows_hint = Some(9); - session.transient_motion_rows_hint = Some(18); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 360), - viewport_top_y: 360, - }); - - assert!(!session.should_fail_closed_preview_only_local_tail_after_unresolved_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 378, - motion_rows: 18, - mean_abs_diff_x100: 0, - } - )); -} - -#[test] -fn preview_only_local_tail_after_unresolved_burst_does_not_block_after_registered_growth_matches_pending_band() - { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 184; - session.last_block_reason = Some("no_downward_viewport_candidate_resolved"); - session.last_motion_rows_hint = Some(1); - session.transient_motion_rows_hint = Some(277); - session.transient_burst_search_enabled = true; - session.pending_unresolved_burst_registered_growth_viewport_top_y = Some(461); - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 184), - viewport_top_y: 184, - }); - - assert!(!session.should_fail_closed_preview_only_local_tail_after_unresolved_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 186, - motion_rows: 2, - mean_abs_diff_x100: 125, - } - )); -} - -#[test] -fn exactly_corroborated_preview_local_tail_fails_closed_in_extreme_transient_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(10); - session.transient_motion_rows_hint = Some(1_057); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(20); - session.last_downward_viewport_candidates_before_prune = - Some("PreviewOnlyLocalSample@472/20:0,CommittedKeyframe@472/20:0".to_string()); - - for (viewport_top_y, growth_rows) in [(442_i32, 8_u32), (452_i32, 10_u32)] { - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, u32::try_from(viewport_top_y).unwrap()), - growth_rows, - viewport_top_y, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample - .decision_source(), - detected_motion_rows: Some(growth_rows), - effective_motion_rows_hint: Some(1_057), - }); - } - - assert!(session.should_fail_closed_exactly_corroborated_preview_local_tail_in_extreme_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 472, - motion_rows: 20, - mean_abs_diff_x100: 0, - }, - )); -} - -#[test] -fn moderate_transient_preview_local_tail_is_not_blocked_by_extreme_burst_rule() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(20); - session.transient_motion_rows_hint = Some(110); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(24); - session.last_downward_viewport_candidates_before_prune = - Some("PreviewOnlyLocalSample@261/24:329,CommittedKeyframe@512/275:460".to_string()); - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 237), - growth_rows: 20, - viewport_top_y: 237, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(20), - effective_motion_rows_hint: Some(110), - }); - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 217), - growth_rows: 18, - viewport_top_y: 217, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(18), - effective_motion_rows_hint: Some(104), - }); - - assert!(!session.should_fail_closed_exactly_corroborated_preview_local_tail_in_extreme_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 261, - motion_rows: 24, - mean_abs_diff_x100: 329, - }, - )); -} - -#[test] -fn burst_prefers_observed_sample_over_underconsumed_preview_only_local_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(38); - session.transient_motion_rows_hint = Some(1_150); - session.transient_burst_search_enabled = true; - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 120, motion_rows: 32 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 8 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!(session.should_prefer_observed_sample_over_preview_only_local_recovery(primary, local)); -} - -#[test] -fn burst_keeps_preview_only_local_recovery_when_observed_is_only_modestly_ahead() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(38); - session.transient_motion_rows_hint = Some(1_150); - session.transient_burst_search_enabled = true; - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 120, motion_rows: 16 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 8 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!( - !session.should_prefer_observed_sample_over_preview_only_local_recovery(primary, local) - ); -} - -#[test] -fn tiny_recent_continuity_burst_prefers_preview_local_over_far_ahead_observed_sample() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(225); - session.transient_burst_search_enabled = true; - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 12 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 405, motion_rows: 3 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!(session.should_prefer_preview_only_local_recovery_over_observed_sample(primary, local)); -} - -#[test] -fn tiny_recent_continuity_burst_does_not_force_preview_local_when_observed_is_still_nearby() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(225); - session.transient_burst_search_enabled = true; - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 6 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 405, motion_rows: 3 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!( - !session.should_prefer_preview_only_local_recovery_over_observed_sample(primary, local) - ); -} - -#[test] -fn tiny_recent_continuity_burst_does_not_force_one_pixel_preview_local_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(1_211); - session.transient_burst_search_enabled = true; - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 553, motion_rows: 413 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 97, motion_rows: 1 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!( - !session.should_prefer_preview_only_local_recovery_over_observed_sample(primary, local) - ); -} - -#[test] -fn repeated_missing_burst_frames_can_prefer_one_pixel_preview_local_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(277); - session.transient_burst_search_enabled = true; - session.consecutive_transient_burst_missing_downward_candidate_frames = 2; - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 116 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 149, motion_rows: 1 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!(session.should_prefer_preview_only_local_recovery_over_observed_sample(primary, local)); -} - -#[test] -fn preview_local_slowdown_followup_can_prefer_one_pixel_preview_local_recovery() { - let previous = make_sparse_textlike_window(256, 120, 16); - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(4); - session.transient_motion_rows_hint = Some(29); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = - Some(PreviewOnlyDownwardLocalSample { frame: previous.clone(), viewport_top_y: 145 }); - - session.growth_history.push(crate::scroll_capture::GrowthCommit { - frame: previous, - growth_rows: 4, - viewport_top_y: 145, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(4), - effective_motion_rows_hint: Some(8), - }); - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 41 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 410, motion_rows: 1 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!(session.should_prefer_preview_only_local_recovery_over_observed_sample(primary, local)); -} - -#[test] -fn preview_local_slowdown_followup_can_prefer_near_continuity_preview_local_recovery() { - let previous = make_sparse_textlike_window(256, 120, 16); - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(10); - session.transient_motion_rows_hint = Some(1_150); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = - Some(PreviewOnlyDownwardLocalSample { frame: previous.clone(), viewport_top_y: 416 }); - - session.growth_history.push(crate::scroll_capture::GrowthCommit { - frame: previous, - growth_rows: 10, - viewport_top_y: 416, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(10), - effective_motion_rows_hint: Some(10), - }); - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 158 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 697, motion_rows: 12 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!(session.should_prefer_preview_only_local_recovery_over_observed_sample(primary, local)); -} - -#[test] -fn preview_local_slowdown_followup_without_recent_small_preview_commit_does_not_prefer_local() { - let previous = make_sparse_textlike_window(256, 120, 16); - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(4); - session.transient_motion_rows_hint = Some(29); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = - Some(PreviewOnlyDownwardLocalSample { frame: previous.clone(), viewport_top_y: 145 }); - - session.growth_history.push(crate::scroll_capture::GrowthCommit { - frame: previous, - growth_rows: 12, - viewport_top_y: 145, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(12), - effective_motion_rows_hint: Some(12), - }); - - let primary = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 41 }, - source: DownwardSampleMatchSource::ObservedSample, - }; - let local = DownwardSampleMatch { - matched: DirectionMatch { mean_abs_diff_x100: 410, motion_rows: 1 }, - source: DownwardSampleMatchSource::PreviewOnlyLocalSample, - }; - - assert!( - !session.should_prefer_preview_only_local_recovery_over_observed_sample(primary, local) - ); -} - -#[test] -fn observed_burst_catch_up_commit_seeds_preview_local_baseline() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_motion_rows_hint = Some(1_150); - session.transient_burst_search_enabled = true; - - assert!(session.should_seed_preview_only_local_after_observed_burst_commit( - "sample_motion_downward_growth_from_observed_keyframe", - 32, - Some(38), - )); -} - -#[test] -fn non_observed_or_non_catch_up_commit_does_not_seed_preview_local_baseline() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_motion_rows_hint = Some(1_150); - session.transient_burst_search_enabled = true; - - assert!(!session.should_seed_preview_only_local_after_observed_burst_commit( - "sample_motion_downward_growth_from_committed_keyframe", - 32, - Some(38), - )); - assert!(!session.should_seed_preview_only_local_after_observed_burst_commit( - "sample_motion_downward_growth_from_observed_keyframe", - 38, - Some(38), - )); -} - -#[test] -fn preview_local_burst_commit_preserves_local_baseline_for_next_frame() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_motion_rows_hint = Some(226); - session.transient_burst_search_enabled = true; - - assert!(session.should_preserve_preview_only_local_after_preview_only_burst_commit( - "sample_motion_downward_growth_from_preview_only_local_sample", - 18, - Some(12), - )); -} - -#[test] -fn preview_local_burst_commit_does_not_preserve_local_baseline_for_tiny_or_far_growth() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_motion_rows_hint = Some(226); - session.transient_burst_search_enabled = true; - - assert!(!session.should_preserve_preview_only_local_after_preview_only_burst_commit( - "sample_motion_downward_growth_from_preview_only_local_sample", - 1, - Some(12), - )); - assert!(!session.should_preserve_preview_only_local_after_preview_only_burst_commit( - "sample_motion_downward_growth_from_preview_only_local_sample", - 36, - Some(12), - )); -} - -#[test] -fn preview_local_non_burst_small_slowdown_preserves_local_baseline_for_next_frame() { - let session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - assert!(session.should_preserve_preview_only_local_after_preview_only_burst_commit( - "sample_motion_downward_growth_from_preview_only_local_sample", - 4, - Some(8), - )); -} - -#[test] -fn preview_local_non_burst_tiny_or_growing_commit_does_not_preserve_local_baseline() { - let session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - assert!(!session.should_preserve_preview_only_local_after_preview_only_burst_commit( - "sample_motion_downward_growth_from_preview_only_local_sample", - 1, - Some(8), - )); - assert!(!session.should_preserve_preview_only_local_after_preview_only_burst_commit( - "sample_motion_downward_growth_from_preview_only_local_sample", - 10, - Some(8), - )); -} - -#[test] -fn corroborated_huge_local_jump_after_preview_local_commit_blocks_far_committed_only_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 230; - session.last_motion_rows_hint = Some(18); - session.transient_motion_rows_hint = Some(226); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(164); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(164); - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 230), - growth_rows: 18, - viewport_top_y: 230, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(18), - effective_motion_rows_hint: Some(226), - }); - - assert!( - session.should_fail_closed_far_committed_only_recovery_after_corroborated_huge_local_jump( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }, - 164, - ) - ); -} - -#[test] -fn materially_smaller_observed_motion_still_blocks_huge_committed_only_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 230; - session.last_motion_rows_hint = Some(18); - session.transient_motion_rows_hint = Some(282); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(112); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(276); - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 230), - growth_rows: 18, - viewport_top_y: 230, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(18), - effective_motion_rows_hint: Some(282), - }); - - assert!( - session.should_fail_closed_far_committed_only_recovery_after_corroborated_huge_local_jump( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 506, - motion_rows: 276, - mean_abs_diff_x100: 0, - }, - 276, - ) - ); -} - -#[test] -fn nearby_committed_recovery_is_not_blocked_when_local_jump_is_not_huge() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 230; - session.last_motion_rows_hint = Some(18); - session.transient_motion_rows_hint = Some(226); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(38); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(38); - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 230), - growth_rows: 18, - viewport_top_y: 230, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(18), - effective_motion_rows_hint: Some(226), - }); - - assert!( - !session.should_fail_closed_far_committed_only_recovery_after_corroborated_huge_local_jump( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 268, - motion_rows: 38, - mean_abs_diff_x100: 0, - }, - 38, - ) - ); -} - -#[test] -fn suppressed_huge_preview_local_jump_corroborated_by_observed_and_committed_fails_closed() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 230; - session.last_motion_rows_hint = Some(18); - session.transient_motion_rows_hint = Some(226); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(164); - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 230), - growth_rows: 18, - viewport_top_y: 230, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(18), - effective_motion_rows_hint: Some(226), - }); - - assert!( - session - .should_fail_closed_suppressed_huge_preview_local_jump_corroborated_by_observed_and_committed( - Some(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }), - &[DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }], - ) - ); -} - -#[test] -fn suppressed_preview_local_jump_without_exact_committed_corroboration_stays_unblocked() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 230; - session.last_motion_rows_hint = Some(18); - session.transient_motion_rows_hint = Some(226); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(164); - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 230), - growth_rows: 18, - viewport_top_y: 230, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(18), - effective_motion_rows_hint: Some(226), - }); - - assert!( - !session - .should_fail_closed_suppressed_huge_preview_local_jump_corroborated_by_observed_and_committed( - Some(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }), - &[DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 398, - motion_rows: 186, - mean_abs_diff_x100: 0, - }], - ) - ); -} - -#[test] -fn committed_followup_after_suppressed_huge_preview_local_jump_fails_closed() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_burst_search_enabled = true; - session.last_preview_only_local_registration_result = Some("no_match"); - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(164); - - assert!( - session.should_fail_closed_committed_followup_after_suppressed_huge_preview_local_jump( - Some(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }), - &[ - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 398, - motion_rows: 186, - mean_abs_diff_x100: 0, - }, - ], - ) - ); -} - -#[test] -fn committed_followup_without_pending_suppressed_preview_local_jump_stays_unblocked() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_burst_search_enabled = true; - session.last_preview_only_local_registration_result = Some("no_match"); - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(164); - - assert!( - !session.should_fail_closed_committed_followup_after_suppressed_huge_preview_local_jump( - None, - &[DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }], - ) - ); -} - -#[test] -fn committed_followup_after_extreme_preview_local_tail_block_fails_closed() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_burst_search_enabled = true; - - assert!(session.should_fail_closed_committed_followup_after_extreme_preview_local_tail_block( - Some(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 472, - motion_rows: 20, - mean_abs_diff_x100: 0, - }), - &[ - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 472, - motion_rows: 20, - mean_abs_diff_x100: 0, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 472, - motion_rows: 30, - mean_abs_diff_x100: 0, - }, - ], - )); -} - -#[test] -fn committed_followup_after_extreme_preview_local_tail_block_ignores_non_exact_match() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.transient_burst_search_enabled = true; - - assert!(!session.should_fail_closed_committed_followup_after_extreme_preview_local_tail_block( - Some(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 472, - motion_rows: 20, - mean_abs_diff_x100: 0, - }), - &[DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 472, - motion_rows: 30, - mean_abs_diff_x100: 0, - }], - )); -} - -#[test] -fn suppressed_huge_preview_local_followup_block_budget_scales_with_far_recovery_ratio() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(18); - - assert_eq!( - session.suppressed_huge_preview_only_local_followup_block_budget(Some( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }, - )), - 5 - ); - assert_eq!( - session.suppressed_huge_preview_only_local_followup_block_budget(Some( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 290, - motion_rows: 42, - mean_abs_diff_x100: 0, - }, - )), - 3 - ); -} - -#[test] -fn huge_suppressed_jump_window_refreshes_observed_baseline_without_advancing_viewport() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - assert!(!session.should_refresh_downward_observed_baseline_after_huge_suppressed_jump()); - - session.pending_suppressed_huge_preview_only_local_followup = Some(DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 394, - motion_rows: 164, - mean_abs_diff_x100: 0, - }); - - assert!(session.should_refresh_downward_observed_baseline_after_huge_suppressed_jump()); - - session.pending_suppressed_huge_preview_only_local_followup = None; - session.blocked_followup_after_suppressed_huge_preview_local_jump = true; - - assert!(session.should_refresh_downward_observed_baseline_after_huge_suppressed_jump()); - - session.blocked_followup_after_suppressed_huge_preview_local_jump = false; - session.blocked_far_committed_only_recovery_after_corroborated_huge_local_jump = true; - - assert!(session.should_refresh_downward_observed_baseline_after_huge_suppressed_jump()); -} - -#[test] -fn huge_far_committed_block_resets_preview_only_local_baseline() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.refresh_preview_only_downward_local_sample( - &make_sparse_textlike_window(256, 120, 32), - Some(32), - ); - - assert!(session.last_preview_only_downward_local_sample.is_some()); - assert!(!session.should_reset_preview_only_local_baseline_after_huge_far_committed_block()); - - session.blocked_far_committed_only_recovery_after_corroborated_huge_local_jump = true; - - assert!(session.should_reset_preview_only_local_baseline_after_huge_far_committed_block()); -} - -#[test] -fn seeded_preview_only_local_catch_up_candidate_can_commit_small_tail_growth() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 162; - session.seeded_preview_only_local_after_observed_burst_commit = true; - - assert!(session.seeded_preview_only_local_catch_up_candidate_can_commit( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 170, - motion_rows: 8, - mean_abs_diff_x100: 0, - } - )); -} - -#[test] -fn unseeded_preview_only_local_candidate_still_needs_normal_burst_rules() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 162; - - assert!(!session.seeded_preview_only_local_catch_up_candidate_can_commit( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::PreviewOnlyLocalSample, - viewport_top_y: 170, - motion_rows: 8, - mean_abs_diff_x100: 0, - } - )); -} - -#[test] -fn seeded_preview_only_local_recovery_range_includes_one_pixel_tail_growth() { - let previous = make_sparse_textlike_window(256, 120, 0); - let next = make_sparse_textlike_window(256, 120, 1); - let mut session = ScrollSession::new(previous.clone(), 320).unwrap(); - - session.last_motion_rows_hint = Some(4); - session.seeded_preview_only_local_after_observed_burst_commit = true; - - let range = session - .preview_only_local_recovery_motion_range(&previous, &next, OverlapSearchConfig::default()) - .unwrap(); - - assert_eq!(*range.start(), 1); - assert_eq!(*range.end(), 6); -} - -#[test] -fn unseeded_preview_only_local_recovery_range_keeps_hint_floor() { - let previous = make_sparse_textlike_window(256, 120, 0); - let next = make_sparse_textlike_window(256, 120, 1); - let mut session = ScrollSession::new(previous.clone(), 320).unwrap(); - - session.last_motion_rows_hint = Some(4); - - let range = session - .preview_only_local_recovery_motion_range(&previous, &next, OverlapSearchConfig::default()) - .unwrap(); - - assert_eq!(*range.start(), 2); - assert_eq!(*range.end(), 6); -} - -#[test] -fn preview_local_slowdown_followup_range_allows_one_pixel_tail_in_burst() { - let previous = make_sparse_textlike_window(256, 120, 16); - let next = make_sparse_textlike_window(256, 120, 17); - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(4); - session.transient_motion_rows_hint = Some(29); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = - Some(PreviewOnlyDownwardLocalSample { frame: previous.clone(), viewport_top_y: 145 }); - - session.growth_history.push(crate::scroll_capture::GrowthCommit { - frame: previous.clone(), - growth_rows: 4, - viewport_top_y: 145, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(4), - effective_motion_rows_hint: Some(8), - }); - - let range = session - .preview_only_local_recovery_motion_range(&previous, &next, OverlapSearchConfig::default()) - .unwrap(); - - assert_eq!(*range.start(), 1); - assert_eq!(*range.end(), 6); -} - -#[test] -fn preview_local_followup_without_recent_small_preview_commit_keeps_hint_floor_in_burst() { - let previous = make_sparse_textlike_window(256, 120, 16); - let next = make_sparse_textlike_window(256, 120, 17); - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(4); - session.transient_motion_rows_hint = Some(29); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = - Some(PreviewOnlyDownwardLocalSample { frame: previous.clone(), viewport_top_y: 145 }); - - session.growth_history.push(crate::scroll_capture::GrowthCommit { - frame: previous.clone(), - growth_rows: 12, - viewport_top_y: 145, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(12), - effective_motion_rows_hint: Some(12), - }); - - let range = session - .preview_only_local_recovery_motion_range(&previous, &next, OverlapSearchConfig::default()) - .unwrap(); - - assert_eq!(*range.start(), 2); - assert_eq!(*range.end(), 6); -} - -#[test] -fn tiny_committed_keyframe_recovery_fails_closed_during_large_transient_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 68; - session.last_motion_rows_hint = Some(6); - session.transient_motion_rows_hint = Some(401); - session.transient_burst_search_enabled = true; - - assert!(session.should_fail_closed_tiny_committed_keyframe_recovery_in_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 70, - motion_rows: 12, - mean_abs_diff_x100: 654, - } - )); -} - -#[test] -fn tiny_committed_keyframe_recovery_does_not_block_meaningful_growth_during_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 68; - session.last_motion_rows_hint = Some(6); - session.transient_motion_rows_hint = Some(401); - session.transient_burst_search_enabled = true; - - assert!(!session.should_fail_closed_tiny_committed_keyframe_recovery_in_burst( - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 81, - motion_rows: 23, - mean_abs_diff_x100: 696, - } - )); -} - -#[test] -fn underconsumed_observed_recovery_fails_closed_when_nearby_committed_candidate_reaches_recent_continuity() - { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(20); - session.transient_motion_rows_hint = Some(75); - session.transient_burst_search_enabled = true; - - let candidates_before_prune = vec![ - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 289, - motion_rows: 8, - mean_abs_diff_x100: 0, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 289, - motion_rows: 8, - mean_abs_diff_x100: 0, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 291, - motion_rows: 30, - mean_abs_diff_x100: 0, - }, - ]; - let candidates_after_prune = vec![ - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 289, - motion_rows: 8, - mean_abs_diff_x100: 0, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 289, - motion_rows: 8, - mean_abs_diff_x100: 0, - }, - ]; - - assert!(session.should_fail_closed_underconsumed_observed_recovery_in_burst( - &candidates_before_prune, - &candidates_after_prune, - )); -} - -#[test] -fn underconsumed_observed_recovery_does_not_block_small_recorded_burst_commit() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(4); - session.transient_motion_rows_hint = Some(466); - session.transient_burst_search_enabled = true; - - let candidates_before_prune = vec![ - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::ObservedSample, - viewport_top_y: 14, - motion_rows: 2, - mean_abs_diff_x100: 6, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 14, - motion_rows: 2, - mean_abs_diff_x100: 6, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 14, - motion_rows: 6, - mean_abs_diff_x100: 16, - }, - ]; - let candidates_after_prune = candidates_before_prune[..2].to_vec(); - - assert!(!session.should_fail_closed_underconsumed_observed_recovery_in_burst( - &candidates_before_prune, - &candidates_after_prune, - )); -} - -#[test] -fn low_confidence_committed_only_recovery_without_local_anchor_fails_closed_during_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 134; - session.last_motion_rows_hint = Some(43); - session.transient_motion_rows_hint = Some(1_142); - session.transient_burst_search_enabled = true; - - let candidates = vec![ - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 190, - motion_rows: 56, - mean_abs_diff_x100: 621, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 157, - motion_rows: 73, - mean_abs_diff_x100: 557, - }, - ]; - - assert!(session.should_fail_closed_far_committed_only_recovery_without_local_anchor( - candidates[1], - &candidates, - )); -} - -#[test] -fn small_continuity_preview_local_registration_blocks_larger_committed_only_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 62; - session.last_motion_rows_hint = Some(2); - session.transient_motion_rows_hint = Some(225); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 31), - viewport_top_y: 62, - }); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(3); - - let candidates = vec![ - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 74, - motion_rows: 12, - mean_abs_diff_x100: 0, - }, - DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 78, - motion_rows: 14, - mean_abs_diff_x100: 0, - }, - ]; - - assert!(session.should_fail_closed_far_committed_only_recovery_without_local_anchor( - candidates[0], - &candidates, - )); -} - -#[test] -fn suppressed_large_preview_local_registration_blocks_underconsumed_committed_only_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 202; - session.last_motion_rows_hint = Some(8); - session.transient_motion_rows_hint = Some(575); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 31), - viewport_top_y: 202, - }); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(272); - - let candidates = [DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 220, - motion_rows: 32, - mean_abs_diff_x100: 765, - }]; - - assert!( - session - .should_fail_closed_underconsumed_committed_only_recovery_after_suppressed_preview_local_match( - candidates[0], - session.growth_rows_for_candidate_viewport_top_y(candidates[0].viewport_top_y), - ) - ); -} - -#[test] -fn corroborated_sample_registrations_block_committed_only_recovery_without_viewport_anchor() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 237; - session.last_motion_rows_hint = Some(20); - session.transient_motion_rows_hint = Some(145); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 237), - viewport_top_y: 237, - }); - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(135); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(116); - - let preferred = DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 353, - motion_rows: 116, - mean_abs_diff_x100: 0, - }; - - assert!(session - .should_fail_closed_committed_only_recovery_after_corroborated_sample_registration_without_viewport_anchor( - preferred, - session.growth_rows_for_candidate_viewport_top_y(preferred.viewport_top_y), - )); -} - -#[test] -fn corroborated_sample_registrations_block_older_keyframe_recovery_by_growth_band() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 237; - session.last_motion_rows_hint = Some(20); - session.transient_motion_rows_hint = Some(249); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 237), - viewport_top_y: 237, - }); - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(258); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(180); - - let preferred = DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 464, - motion_rows: 271, - mean_abs_diff_x100: 700, - }; - - assert!(session - .should_fail_closed_committed_only_recovery_after_corroborated_sample_registration_without_viewport_anchor( - preferred, - session.growth_rows_for_candidate_viewport_top_y(preferred.viewport_top_y), - )); -} - -#[test] -fn observed_burst_outpacing_recent_preview_local_commit_blocks_committed_only_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 237; - session.last_motion_rows_hint = Some(20); - session.transient_motion_rows_hint = Some(145); - session.transient_burst_search_enabled = true; - session.last_observed_sample_registration_result = Some("matched"); - session.last_observed_sample_registration_motion_rows = Some(135); - session.last_preview_only_local_registration_result = Some("no_match"); - - session.growth_history.push(super::GrowthCommit { - frame: make_sparse_textlike_window(256, 120, 237), - growth_rows: 20, - viewport_top_y: 237, - decision_source: DownwardViewportCandidateSource::PreviewOnlyLocalSample.decision_source(), - detected_motion_rows: Some(20), - effective_motion_rows_hint: Some(145), - }); - - let preferred = DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 353, - motion_rows: 116, - mean_abs_diff_x100: 0, - }; - - assert!(session - .should_fail_closed_committed_only_recovery_when_observed_burst_outpaces_recent_preview_local_commit( - preferred, - session.growth_rows_for_candidate_viewport_top_y(preferred.viewport_top_y), - )); -} - -#[test] -fn suppressed_large_preview_local_registration_helper_skips_hint_band_committed_recovery() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.current_viewport_top_y = 202; - session.last_motion_rows_hint = Some(8); - session.transient_motion_rows_hint = Some(575); - session.transient_burst_search_enabled = true; - session.last_preview_only_downward_local_sample = Some(PreviewOnlyDownwardLocalSample { - frame: make_sparse_textlike_window(256, 120, 31), - viewport_top_y: 202, - }); - session.last_preview_only_local_registration_result = Some("matched"); - session.last_preview_only_local_registration_motion_rows = Some(272); - - let candidates = [DownwardViewportCandidate { - source: DownwardViewportCandidateSource::CommittedKeyframe, - viewport_top_y: 500, - motion_rows: 310, - mean_abs_diff_x100: 0, - }]; - - assert!( - !session - .should_fail_closed_underconsumed_committed_only_recovery_after_suppressed_preview_local_match( - candidates[0], - session.growth_rows_for_candidate_viewport_top_y(candidates[0].viewport_top_y), - ) - ); -} - -#[test] -fn weak_tiny_committed_keyframe_match_retries_full_range_during_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(14); - session.transient_motion_rows_hint = Some(380); - session.transient_burst_search_enabled = true; - - assert!(session.should_retry_committed_keyframe_registration_across_full_range( - DownwardRegistration::Matched(DirectionMatch { mean_abs_diff_x100: 733, motion_rows: 7 }), - )); - assert_eq!( - session.prefer_full_range_committed_keyframe_registration( - DownwardRegistration::Matched(DirectionMatch { - mean_abs_diff_x100: 733, - motion_rows: 7, - }), - DownwardRegistration::Matched(DirectionMatch { - mean_abs_diff_x100: 0, - motion_rows: 50, - }), - ), - DownwardRegistration::Matched(DirectionMatch { mean_abs_diff_x100: 0, motion_rows: 50 }), - ); -} - -#[test] -fn modest_committed_keyframe_match_does_not_retry_full_range_during_burst() { - let mut session = ScrollSession::new(make_sparse_textlike_window(256, 120, 0), 320).unwrap(); - - session.last_motion_rows_hint = Some(9); - session.transient_motion_rows_hint = Some(1_284); - session.transient_burst_search_enabled = true; - - assert!(!session.should_retry_committed_keyframe_registration_across_full_range( - DownwardRegistration::Matched(DirectionMatch { mean_abs_diff_x100: 301, motion_rows: 27 }), - )); -} - #[test] fn session_preview_matches_export_after_downward_growth() { let document = [