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