first cut at repeater
[catagits/HTML-Zoom.git] / t / actions.t
1 use strict;
2 use warnings FATAL => 'all';
3 use Test::More;
4
5 use Devel::Dwarn;
6
7 use HTML::Zoom::Parser::BuiltIn;
8 use HTML::Zoom::Producer::BuiltIn;
9 use HTML::Zoom::SelectorParser;
10 use HTML::Zoom::FilterBuilder;
11 use HTML::Zoom::FilterStream;
12
13 my $tmpl = <<END;
14 <body>
15   <div class="main">
16     <span class="hilight name">Bob</span>
17     <span class="career">Builder</span>
18     <hr />
19   </div>
20 </body>
21 END
22
23 sub src_stream { HTML::Zoom::Parser::BuiltIn->html_to_stream($tmpl); }
24
25 sub html_sink { HTML::Zoom::Producer::BuiltIn->html_from_stream($_[0]) }
26
27 my $fb = HTML::Zoom::FilterBuilder->new;
28
29 my $sp = HTML::Zoom::SelectorParser->new;
30
31 sub filter {
32   my ($stream, $sel, $cb) = @_;
33   return HTML::Zoom::FilterStream->new({
34     stream => $stream,
35     match => $sp->parse_selector($sel),
36     filter => do { local $_ = $fb; $cb->($fb) }
37   });
38 }
39
40 sub run_for (&;$) {
41   my $cb = shift;
42   (html_sink
43     (filter
44       src_stream,
45       (shift or '.main'),
46       $cb
47     )
48   )
49 }
50
51 my ($expect, @ev);
52
53 ($expect = $tmpl) =~ s/class="main"/class="foo"/;
54
55 is(
56   run_for { $_->set_attribute({ name => 'class', value => 'foo' }) },
57   $expect,
58   'set attribute on existing attribute'
59 );
60
61 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
62
63 is(
64   run_for { $_->set_attribute({ name => 'foo', value => 'bar' }) },
65   $expect,
66   'set attribute on non existing attribute'
67 );
68
69 ($expect = $tmpl) =~ s/class="main"/class="main foo"/;
70
71 is(
72   run_for { $_->add_attribute({ name => 'class', value => 'foo' }) },
73   $expect,
74   'add attribute on existing attribute'
75 );
76
77 ($expect = $tmpl) =~ s/class="main"/class="main" foo="bar"/;
78
79 is(
80   run_for { $_->add_attribute({ name => 'foo', value => 'bar' }) },
81   $expect,
82   'add attribute on non existing attribute'
83 );
84
85 ($expect = $tmpl) =~ s/ class="main"//;
86
87 is(
88   run_for { $_->remove_attribute({ name => 'class' }) },
89   $expect,
90   'remove attribute on existing attribute'
91 );
92
93 is(
94   run_for { $_->remove_attribute({ name => 'foo' }) },
95   $tmpl,
96   'remove attribute on non existing attribute'
97 );
98
99 ($expect = $tmpl) =~ s/(?=<div)/O HAI/;
100
101 my $ohai = [ { type => 'TEXT', raw => 'O HAI' } ];
102
103 is(
104   run_for { $_->add_before($ohai) },
105   $expect,
106   'add_before ok'
107 );
108
109 ($expect = $tmpl) =~ s/(?<=<\/div>)/O HAI/;
110
111 is(
112   run_for { $_->add_after($ohai) },
113   $expect,
114   'add_after ok'
115 );
116
117 ($expect = $tmpl) =~ s/(?<=class="main">)/O HAI/;
118
119 is(
120   run_for { $_->prepend_inside($ohai) },
121   $expect,
122   'prepend_inside ok'
123 );
124
125 ($expect = $tmpl) =~ s/<hr \/>/<hr>O HAI<\/hr>/;
126
127 is(
128   (run_for { $_->prepend_inside($ohai) } 'hr'),
129   $expect,
130   'prepend_inside ok with in place close'
131 );
132
133 is(
134   run_for { $_->replace($ohai) },
135 '<body>
136   O HAI
137 </body>
138 ',
139   'replace ok'
140 );
141
142 @ev = ();
143
144 is(
145   run_for { $_->collect({ into => \@ev }) },
146   '<body>
147   
148 </body>
149 ',
150   'collect removes without passthrough'
151 );
152
153 is(
154   HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
155   '<div class="main">
156     <span class="hilight name">Bob</span>
157     <span class="career">Builder</span>
158     <hr />
159   </div>',
160   'collect collected right events'
161 );
162
163 @ev = ();
164
165 is(
166   run_for { $_->collect({ into => \@ev, inside => 1 }) },
167   '<body>
168   <div class="main"></div>
169 </body>
170 ',
171   'collect w/inside removes correctly'
172 );
173
174 is(
175   HTML::Zoom::Producer::BuiltIn->html_from_events(\@ev),
176   '
177     <span class="hilight name">Bob</span>
178     <span class="career">Builder</span>
179     <hr />
180   ',
181   'collect w/inside collects correctly'
182 );
183
184 is(
185   run_for { $_->replace($ohai, { inside => 1 }) },
186   '<body>
187   <div class="main">O HAI</div>
188 </body>
189 ',
190   'replace w/inside'
191 );
192
193 ($expect = $tmpl) =~ s/(?=<\/div>)/O HAI/;
194
195 is(
196   run_for { $_->append_inside($ohai) },
197   $expect,
198   'append inside ok'
199 );
200
201 if (1) {
202
203 warn "\n\n----\n\n";
204
205 my $r_inside = sub { my $r = shift; sub { $_->replace($r, { inside => 1 }) } };
206
207 is(
208   run_for {
209     $_->repeat(
210       [
211         sub {
212           filter
213             filter($_ => '.name' => $r_inside->('mst'))
214             => '.career' => $r_inside->('Chainsaw Wielder')
215         },
216         sub {
217           filter
218             filter($_ => '.name' => $r_inside->('mdk'))
219             => '.career' => $r_inside->('Adminion')
220         },
221       ]
222     )
223   },
224   q{<body>
225   <div class="main">
226     <span class="hilight name">mst</span>
227     <span class="career">Chainsaw Wielder</span>
228     <hr />
229   </div><div class="main">
230     <span class="hilight name">mdk</span>
231     <span class="career">Adminion</span>
232     <hr />
233   </div>
234 </body>
235 },
236   'repeat ok'
237 );
238
239 }
240
241 done_testing;