Commit | Line | Data |
456a815d |
1 | use strict; |
2 | use warnings FATAL => 'all'; |
3 | use Test::More; |
4 | |
5 | use HTML::Zoom::Parser::BuiltIn; |
6 | use HTML::Zoom::Producer::BuiltIn; |
7 | use HTML::Zoom::SelectorParser; |
8 | use HTML::Zoom::FilterBuilder; |
9 | use HTML::Zoom::FilterStream; |
10 | |
11 | my $tmpl = <<END; |
12 | <body> |
13 | <div class="main"> |
14 | <span class="hilight name">Bob</span> |
15 | <span class="career">Builder</span> |
16 | <hr /> |
17 | </div> |
18 | </body> |
19 | END |
20 | |
d80786d0 |
21 | sub src_stream { HTML::Zoom::Parser::BuiltIn->new->html_to_stream($tmpl); } |
456a815d |
22 | |
d80786d0 |
23 | sub html_sink { HTML::Zoom::Producer::BuiltIn->new->html_from_stream($_[0]) } |
456a815d |
24 | |
25 | my $fb = HTML::Zoom::FilterBuilder->new; |
26 | |
27 | my $sp = HTML::Zoom::SelectorParser->new; |
28 | |
29 | sub filter { |
30 | my ($stream, $sel, $cb) = @_; |
31 | return HTML::Zoom::FilterStream->new({ |
32 | stream => $stream, |
33 | match => $sp->parse_selector($sel), |
34 | filter => do { local $_ = $fb; $cb->($fb) } |
35 | }); |
36 | } |
37 | |
38 | sub run_for (&;$) { |
39 | my $cb = shift; |
40 | (html_sink |
41 | (filter |
42 | src_stream, |
43 | (shift or '.main'), |
44 | $cb |
45 | ) |
46 | ) |
47 | } |
48 | |
8f962884 |
49 | my ($expect, @ev); |
50 | |
51 | ($expect = $tmpl) =~ s/class="main"/class="foo"/; |
52 | |
53 | is( |
54 | run_for { $_->set_attribute({ name => 'class', value => 'foo' }) }, |
55 | $expect, |
56 | 'set attribute on existing attribute' |
57 | ); |
58 | |
59 | ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/; |
60 | |
61 | is( |
62 | run_for { $_->set_attribute({ name => 'foo', value => 'bar' }) }, |
63 | $expect, |
64 | 'set attribute on non existing attribute' |
65 | ); |
66 | |
67 | ($expect = $tmpl) =~ s/class="main"/class="main foo"/; |
68 | |
69 | is( |
2daa653a |
70 | run_for { $_->add_to_attribute({ name => 'class', value => 'foo' }) }, |
8f962884 |
71 | $expect, |
72 | 'add attribute on existing attribute' |
73 | ); |
74 | |
75 | ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/; |
76 | |
77 | is( |
2daa653a |
78 | run_for { $_->add_to_attribute({ name => 'foo', value => 'bar' }) }, |
8f962884 |
79 | $expect, |
80 | 'add attribute on non existing attribute' |
81 | ); |
82 | |
83 | ($expect = $tmpl) =~ s/ class="main"//; |
84 | |
85 | is( |
86 | run_for { $_->remove_attribute({ name => 'class' }) }, |
87 | $expect, |
88 | 'remove attribute on existing attribute' |
89 | ); |
90 | |
91 | is( |
92 | run_for { $_->remove_attribute({ name => 'foo' }) }, |
93 | $tmpl, |
94 | 'remove attribute on non existing attribute' |
95 | ); |
96 | |
97 | ($expect = $tmpl) =~ s/(?=<div)/O HAI/; |
456a815d |
98 | |
99 | my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ]; |
100 | |
101 | is( |
102 | run_for { $_->add_before($ohai) }, |
103 | $expect, |
9aa040d7 |
104 | 'add_before event ok' |
105 | ); |
106 | is( |
107 | eval { run_for { $_->add_before('O HAI') } }, |
108 | $expect, |
109 | 'add_before string ok' |
456a815d |
110 | ); |
111 | |
112 | ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/; |
113 | |
114 | is( |
115 | run_for { $_->add_after($ohai) }, |
116 | $expect, |
9aa040d7 |
117 | 'add_after event ok' |
118 | ); |
119 | is( |
120 | eval { run_for { $_->add_after('O HAI') } }, |
121 | $expect, |
122 | 'add_after string ok' |
456a815d |
123 | ); |
124 | |
125 | ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/; |
126 | |
127 | is( |
865bb5d2 |
128 | run_for { $_->prepend_content($ohai) }, |
456a815d |
129 | $expect, |
865bb5d2 |
130 | 'prepend_content ok' |
456a815d |
131 | ); |
132 | |
133 | ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/; |
134 | |
135 | is( |
865bb5d2 |
136 | (run_for { $_->prepend_content($ohai) } 'hr'), |
456a815d |
137 | $expect, |
865bb5d2 |
138 | 'prepend_content ok with in place close' |
456a815d |
139 | ); |
140 | |
9aa040d7 |
141 | $expect = <<'HTML'; |
142 | <body> |
456a815d |
143 | O HAI |
144 | </body> |
9aa040d7 |
145 | HTML |
146 | is( |
147 | run_for { $_->replace($ohai) }, |
148 | $expect, |
149 | 'replace event ok' |
150 | ); |
151 | is( |
152 | run_for { $_->replace('O HAI') }, |
153 | $expect, |
154 | 'replace string ok' |
456a815d |
155 | ); |
156 | |
8f962884 |
157 | @ev = (); |
c86c0ce2 |
158 | |
159 | is( |
160 | run_for { $_->collect({ into => \@ev }) }, |
161 | '<body> |
162 | |
163 | </body> |
164 | ', |
165 | 'collect removes without passthrough' |
166 | ); |
167 | |
168 | is( |
169 | HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev), |
170 | '<div class="main"> |
171 | <span class="hilight name">Bob</span> |
172 | <span class="career">Builder</span> |
173 | <hr /> |
174 | </div>', |
175 | 'collect collected right events' |
176 | ); |
41153e87 |
177 | |
8f962884 |
178 | @ev = (); |
41153e87 |
179 | |
180 | is( |
865bb5d2 |
181 | run_for { $_->collect({ into => \@ev, content => 1 }) }, |
8f962884 |
182 | '<body> |
183 | <div class="main"></div> |
184 | </body> |
185 | ', |
865bb5d2 |
186 | 'collect w/content removes correctly' |
41153e87 |
187 | ); |
188 | |
189 | is( |
8f962884 |
190 | HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev), |
191 | ' |
192 | <span class="hilight name">Bob</span> |
193 | <span class="career">Builder</span> |
194 | <hr /> |
195 | ', |
865bb5d2 |
196 | 'collect w/content collects correctly' |
41153e87 |
197 | ); |
198 | |
11cc25dd |
199 | is( |
865bb5d2 |
200 | run_for { $_->replace($ohai, { content => 1 }) }, |
11cc25dd |
201 | '<body> |
202 | <div class="main">O HAI</div> |
203 | </body> |
204 | ', |
865bb5d2 |
205 | 'replace w/content' |
11cc25dd |
206 | ); |
207 | |
a25b8d4d |
208 | ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/; |
209 | |
210 | is( |
865bb5d2 |
211 | run_for { $_->append_content($ohai) }, |
a25b8d4d |
212 | $expect, |
865bb5d2 |
213 | 'append content ok' |
a25b8d4d |
214 | ); |
215 | |
865bb5d2 |
216 | my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } }; |
3cdbc13f |
217 | |
218 | is( |
219 | run_for { |
220 | $_->repeat( |
221 | [ |
222 | sub { |
223 | filter |
865bb5d2 |
224 | filter($_ => '.name' => $r_content->('mst')) |
225 | => '.career' => $r_content->('Chainsaw Wielder') |
3cdbc13f |
226 | }, |
227 | sub { |
228 | filter |
865bb5d2 |
229 | filter($_ => '.name' => $r_content->('mdk')) |
230 | => '.career' => $r_content->('Adminion') |
3cdbc13f |
231 | }, |
232 | ] |
233 | ) |
234 | }, |
235 | q{<body> |
236 | <div class="main"> |
237 | <span class="hilight name">mst</span> |
238 | <span class="career">Chainsaw Wielder</span> |
239 | <hr /> |
240 | </div><div class="main"> |
241 | <span class="hilight name">mdk</span> |
242 | <span class="career">Adminion</span> |
243 | <hr /> |
244 | </div> |
245 | </body> |
246 | }, |
247 | 'repeat ok' |
248 | ); |
249 | |
865bb5d2 |
250 | is( |
251 | run_for { |
252 | $_->repeat_content( |
253 | [ |
254 | sub { |
255 | filter |
256 | filter($_ => '.name' => $r_content->('mst')) |
257 | => '.career' => $r_content->('Chainsaw Wielder') |
258 | }, |
259 | sub { |
260 | filter |
261 | filter($_ => '.name' => $r_content->('mdk')) |
262 | => '.career' => $r_content->('Adminion') |
263 | }, |
264 | ] |
265 | ) |
266 | }, |
267 | q{<body> |
268 | <div class="main"> |
269 | <span class="hilight name">mst</span> |
270 | <span class="career">Chainsaw Wielder</span> |
271 | <hr /> |
272 | |
273 | <span class="hilight name">mdk</span> |
274 | <span class="career">Adminion</span> |
275 | <hr /> |
276 | </div> |
277 | </body> |
278 | }, |
279 | 'repeat_content ok' |
280 | ); |
3cdbc13f |
281 | |
dae33531 |
282 | is( |
283 | run_for { |
284 | my @between; |
285 | $_->repeat_content( |
286 | [ |
287 | sub { |
b5a48c47 |
288 | HTML::Zoom::ArrayStream->new({ array => [ |
dae33531 |
289 | (filter |
290 | filter($_ => '.name' => $r_content->('mst')) |
291 | => '.career' => $r_content->('Chainsaw Wielder')), |
b5a48c47 |
292 | HTML::Zoom::ArrayStream->new({ array => \@between }) |
293 | ] })->flatten |
dae33531 |
294 | }, |
295 | sub { |
296 | filter |
297 | filter($_ => '.name' => $r_content->('mdk')) |
298 | => '.career' => $r_content->('Adminion') |
299 | }, |
300 | ], |
301 | { filter => sub { |
302 | filter $_[0] => 'hr' => sub { $_->collect({ into => \@between }) } |
303 | } |
304 | } |
305 | ) |
306 | }, |
307 | q{<body> |
308 | <div class="main"> |
309 | <span class="hilight name">mst</span> |
310 | <span class="career">Chainsaw Wielder</span> |
311 | <hr /> |
312 | <span class="hilight name">mdk</span> |
313 | <span class="career">Adminion</span> |
314 | |
315 | </div> |
316 | </body> |
317 | }, |
318 | 'repeat_content with filter ok' |
319 | ); |
320 | |
f8ed299b |
321 | is( |
322 | run_for { |
323 | my @between; |
324 | $_->repeat_content( |
325 | [ |
326 | sub { |
327 | filter |
328 | filter($_ => '.name' => $r_content->('mst')) |
329 | => '.career' => $r_content->('Chainsaw Wielder') |
330 | }, |
331 | sub { |
332 | filter |
333 | filter($_ => '.name' => $r_content->('mdk')) |
334 | => '.career' => $r_content->('Adminion') |
335 | }, |
336 | ], |
337 | { repeat_between => 'hr' } |
338 | ) |
339 | }, |
340 | q{<body> |
341 | <div class="main"> |
342 | <span class="hilight name">mst</span> |
343 | <span class="career">Chainsaw Wielder</span> |
344 | <hr /> |
345 | <span class="hilight name">mdk</span> |
346 | <span class="career">Adminion</span> |
347 | |
348 | </div> |
349 | </body> |
350 | }, |
351 | 'repeat_content using repeat_between ok' |
352 | ); |
353 | |
456a815d |
354 | done_testing; |