Commit | Line | Data |
1cf03540 |
1 | use strictures 1; |
456a815d |
2 | use Test::More; |
3 | |
4 | use HTML::Zoom::Parser::BuiltIn; |
5 | use HTML::Zoom::Producer::BuiltIn; |
6 | use HTML::Zoom::SelectorParser; |
7 | use HTML::Zoom::FilterBuilder; |
8 | use HTML::Zoom::FilterStream; |
9 | |
10 | my $tmpl = <<END; |
11 | <body> |
3c53c439 |
12 | <div name="cow" class="main"> |
456a815d |
13 | <span class="hilight name">Bob</span> |
14 | <span class="career">Builder</span> |
15 | <hr /> |
16 | </div> |
17 | </body> |
18 | END |
19 | |
d80786d0 |
20 | sub src_stream { HTML::Zoom::Parser::BuiltIn->new->html_to_stream($tmpl); } |
456a815d |
21 | |
d80786d0 |
22 | sub html_sink { HTML::Zoom::Producer::BuiltIn->new->html_from_stream($_[0]) } |
456a815d |
23 | |
24 | my $fb = HTML::Zoom::FilterBuilder->new; |
25 | |
26 | my $sp = HTML::Zoom::SelectorParser->new; |
27 | |
28 | sub filter { |
29 | my ($stream, $sel, $cb) = @_; |
30 | return HTML::Zoom::FilterStream->new({ |
31 | stream => $stream, |
32 | match => $sp->parse_selector($sel), |
33 | filter => do { local $_ = $fb; $cb->($fb) } |
34 | }); |
35 | } |
36 | |
37 | sub run_for (&;$) { |
38 | my $cb = shift; |
39 | (html_sink |
40 | (filter |
41 | src_stream, |
42 | (shift or '.main'), |
43 | $cb |
44 | ) |
45 | ) |
46 | } |
47 | |
8f962884 |
48 | my ($expect, @ev); |
49 | |
50 | ($expect = $tmpl) =~ s/class="main"/class="foo"/; |
51 | |
52 | is( |
f0ddc273 |
53 | run_for { $_->set_attribute( 'class' => 'foo' ) }, |
8f962884 |
54 | $expect, |
55 | 'set attribute on existing attribute' |
56 | ); |
57 | |
3c53c439 |
58 | ($expect = $tmpl) =~ s/name="cow" class="main"/name="bar" class="foo"/; |
59 | |
60 | is( |
c84b68f3 |
61 | run_for { $_->set_attr({ 'class' => 'foo', 'name' => 'bar'}) }, |
3c53c439 |
62 | $expect, |
c84b68f3 |
63 | 'set attributes using hashref form (shorthand)' |
3c53c439 |
64 | ); |
65 | |
8f962884 |
66 | ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/; |
67 | |
68 | is( |
f0ddc273 |
69 | run_for { $_->set_attribute( 'foo' => 'bar' ) }, |
8f962884 |
70 | $expect, |
71 | 'set attribute on non existing attribute' |
72 | ); |
73 | |
74 | ($expect = $tmpl) =~ s/class="main"/class="main foo"/; |
75 | |
76 | is( |
f0ddc273 |
77 | run_for { $_->add_to_attribute( 'class' => 'foo' ) }, |
8f962884 |
78 | $expect, |
79 | 'add attribute on existing attribute' |
80 | ); |
81 | |
bf07288f |
82 | ($expect = $tmpl) =~ s/class="main"/class="main foo"/; |
83 | |
84 | is( |
85 | run_for { $_->add_class('foo') }, |
86 | $expect, |
87 | 'add attribute on existing attribute (shorthand)' |
88 | ); |
89 | |
90 | ($expect = $tmpl) =~ s/class="main"/class="main" id="foo"/; |
91 | |
92 | is( |
93 | run_for { $_->set_id('foo') }, |
94 | $expect, |
95 | 'set_id (shorthand)' |
96 | ); |
97 | |
8f962884 |
98 | ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/; |
99 | |
100 | is( |
f0ddc273 |
101 | run_for { $_->add_to_attribute( 'foo' => 'bar' ) }, |
8f962884 |
102 | $expect, |
103 | 'add attribute on non existing attribute' |
104 | ); |
105 | |
106 | ($expect = $tmpl) =~ s/ class="main"//; |
107 | |
108 | is( |
109 | run_for { $_->remove_attribute({ name => 'class' }) }, |
110 | $expect, |
111 | 'remove attribute on existing attribute' |
112 | ); |
113 | |
114 | is( |
115 | run_for { $_->remove_attribute({ name => 'foo' }) }, |
116 | $tmpl, |
117 | 'remove attribute on non existing attribute' |
118 | ); |
119 | |
c84b68f3 |
120 | ($expect = $tmpl) =~ s/class="main"/class=""/; |
121 | |
122 | is( |
123 | run_for { $_->remove_from_attribute({ class => 'main' }) }, |
124 | $expect, |
125 | 'remove name from attribute' |
126 | ); |
127 | |
071d8831 |
128 | is( |
129 | run_for { $_->remove_from_attribute({ madeup => 'main' }) }, |
130 | $tmpl, |
131 | 'remove name from non existing attribute (ignored)' |
132 | ); |
133 | |
134 | ($expect = $tmpl) =~ s/class="main"/class=""/; |
135 | |
136 | is( |
137 | run_for { $_->remove_class( 'main' ) }, |
138 | $expect, |
139 | 'remove_class' |
140 | ); |
141 | |
5cac799e |
142 | ($expect = $tmpl) =~ s/ class="main"//; |
143 | |
144 | is( |
145 | run_for { |
146 | $_->transform_attribute({ |
147 | name => 'class', |
148 | code => sub { |
149 | my $a = shift; |
150 | return if $a eq 'main'; |
151 | return $a; |
152 | }, |
153 | }) |
154 | }, |
155 | $expect, |
156 | 'transform_attribute deletes the attr if code returns undef', |
157 | ); |
158 | |
159 | ($expect = $tmpl) =~ s/ class="main"/ class="moan"/; |
160 | |
161 | is( |
162 | run_for { |
163 | $_->transform_attribute({ |
164 | name => 'class', |
165 | code => sub { |
166 | ( my $b = shift ) =~ s/main/moan/; |
167 | $b |
168 | }, |
169 | }) |
170 | }, |
171 | $expect, |
172 | 'transform_attribute transforms something', |
173 | ); |
174 | |
175 | ($expect = $tmpl) =~ s/ class="main"/ class="main" noggin="zonk"/; |
176 | |
177 | is( |
178 | run_for { |
179 | $_->transform_attribute({ |
180 | name => 'noggin', |
181 | code => sub { 'zonk' }, |
182 | }) |
183 | }, |
184 | $expect, |
185 | 'transform_attribute adds attribute if not there before', |
186 | ); |
187 | |
188 | is( |
189 | run_for { |
190 | $_->transform_attribute({ |
191 | name => 'noggin', |
192 | code => sub { }, |
193 | }) |
194 | }, |
195 | $tmpl, |
196 | 'transform_attribute on nonexistent att does not add it if code returns undef', |
197 | ); |
198 | |
199 | |
8f962884 |
200 | ($expect = $tmpl) =~ s/(?=<div)/O HAI/; |
456a815d |
201 | |
202 | my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ]; |
203 | |
204 | is( |
205 | run_for { $_->add_before($ohai) }, |
206 | $expect, |
207 | 'add_before ok' |
208 | ); |
209 | |
210 | ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/; |
211 | |
212 | is( |
213 | run_for { $_->add_after($ohai) }, |
214 | $expect, |
215 | 'add_after ok' |
216 | ); |
217 | |
218 | ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/; |
219 | |
220 | is( |
865bb5d2 |
221 | run_for { $_->prepend_content($ohai) }, |
456a815d |
222 | $expect, |
865bb5d2 |
223 | 'prepend_content ok' |
456a815d |
224 | ); |
225 | |
226 | ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/; |
227 | |
228 | is( |
865bb5d2 |
229 | (run_for { $_->prepend_content($ohai) } 'hr'), |
456a815d |
230 | $expect, |
865bb5d2 |
231 | 'prepend_content ok with in place close' |
456a815d |
232 | ); |
233 | |
234 | is( |
235 | run_for { $_->replace($ohai) }, |
236 | '<body> |
237 | O HAI |
238 | </body> |
239 | ', |
240 | 'replace ok' |
241 | ); |
242 | |
8f962884 |
243 | @ev = (); |
c86c0ce2 |
244 | |
245 | is( |
246 | run_for { $_->collect({ into => \@ev }) }, |
247 | '<body> |
248 | |
249 | </body> |
250 | ', |
251 | 'collect removes without passthrough' |
252 | ); |
253 | |
254 | is( |
255 | HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev), |
3c53c439 |
256 | '<div name="cow" class="main"> |
c86c0ce2 |
257 | <span class="hilight name">Bob</span> |
258 | <span class="career">Builder</span> |
259 | <hr /> |
260 | </div>', |
261 | 'collect collected right events' |
262 | ); |
41153e87 |
263 | |
8f962884 |
264 | @ev = (); |
41153e87 |
265 | |
266 | is( |
865bb5d2 |
267 | run_for { $_->collect({ into => \@ev, content => 1 }) }, |
8f962884 |
268 | '<body> |
3c53c439 |
269 | <div name="cow" class="main"></div> |
8f962884 |
270 | </body> |
271 | ', |
865bb5d2 |
272 | 'collect w/content removes correctly' |
41153e87 |
273 | ); |
274 | |
275 | is( |
8f962884 |
276 | HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev), |
277 | ' |
278 | <span class="hilight name">Bob</span> |
279 | <span class="career">Builder</span> |
280 | <hr /> |
281 | ', |
865bb5d2 |
282 | 'collect w/content collects correctly' |
41153e87 |
283 | ); |
284 | |
11cc25dd |
285 | is( |
865bb5d2 |
286 | run_for { $_->replace($ohai, { content => 1 }) }, |
11cc25dd |
287 | '<body> |
3c53c439 |
288 | <div name="cow" class="main">O HAI</div> |
11cc25dd |
289 | </body> |
290 | ', |
865bb5d2 |
291 | 'replace w/content' |
11cc25dd |
292 | ); |
293 | |
a25b8d4d |
294 | ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/; |
295 | |
296 | is( |
865bb5d2 |
297 | run_for { $_->append_content($ohai) }, |
a25b8d4d |
298 | $expect, |
865bb5d2 |
299 | 'append content ok' |
a25b8d4d |
300 | ); |
301 | |
865bb5d2 |
302 | my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } }; |
3cdbc13f |
303 | |
304 | is( |
305 | run_for { |
306 | $_->repeat( |
307 | [ |
308 | sub { |
309 | filter |
865bb5d2 |
310 | filter($_ => '.name' => $r_content->('mst')) |
311 | => '.career' => $r_content->('Chainsaw Wielder') |
3cdbc13f |
312 | }, |
313 | sub { |
314 | filter |
865bb5d2 |
315 | filter($_ => '.name' => $r_content->('mdk')) |
316 | => '.career' => $r_content->('Adminion') |
3cdbc13f |
317 | }, |
318 | ] |
319 | ) |
320 | }, |
321 | q{<body> |
3c53c439 |
322 | <div name="cow" class="main"> |
3cdbc13f |
323 | <span class="hilight name">mst</span> |
324 | <span class="career">Chainsaw Wielder</span> |
325 | <hr /> |
3c53c439 |
326 | </div><div name="cow" class="main"> |
3cdbc13f |
327 | <span class="hilight name">mdk</span> |
328 | <span class="career">Adminion</span> |
329 | <hr /> |
330 | </div> |
331 | </body> |
332 | }, |
333 | 'repeat ok' |
334 | ); |
335 | |
865bb5d2 |
336 | is( |
337 | run_for { |
338 | $_->repeat_content( |
339 | [ |
340 | sub { |
341 | filter |
342 | filter($_ => '.name' => $r_content->('mst')) |
343 | => '.career' => $r_content->('Chainsaw Wielder') |
344 | }, |
345 | sub { |
346 | filter |
347 | filter($_ => '.name' => $r_content->('mdk')) |
348 | => '.career' => $r_content->('Adminion') |
349 | }, |
350 | ] |
351 | ) |
352 | }, |
353 | q{<body> |
3c53c439 |
354 | <div name="cow" class="main"> |
865bb5d2 |
355 | <span class="hilight name">mst</span> |
356 | <span class="career">Chainsaw Wielder</span> |
357 | <hr /> |
358 | |
359 | <span class="hilight name">mdk</span> |
360 | <span class="career">Adminion</span> |
361 | <hr /> |
362 | </div> |
363 | </body> |
364 | }, |
365 | 'repeat_content ok' |
366 | ); |
3cdbc13f |
367 | |
dae33531 |
368 | is( |
369 | run_for { |
370 | my @between; |
371 | $_->repeat_content( |
372 | [ |
373 | sub { |
b5a48c47 |
374 | HTML::Zoom::ArrayStream->new({ array => [ |
dae33531 |
375 | (filter |
376 | filter($_ => '.name' => $r_content->('mst')) |
377 | => '.career' => $r_content->('Chainsaw Wielder')), |
b5a48c47 |
378 | HTML::Zoom::ArrayStream->new({ array => \@between }) |
379 | ] })->flatten |
dae33531 |
380 | }, |
381 | sub { |
382 | filter |
383 | filter($_ => '.name' => $r_content->('mdk')) |
384 | => '.career' => $r_content->('Adminion') |
385 | }, |
386 | ], |
387 | { filter => sub { |
388 | filter $_[0] => 'hr' => sub { $_->collect({ into => \@between }) } |
389 | } |
390 | } |
391 | ) |
392 | }, |
393 | q{<body> |
3c53c439 |
394 | <div name="cow" class="main"> |
dae33531 |
395 | <span class="hilight name">mst</span> |
396 | <span class="career">Chainsaw Wielder</span> |
397 | <hr /> |
398 | <span class="hilight name">mdk</span> |
399 | <span class="career">Adminion</span> |
400 | |
401 | </div> |
402 | </body> |
403 | }, |
404 | 'repeat_content with filter ok' |
405 | ); |
406 | |
f8ed299b |
407 | is( |
408 | run_for { |
409 | my @between; |
410 | $_->repeat_content( |
411 | [ |
412 | sub { |
413 | filter |
414 | filter($_ => '.name' => $r_content->('mst')) |
415 | => '.career' => $r_content->('Chainsaw Wielder') |
416 | }, |
417 | sub { |
418 | filter |
419 | filter($_ => '.name' => $r_content->('mdk')) |
420 | => '.career' => $r_content->('Adminion') |
421 | }, |
422 | ], |
423 | { repeat_between => 'hr' } |
424 | ) |
425 | }, |
426 | q{<body> |
3c53c439 |
427 | <div name="cow" class="main"> |
f8ed299b |
428 | <span class="hilight name">mst</span> |
429 | <span class="career">Chainsaw Wielder</span> |
430 | <hr /> |
431 | <span class="hilight name">mdk</span> |
432 | <span class="career">Adminion</span> |
433 | |
434 | </div> |
435 | </body> |
436 | }, |
437 | 'repeat_content using repeat_between ok' |
438 | ); |
439 | |
456a815d |
440 | done_testing; |