Bug 9259: Use is instead of is_deeply
[koha.git] / t / db_dependent / FrameworkPlugin.t
1 use Modern::Perl;
2
3 use C4::Auth;
4 use C4::Output;
5 use Koha::FrameworkPlugin;
6
7 use CGI;
8 use File::Temp qw/tempfile/;
9 use Getopt::Long;
10 use Test::MockModule;
11 use Test::More tests => 5;
12
13 my @includes;
14 GetOptions( 'include=s{,}' => \@includes ); #not used by default !
15
16 my $dbh = C4::Context->dbh;
17 $dbh->{AutoCommit} = 0;
18 $dbh->{RaiseError} = 1;
19
20 subtest 'Test01 -- Simple tests for new and name' => sub {
21     plan tests => 7;
22     test01();
23     $dbh->rollback;
24 };
25 subtest 'Test02 -- test build with old styler and marc21_leader' => sub {
26     plan tests => 5;
27     test02();
28     $dbh->rollback;
29 };
30 subtest 'Test03 -- tests with bad plugins' => sub {
31     test03();
32     $dbh->rollback;
33 };
34 subtest 'Test04 -- tests with new style plugin' => sub {
35     plan tests => 5;
36     test04();
37     $dbh->rollback;
38 };
39 subtest 'Test05 -- tests with build and launch for default plugins' => sub {
40     test05( \@includes );
41     $dbh->rollback;
42 };
43 $dbh->rollback;
44
45 sub test01 {
46     #empty plugin
47     my $plugin= Koha::FrameworkPlugin->new;
48     is( ref($plugin), 'Koha::FrameworkPlugin', 'Got an object' );
49     isnt( $plugin->errstr, undef, 'We should have an error for missing name');
50     is( $plugin->build, undef, 'Build returns undef');
51
52     #tests for name and path, with/without hashref
53     $plugin= Koha::FrameworkPlugin->new( { name => 'marc21_leader.pl' } );
54     is( $plugin->name, 'marc21_leader.pl', 'Check name without path in hash' );
55     $plugin= Koha::FrameworkPlugin->new( 'marc21_leader.pl' );
56     is( $plugin->name, 'marc21_leader.pl', 'Check name without path' );
57     $plugin= Koha::FrameworkPlugin->new( 'cataloguing/value_builder/marc21_leader.pl' );
58     is( $plugin->name, 'marc21_leader.pl', 'Check name with path' );
59     $plugin= Koha::FrameworkPlugin->new({ path => 'cataloguing/value_builder', name => 'marc21_leader.pl' });
60     is( $plugin->name, 'marc21_leader.pl', 'Check name and path in hash' );
61 }
62
63 sub test02 {
64     # first test an old style item plugin
65     my $old = old01(); # plugin filename
66     my $path;
67     if( $old =~ /^(.*)\/([^\/]+)$/ ) { # extract path
68         $path = $1;
69         $old = $2;
70     }
71     my $plugin= Koha::FrameworkPlugin->new({
72         name => $old, path => $path, item_style => 1,
73     });
74     my $pars= { id => '234567' };
75     is( $plugin->build($pars), 1, 'Build oldstyler successful' );
76     is( length($plugin->javascript)>0 && !$plugin->noclick, 1,
77         'Checked javascript and noclick' );
78
79     # now test marc21_leader
80     $plugin= Koha::FrameworkPlugin->new( { name => 'marc21_leader.pl' } );
81     $pars= { dbh => $dbh, id => '123456' };
82     is( $plugin->build($pars), 1, 'Build marc21_leader successful' );
83     is( $plugin->javascript =~ /<script.*function.*\<\/script\>/s, 1,
84         'Javascript looks ok' );
85     is( $plugin->noclick, '', 'marc21_leader should have a popup');
86 }
87
88 sub test03 {
89     #file not found
90     my $plugin= Koha::FrameworkPlugin->new('file_does_not_exist');
91     $plugin->build;
92     is( $plugin->errstr =~ /not found/i, 1, 'File not found-message');
93
94     #three bad ones: no perl, syntax error, bad return value
95     foreach my $f ( bad01(), bad02(), bad03() ) {
96         next if !$f;
97         $plugin= Koha::FrameworkPlugin->new( $f );
98         $plugin->build({ id => '998877' });
99         is( defined($plugin->errstr), 1,
100             "Saw: ". ( $plugin->errstr//'no error??' ));
101     }
102     done_testing();
103 }
104
105 sub test04 {
106     #two simple new style plugins
107     my $plugin= Koha::FrameworkPlugin->new( good01() );
108     my $pars= { id => 'example_345' };
109     is( $plugin->build($pars), 1, 'Build 1 ok');
110     isnt( $plugin->javascript, '', 'Checked javascript property' );
111
112     $plugin= Koha::FrameworkPlugin->new( ugly01() );
113     $pars= { id => 'example_456' };
114     is( $plugin->build($pars), 1, 'Build 2 ok');
115     is( $plugin->build($pars), 1, 'Second build 2 ok');
116     is( $plugin->launch($pars), 'abc', 'Launcher returned something' );
117         #note: normally you will not call build and launch like that
118 }
119
120 sub test05 {
121     my ( $incl ) = @_;
122     #mock to simulate some authorization and eliminate lots of output
123     my $launched = 0;
124     my $mContext = new Test::MockModule('C4::Context');
125     my $mAuth = new Test::MockModule('C4::Auth');
126     my $mOutput = new Test::MockModule('C4::Output');
127     $mContext->mock( 'userenv', \&mock_userenv );
128     $mAuth->mock( 'checkauth', sub { return ( 1, undef, 1, all_perms() ); } );
129     $mOutput->mock('output_html_with_http_headers',  sub { ++$launched; } );
130
131     my $cgi=new CGI;
132     my ( $plugins, $min ) = selected_plugins( $incl );
133
134     # test building them
135     my $objs;
136     foreach my $f ( @$plugins ) {
137         $objs->{$f} = Koha::FrameworkPlugin->new( $f );
138         my $pars= { dbh => $dbh, id => $f };
139         is( $objs->{$f}->build($pars), 1, "Builded ".$objs->{$f}->name );
140     }
141
142     # test launching them (but we cannot verify returned results here)
143     undef $objs;
144     foreach my $f ( @$plugins ) {
145         $objs->{$f} = Koha::FrameworkPlugin->new( $f );
146         my $pars= { dbh => $dbh, id => $f };
147         $objs->{$f}->launch({ cgi => $cgi });
148             # may generate some uninitialized warnings for missing params
149         is( $objs->{$f}->errstr, undef, "Launched ".$objs->{$f}->name );
150     }
151     is( $launched >= $min, 1,
152             "$launched of ". scalar @$plugins.' plugins generated output ');
153     done_testing();
154 }
155
156 sub selected_plugins {
157     my ( $incl ) = @_;
158     #if you use includes, FIRST assure yourself that you do not
159     #include any destructive perl scripts! You know what you are doing..
160
161     my ( @fi, $min);
162     if( $incl && @$incl ) {
163         @fi = @$incl;
164         $min = 0; #not sure how many will output
165     } else { # some default MARC, UNIMARC and item plugins
166         @fi = qw| barcode.pl dateaccessioned.pl marc21_orgcode.pl
167 marc21_field_005.pl marc21_field_006.pl marc21_field_007.pl marc21_field_008.pl
168 marc21_field_008_authorities.pl marc21_leader.pl marc21_leader_authorities.pl
169 unimarc_leader.pl unimarc_field_100.pl unimarc_field_105.pl
170 unimarc_field_106.pl unimarc_field_110.pl unimarc_field_120.pl
171 unimarc_field_130.pl unimarc_field_140.pl unimarc_field_225a.pl
172 unimarc_field_4XX.pl |;
173         $min = 16; # the first four generate no output
174     }
175     @fi = grep
176         { !/ajax|callnumber(-KU)?\.pl|labs_theses/ } # skip these
177         @fi;
178     return ( \@fi, $min);
179 }
180
181 sub mock_userenv {
182     return { branch => 'CPL', flags => 1, id => 1 };
183 }
184
185 sub all_perms {
186     my $p = $dbh->selectcol_arrayref("SELECT flag FROM userflags");
187     my $rv= {};
188     foreach my $module ( @$p ) {
189         $rv->{ $module } = 1;
190     }
191     return $rv;
192 }
193
194 sub mytempfile {
195     my ( $fh, $fn ) = tempfile( SUFFIX => '.plugin', UNLINK => 1 );
196     print $fh $_[0]//'';
197     close $fh;
198     return $fn;
199 }
200
201 sub old01 {
202 # simple old style item plugin: note that Focus has two pars
203 # includes a typical empty Clic function and plugin subroutine
204     return mytempfile( <<'HERE'
205 sub plugin_javascript {
206     my ($dbh,$record,$tagslib,$field_number,$tabloop) = @_;
207     my $function_name = $field_number;
208     my $res = "
209 <script type=\"text/javascript\">
210 //<![CDATA[
211 function Focus$function_name(subfield_managed,id) {
212     document.getElementById(id).value='test';
213     return 0;
214 }
215 function Clic$function_name(subfield_managed) {
216 }
217 //]]>
218 </script>
219 ";
220     return ($function_name,$res);
221 }
222 sub plugin {
223     return "";
224 }
225 HERE
226     );
227 }
228
229 sub good01 { #very simple new style plugin, no launcher
230     return mytempfile( <<'HERE'
231 my $builder = sub {
232     my $params = shift;
233     return qq|
234 <script type="text/javascript">
235     function Focus$params->{id}(event) {
236         if( document.getElementById(event.data.id).value == '' ) {
237             document.getElementById(event.data.id).value='EXAMPLE: ';
238         }
239     }
240 </script>|;
241 };
242 return { builder => $builder };
243 HERE
244     );
245 }
246
247 sub bad01 { # this is no plugin
248     return mytempfile( 'Just nonsense' );
249 }
250
251 sub bad02 { # common syntax error: you forgot the semicolon of sub1 declare
252     return mytempfile( <<'HERE'
253 my $sub1= sub {
254     my $params = shift;
255     return qq|<script type="text/javascript">function Change$params->{id}(event) { alert("Changed"); }</script>|;
256 }
257 return { builder => $sub1 };
258 HERE
259     );
260 }
261
262 sub bad03 { # badscript tag should trigger an error
263     return mytempfile( <<'HERE'
264 my $sub1= sub {
265     my $params = shift;
266     return qq|<badscript type="text/javascript">function Click$params->{id} (event) { alert("Hi there"); return false; }</badscript>|;
267 };
268 return { builder => $sub1 };
269 HERE
270     );
271 }
272
273 sub ugly01 { #works, but not very readable..
274     return mytempfile( <<'HERE'
275 return {builder=>sub{return qq|<script type="text/javascript">function Blur$_[0]->{id}(event){alert('Bye');}</script>|;},launcher=>sub{'abc'}};
276 HERE
277     );
278 }