#![allow(clippy::expect_used)]
use pdfrum::{Document, FormSession, Modifiers, Point};
fn document() -> Document {
Document::open("tests/fixtures/listbox_form.pdf").expect("the listbox fixture must open")
}
const X: f64 = 102.0;
const SINGLE_FIRST: f64 = 371.0;
const SINGLE_SECOND: f64 = 358.0;
const MULTI_FIRST: f64 = 423.0;
const INDICES_FIRST: f64 = 273.0;
const VALUES_FIRST: f64 = 223.0;
const MISMATCH_FIRST: f64 = 173.0;
const READ_ONLY_Y: f64 = 510.0;
fn click(session: &mut FormSession<'_>, y: f64) {
session.mouse_move(0, Point::new(X, y), Modifiers::NONE);
session.mouse_down(0, Point::new(X, y), Modifiers::NONE);
session.mouse_up(0, Point::new(X, y), Modifiers::NONE);
}
fn focus(session: &mut FormSession<'_>, y: f64) {
session.focus_at(0, Point::new(X, y), Modifiers::NONE);
}
fn selected_rows(session: &FormSession<'_>, count: usize) -> Vec<usize> {
(0..count)
.filter(|i| session.is_index_selected(*i))
.collect()
}
#[test]
fn a_value_array_selects_every_row_it_names() {
let doc = document();
let mut session = FormSession::new(&doc);
focus(&mut session, VALUES_FIRST);
assert!(
session.focused_annot().is_some(),
"the click must reach the field"
);
assert_eq!(selected_rows(&session, 5), vec![2, 4]);
}
#[test]
fn an_index_array_alone_selects_the_rows_it_names() {
let doc = document();
let mut session = FormSession::new(&doc);
focus(&mut session, INDICES_FIRST);
assert!(session.focused_annot().is_some());
assert_eq!(selected_rows(&session, 5), vec![1, 3]);
}
#[test]
fn the_value_array_wins_over_a_disagreeing_index_array() {
let doc = document();
let mut session = FormSession::new(&doc);
focus(&mut session, MISMATCH_FIRST);
assert!(session.focused_annot().is_some());
let rows = selected_rows(&session, 5);
assert_eq!(
rows,
vec![0, 2],
"/V [(Alligator) (Cougar)] wins over /I [1 3 4]"
);
}
#[test]
fn a_single_select_list_selects_the_first_visible_row_clicked() {
let doc = document();
let mut session = FormSession::new(&doc);
click(&mut session, SINGLE_FIRST);
assert!(session.focused_annot().is_some());
assert_eq!(selected_rows(&session, 26), vec![0]);
}
#[test]
fn clicking_the_second_visible_row_selects_the_second_option() {
let doc = document();
let mut session = FormSession::new(&doc);
click(&mut session, SINGLE_SECOND);
assert_eq!(selected_rows(&session, 26), vec![1]);
}
#[test]
fn a_row_is_the_laid_out_line_tall_not_the_font_size() {
let doc = document();
let mut boundaries = Vec::new();
let mut previous: Option<Vec<usize>> = None;
let mut y = 379.0_f64;
while y > 351.0 {
let mut session = FormSession::new(&doc);
click(&mut session, y);
let rows = selected_rows(&session, 26);
if previous.as_ref().is_some_and(|was| *was != rows) {
boundaries.push(y);
}
previous = Some(rows);
y -= 0.05;
}
assert_eq!(
boundaries.len(),
2,
"three rows fit, so there are two edges"
);
let step = boundaries[0] - boundaries[1];
assert!(
(step - 12.0).abs() > 0.5,
"a row is the laid-out line, not the 12-point size; measured {step}"
);
let client_top = 380.0 - 1.0; assert!(
((client_top - boundaries[0]) - step).abs() < 0.2,
"the first row starts at the client's top"
);
}
#[test]
fn a_multi_select_list_accumulates() {
let doc = document();
let mut session = FormSession::new(&doc);
click(&mut session, MULTI_FIRST);
assert!(session.focused_annot().is_some());
assert!(session.set_index_selected(0, true));
assert!(session.set_index_selected(2, true));
assert!(session.is_index_selected(0));
assert!(session.is_index_selected(2));
}
#[test]
fn a_read_only_list_never_takes_focus() {
let doc = document();
let mut session = FormSession::new(&doc);
click(&mut session, READ_ONLY_Y);
assert!(session.focused_annot().is_none());
}
#[test]
fn an_out_of_range_row_is_refused() {
let doc = document();
let mut session = FormSession::new(&doc);
click(&mut session, MULTI_FIRST);
assert!(!session.set_index_selected(100, true));
assert!(!session.is_index_selected(100));
assert!(!session.is_index_selected(usize::MAX));
}