use super::flat_reading_order::{reading_order, CutConfig, OrderBox};
fn line(min_x: f64, bottom_y: f64, width: f64, font_size: f64) -> OrderBox {
OrderBox {
min_x,
max_x: min_x + width,
min_y: bottom_y,
max_y: bottom_y + font_size,
font_size,
}
}
fn cfg() -> CutConfig {
CutConfig {
horizontal_k: 1.0,
vertical_k: 1.5,
}
}
#[test]
fn two_columns_drawn_right_first_come_out_left_first() {
let boxes = vec![
line(350.0, 700.0, 100.0, 10.0), line(350.0, 680.0, 100.0, 10.0), line(50.0, 700.0, 100.0, 10.0), line(50.0, 680.0, 100.0, 10.0), ];
assert_eq!(reading_order(&boxes, &cfg()), vec![2, 3, 0, 1]);
}
#[test]
fn stacked_sections_drawn_bottom_first_come_out_top_first() {
let boxes = vec![
line(50.0, 100.0, 200.0, 10.0), line(50.0, 80.0, 200.0, 10.0), line(50.0, 700.0, 200.0, 10.0), line(50.0, 680.0, 200.0, 10.0), ];
assert_eq!(reading_order(&boxes, &cfg()), vec![2, 3, 0, 1]);
}
#[test]
fn output_is_always_a_permutation() {
let boxes = vec![
line(350.0, 700.0, 100.0, 10.0),
line(350.0, 300.0, 100.0, 10.0),
line(50.0, 700.0, 100.0, 10.0),
line(50.0, 300.0, 100.0, 10.0),
line(50.0, 690.0, 100.0, 10.0),
];
let order = reading_order(&boxes, &cfg());
let mut sorted = order.clone();
sorted.sort_unstable();
assert_eq!(sorted, (0..boxes.len()).collect::<Vec<_>>());
}
#[test]
fn single_column_in_reading_order_is_the_identity_permutation() {
let boxes = vec![
line(50.0, 700.0, 200.0, 10.0),
line(50.0, 686.0, 200.0, 10.0),
line(50.0, 672.0, 200.0, 10.0),
line(50.0, 658.0, 200.0, 10.0),
];
assert_eq!(reading_order(&boxes, &cfg()), vec![0, 1, 2, 3]);
}
#[test]
fn horizontal_threshold_degrades_on_both_sides() {
let boxes = vec![
line(190.0, 700.0, 20.0, 10.0), line(150.0, 700.0, 20.0, 10.0), ];
let split = CutConfig {
horizontal_k: 1.0,
vertical_k: 1.5,
};
let no_split = CutConfig {
horizontal_k: 3.0,
vertical_k: 1.5,
};
assert_eq!(
reading_order(&boxes, &split),
vec![1, 0],
"gutter 2x median glyph clears horizontal_k=1.0, so the columns split"
);
assert_eq!(
reading_order(&boxes, &no_split),
vec![0, 1],
"gutter 2x median glyph is below horizontal_k=3.0, so stream order stands"
);
}
#[test]
fn vertical_threshold_degrades_on_both_sides() {
let boxes = vec![
line(50.0, 640.0, 200.0, 10.0), line(50.0, 620.0, 200.0, 10.0), line(50.0, 700.0, 200.0, 10.0), ];
let split = CutConfig {
horizontal_k: 1.0,
vertical_k: 1.5,
};
let no_split = CutConfig {
horizontal_k: 1.0,
vertical_k: 6.0,
};
assert_eq!(
reading_order(&boxes, &split),
vec![2, 0, 1],
"section gap 4x median glyph clears vertical_k=1.5, so the blocks split"
);
assert_eq!(
reading_order(&boxes, &no_split),
vec![0, 1, 2],
"section gap 4x median glyph is below vertical_k=6.0, so stream order stands"
);
}
#[test]
fn adversarial_inputs_do_not_panic() {
assert_eq!(reading_order(&[], &cfg()), Vec::<usize>::new());
assert_eq!(
reading_order(&[line(0.0, 0.0, 10.0, 10.0)], &cfg()),
vec![0]
);
let coincident = vec![
line(10.0, 10.0, 5.0, 10.0),
line(10.0, 10.0, 5.0, 10.0),
line(10.0, 10.0, 5.0, 10.0),
];
assert_eq!(reading_order(&coincident, &cfg()), vec![0, 1, 2]);
let zero_font = vec![
OrderBox {
min_x: 300.0,
max_x: 400.0,
min_y: 0.0,
max_y: 0.0,
font_size: 0.0,
},
OrderBox {
min_x: 0.0,
max_x: 100.0,
min_y: 0.0,
max_y: 0.0,
font_size: 0.0,
},
];
assert_eq!(reading_order(&zero_font, &cfg()), vec![0, 1]);
let overlap = vec![line(0.0, 100.0, 300.0, 10.0), line(50.0, 98.0, 300.0, 10.0)];
let order = reading_order(&overlap, &cfg());
let mut sorted = order.clone();
sorted.sort_unstable();
assert_eq!(sorted, vec![0, 1]);
let nan = vec![
OrderBox {
min_x: f64::NAN,
max_x: f64::NAN,
min_y: 0.0,
max_y: 10.0,
font_size: 10.0,
},
line(0.0, 0.0, 10.0, 10.0),
];
let order = reading_order(&nan, &cfg());
let mut sorted = order.clone();
sorted.sort_unstable();
assert_eq!(sorted, vec![0, 1]);
}
#[test]
fn inverted_boxes_do_not_recurse_forever() {
let inverted_x = vec![
line(0.0, 0.0, 10.0, 10.0),
OrderBox {
min_x: 1000.0,
max_x: -1000.0,
min_y: 0.0,
max_y: 10.0,
font_size: 10.0,
},
];
let mut sorted = reading_order(&inverted_x, &cfg());
sorted.sort_unstable();
assert_eq!(sorted, vec![0, 1]);
let inverted_y = vec![
line(0.0, 0.0, 10.0, 10.0),
OrderBox {
min_x: 0.0,
max_x: 10.0,
min_y: 1000.0,
max_y: -1000.0,
font_size: 10.0,
},
];
let mut sorted = reading_order(&inverted_y, &cfg());
sorted.sort_unstable();
assert_eq!(sorted, vec![0, 1]);
}