laser_pdf/test_utils/
record_passes.rs1use std::cell::RefCell;
2
3use crate::*;
4
5#[derive(PartialEq, Debug)]
6pub struct Break {
7 pub page: usize,
8 pub layer: usize,
9 pub pos: (f32, f32),
10}
11
12#[derive(PartialEq, Debug)]
13pub struct BreakableDraw {
14 pub full_height: f32,
15 pub preferred_height_break_count: u32,
16 pub breaks: Vec<Break>,
17}
18
19#[derive(PartialEq, Debug)]
20pub enum Pass {
21 FirstLocationUsage {
22 width: WidthConstraint,
23 first_height: f32,
24 full_height: f32,
25 },
26 Measure {
27 width: WidthConstraint,
28 first_height: f32,
29
30 full_height: Option<f32>,
32 },
33 Draw(DrawPass),
34}
35
36#[derive(PartialEq, Debug)]
37pub struct DrawPass {
38 pub width: WidthConstraint,
39 pub first_height: f32,
40 pub preferred_height: Option<f32>,
41 pub page: usize,
42 pub layer: usize,
43 pub pos: (f32, f32),
44 pub breakable: Option<BreakableDraw>,
45}
46
47pub struct RecordPasses<E: Element> {
51 element: E,
52 passes: RefCell<Vec<Pass>>,
53}
54
55impl<E: Element> RecordPasses<E> {
56 pub fn new(element: E) -> Self {
57 RecordPasses {
58 element,
59 passes: RefCell::new(Vec::new()),
60 }
61 }
62
63 pub fn into_passes(self) -> Vec<Pass> {
64 self.passes.into_inner()
65 }
66
67 pub fn assert_draw(&self, pass: DrawPass) {
68 self.assert_draws(&[pass]);
69 }
70
71 pub fn assert_draws(&self, expected_draws: &[DrawPass]) {
72 let passes = self.passes.borrow();
73 let actual_draws: Vec<_> = passes
74 .iter()
75 .filter_map(|p| if let Pass::Draw(d) = p { Some(d) } else { None })
76 .collect();
77
78 assert!(
79 expected_draws.iter().eq(actual_draws.iter().map(|d| *d)),
80 "assertion `actual_draws == expected_draws` failed\nactual_draws: {:#?}\nexpected_draws: {:#?}",
81 actual_draws,
82 expected_draws,
83 );
84 }
85
86 pub fn assert_draw_count(&self, count: usize) {
87 let passes = self.passes.borrow();
88 let draw_passes = passes.iter().filter(|p| matches!(p, Pass::Draw { .. }));
89 assert_eq!(draw_passes.count(), count);
90 }
91
92 pub fn assert_measure_count(&self, count: usize) {
93 let passes = self.passes.borrow();
94 let measure_passes = passes.iter().filter(|p| matches!(p, Pass::Measure { .. }));
95 assert_eq!(measure_passes.count(), count);
96 }
97
98 pub fn assert_first_location_usage_count(&self, count: usize) {
99 let passes = self.passes.borrow();
100 let first_location_usage_passes = passes
101 .iter()
102 .filter(|p| matches!(p, Pass::FirstLocationUsage { .. }));
103 assert_eq!(first_location_usage_passes.count(), count);
104 }
105}
106
107impl<E: Element> Element for RecordPasses<E> {
108 fn first_location_usage(&self, ctx: FirstLocationUsageCtx) -> FirstLocationUsage {
109 self.passes.borrow_mut().push(Pass::FirstLocationUsage {
110 width: ctx.width,
111 first_height: ctx.first_height,
112 full_height: ctx.full_height,
113 });
114
115 self.element.first_location_usage(ctx)
116 }
117
118 fn measure(&self, ctx: MeasureCtx) -> ElementSize {
119 if let Some(ref b) = ctx.breakable {
120 assert_eq!(*b.break_count, 0);
121 assert_eq!(*b.extra_location_min_height, None);
122 }
123
124 self.passes.borrow_mut().push(Pass::Measure {
125 width: ctx.width,
126 first_height: ctx.first_height,
127 full_height: ctx.breakable.as_ref().map(|b| b.full_height),
128 });
129
130 self.element.measure(ctx)
131 }
132
133 fn draw(&self, ctx: DrawCtx) -> ElementSize {
134 let width = ctx.width;
135 let first_height = ctx.first_height;
136 let preferred_height = ctx.preferred_height;
137
138 let page = ctx.location.page_idx;
139 let layer = ctx.location.layer_idx;
140 let pos = ctx.location.pos;
141
142 let result;
143
144 let breakable = if let Some(breakable) = ctx.breakable {
145 let full_height = breakable.full_height;
146 let preferred_height_break_count = breakable.preferred_height_break_count;
147
148 let mut breaks = Vec::new();
149
150 result = self.element.draw(DrawCtx {
151 breakable: Some(crate::BreakableDraw {
152 do_break: &mut |pdf, location_idx, height| {
153 let location = (breakable.do_break)(pdf, location_idx, height);
154
155 breaks.push(Break {
156 page: location.page_idx,
157 layer: location.layer_idx,
158 pos: location.pos,
159 });
160
161 location
162 },
163 ..breakable
164 }),
165 ..ctx
166 });
167
168 Some(BreakableDraw {
169 full_height,
170 preferred_height_break_count,
171 breaks,
172 })
173 } else {
174 result = self.element.draw(ctx);
175 None
176 };
177
178 self.passes.borrow_mut().push(Pass::Draw(DrawPass {
179 width,
180 first_height,
181 preferred_height,
182 page,
183 layer,
184 pos,
185 breakable,
186 }));
187
188 result
189 }
190}