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