Three new tests in t/action.t, two of them failing
[catagits/HTML-Zoom.git] / t / actions.t
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
21 sub src_stream { HTML::Zoom::Parser::BuiltIn->new->html_to_stream($tmpl); }
22
23 sub html_sink { HTML::Zoom::Producer::BuiltIn->new->html_from_stream($_[0]) }
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
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(
70   run_for { $_->add_to_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
77 is(
78   run_for { $_->add_to_attribute({ name => 'foo', value => 'bar' }) },
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/;
98
99 my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ];
100
101 is(
102   run_for { $_->add_before($ohai) },
103   $expect,
104   'add_before event ok'
105 );
106 is(
107   eval { run_for { $_->add_before('O HAI') } },
108   $expect,
109   'add_before string ok'
110 );
111
112 ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/;
113
114 is(
115   run_for { $_->add_after($ohai) },
116   $expect,
117   'add_after event ok'
118 );
119 is(
120   eval { run_for { $_->add_after('O HAI') } },
121   $expect,
122   'add_after string ok'
123 );
124
125 ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/;
126
127 is(
128   run_for { $_->prepend_content($ohai) },
129   $expect,
130   'prepend_content ok'
131 );
132
133 ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/;
134
135 is(
136   (run_for { $_->prepend_content($ohai) } 'hr'),
137   $expect,
138   'prepend_content ok with in place close'
139 );
140
141 $expect = <<'HTML';
142 <body>
143   O HAI
144 </body>
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'
155 );
156
157 @ev = ();
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 );
177
178 @ev = ();
179
180 is(
181   run_for { $_->collect({ into => \@ev, content => 1 }) },
182   '<body>
183   <div class="main"></div>
184 </body>
185 ',
186   'collect w/content removes correctly'
187 );
188
189 is(
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   ',
196   'collect w/content collects correctly'
197 );
198
199 is(
200   run_for { $_->replace($ohai, { content => 1 }) },
201   '<body>
202   <div class="main">O HAI</div>
203 </body>
204 ',
205   'replace w/content'
206 );
207
208 ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/;
209
210 is(
211   run_for { $_->append_content($ohai) },
212   $expect,
213   'append content ok'
214 );
215
216 my $r_content = sub { my $r = shift; sub { $_->replace($r, { content => 1 }) } };
217
218 is(
219   run_for {
220     $_->repeat(
221       [
222         sub {
223           filter
224             filter($_ => '.name' => $r_content->('mst'))
225             => '.career' => $r_content->('Chainsaw Wielder')
226         },
227         sub {
228           filter
229             filter($_ => '.name' => $r_content->('mdk'))
230             => '.career' => $r_content->('Adminion')
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
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 );
281
282 is(
283   run_for {
284     my @between;
285     $_->repeat_content(
286       [
287         sub {
288           HTML::Zoom::ArrayStream->new({ array => [
289             (filter
290               filter($_ => '.name' => $r_content->('mst'))
291               => '.career' => $r_content->('Chainsaw Wielder')),
292             HTML::Zoom::ArrayStream->new({ array => \@between })
293           ] })->flatten
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
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
354 done_testing;