File Coverage

lib/WWW/Selenium/Utils.pm
Criterion Covered Total %
statement 212 215 98.6
branch 92 126 73.0
condition 26 35 74.2
subroutine 22 22 100.0
pod 1 10 10.0
total 353 408 86.5


\n); ", ", @$r), \n"; \n);
line stmt bran cond sub pod time code
1             package WWW::Selenium::Utils;
2              
3 2     2   34840 use 5.006;
  2         7  
  2         71  
4 2     2   9 use strict;
  2         6  
  2         54  
5 2     2   18 use warnings;
  2         4  
  2         49  
6 2     2   9 use Carp;
  2         3  
  2         140  
7 2     2   11 use File::Find;
  2         2  
  2         98  
8 2     2   7 use Config;
  2         2  
  2         97  
9 2     2   679 use WWW::Selenium::Utils::Actions qw(%selenium_actions);
  2         4  
  2         6603  
10              
11             require Exporter;
12             our @ISA = qw(Exporter);
13             our @EXPORT_OK = qw(generate_suite cat parse_wikifile);
14              
15             our $VERSION = '0.09';
16              
17             sub html_header;
18             sub html_footer;
19              
20             sub generate_suite {
21 25     25 1 40873 my %opts = @_;
22              
23 25         86 my %config = parse_config();
24 25   100     138 $opts{$_} ||= $config{$_} for keys %config;
25              
26 25 50       76 croak "Must provide a directory of tests!\n" unless $opts{test_dir};
27              
28 25         88 _generate_suite( %opts );
29              
30             # create a test Suite index
31 17 100       137 create_suite_index($opts{test_dir}, $opts{index}) if $opts{index};
32             }
33              
34             sub _generate_suite {
35 25     25   65 my %opts = @_;
36 25         50 my $testdir = $opts{test_dir};
37 25         41 $testdir =~ s#/$##;
38 25 50       314 croak "$testdir is not a directory!\n" unless -d $testdir;
39 25   33     152 my $files = $opts{files} || test_files($testdir, $opts{perdir}, \%opts);
40              
41 25         58 my $suite = "$testdir/TestSuite.html";
42 25         811 my $date = localtime;
43              
44 25 50       1674 open(my $fh, ">$suite.tmp") or croak "Can't open $suite.tmp: $!";
45 25         109 print $fh html_header(title => "Test Suite",
46             text => "Generated at $date",
47             );
48              
49 25         39 my $tests_added = 0;
50 25         114 for (sort {$a cmp $b} @$files) {
  21         68  
51 42 50       193 next if /(?:\.tmp|TestSuite\.html)$/;
52              
53 42         56 my $f = $_;
54 42         71 my $fp = "$testdir/$f";
55 42 100       134 if ($f =~ /(.+)\.html$/) {
56 20         39 my $basename = $1;
57             # skip html files that we have or will generate
58 20 50       328 next if -e "$testdir/$basename.wiki";
59             # find orphaned html files
60 20         71 my $html = cat($fp);
61 20 100 66     206 if ($html =~ m#Auto-generated from $testdir/$basename\.wiki# and
62             !-e "$testdir/$basename.wiki") {
63 1 50       152 print "Deleting orphaned file $fp\n" if $opts{verbose};
64 1 50       87 unlink $fp or croak "Can't unlink $fp: $!";
65 1         6 next;
66             }
67             }
68              
69 41 100       4378 print "Adding row for $f\n" if $opts{verbose};
70 41 100       167 if (/\.wiki$/) {
71 22         110 $f = wiki2html($fp,
72             verbose => $opts{verbose},
73             base_href => $opts{base_href});
74 14         177 $f =~ s/^$testdir\///;
75 14         37 $fp = "$testdir/$f";
76             }
77 33         83 my $title = find_title($fp);
78 33         97 print $fh qq(\t
$title
79 33         58 $tests_added++;
80             }
81             #print the footer
82 17         32 print $fh html_footer();
83 17 50       544 close $fh or croak "Can't close $suite.tmp: $!";
84              
85 17 100       37 if ($tests_added) {
86             # rename into place
87 14 50       674 rename "$suite.tmp", $suite or croak "can't rename $suite.tmp $suite: $!";
88 14 50       1684 print "Created new $suite\n" if $opts{verbose};
89             }
90             else {
91 3         189 unlink "$suite.tmp";
92             }
93             }
94              
95             sub test_files {
96 25     25 0 59 my ($testdir, $perdir, $opts) = @_;
97              
98 25         42 my @tests;
99 25 100       58 if ($perdir) {
100 11         779 my @files = glob("$testdir/*");
101 11         26 foreach my $f (@files) {
102 19 100       300 if (-d $f) {
103 6         13 $opts->{test_dir} = $f;
104 6         24 generate_suite( %$opts );
105 6         12 next;
106             }
107 13         45 push @tests, $f;
108             }
109             }
110             else {
111 14     44   1020 find(sub { push @tests, $File::Find::name }, $testdir);
  44         1349  
112             }
113              
114 25 100       80 @tests = grep { !-d $_ and m#(?:wiki|html)$# } @tests;
  57         876  
115 25         46 for (@tests) {
116 42         356 s#^$testdir/?##;
117 42         105 s#^.+/tests/##;
118             }
119              
120 25         102 return \@tests;
121             }
122              
123             sub wiki2html {
124 22     22 0 86 my ($wiki, %opts) = @_;
125 22         41 my $verbose = $opts{verbose};
126 22         29 my $base_href = $opts{base_href};
127 22 100       48 $base_href =~ s#/$## if $base_href;
128              
129 22         92 (my $html = $wiki) =~ s#\.wiki$#.html#;
130              
131 22         67 my $results = parse_wikifile(filename => $wiki,
132             base_href => $base_href);
133 22 100       72 if ($results->{errors}) {
134 8         163 croak "Error parsing file $wiki:\n "
135 8         24 . join("\n ", @{$results->{errors}})
136             . "\n";
137             }
138              
139 14 50       1603 print "Generating html for ($results->{title}): $html\n" if $verbose;
140 14 50       1032 open(my $out, ">$html") or croak "Can't open $html: $!";
141 14         74 print $out html_header( title => $results->{title},
142             text => "Auto-generated from $wiki
");
143 14         22 foreach my $r (@{$results->{rows}}) {
  14         32  
144 58         302 print $out "\n\t
145             join('', map "$_
146             "
147             }
148              
149 14         330 my $now = localtime;
150 14         66 print $out html_footer("
Auto-generated from $wiki at $now\n");
151 14 50       597 close $out or croak "Can't write $html: $!";
152 14         95 return $html;
153             }
154              
155             sub parse_wikifile {
156 23     23 0 75 my %opts = @_;
157 23         37 my $filename = $opts{filename};
158 23         29 my $base_href = $opts{base_href};
159 23         35 my $include = $opts{include};
160 23         120 (my $base_dir = $filename) =~ s#(.+)/.+$#$1#;
161              
162 23         40 my $title;
163             my @rows;
164 0         0 my @errors;
165              
166             # $. and $_ are global, so we don't need to pass them in
167             # to this closure
168             my $parse_error = sub {
169 9     9   55 push @errors, "line $.: $_[0] ($_)";
170 23         95 };
171              
172 23 50       771 open(my $in, $filename) or croak "Can't open $filename: $!";
173 23         251 while(<$in>) {
174 167         484 s/^\s*//;
175 167 100 66     821 next if /^#/ or /^\s*$/;
176 122         122 chomp;
177              
178             # included files won't have a title
179 122 100 100     909 if (not defined $title and not $include) {
    100          
    100          
180 22         25 $title = $_;
181 22         69 $title =~ s#^\s*##;
182 22         39 $title =~ s#^\|(.+)\|$#$1#;
183 22         53 next;
184             }
185             elsif (/^\s* # some possible leading space
186             \|\s*([^\|]+?)\s*\| # cmd
187             (?:\s*([^\|]+?)\s*\|)? # opt1 (optional)
188             (?:\s*([^\|]+?)\s*\|)? # opt2 (optional)
189             \s*$/x) {
190 94         238 my ($cmd, $opt1, $opt2) = ($1,$2,$3);
191 94 50 0     151 $parse_error->("No command found") and next unless $cmd;
192              
193 94         102 my $numargs = (grep { defined $_ } ($opt1, $opt2));
  188         333  
194 94         169 my $expected_args = $selenium_actions{lc($cmd)};
195 94 100 100     257 if (defined $expected_args and $expected_args != $numargs) {
196 4         14 $parse_error->("Incorrect number of arguments for $cmd");
197 4         18 next;
198             }
199              
200 90 50       149 $opt1 = ' ' unless defined $opt1;
201 90 100       157 $opt2 = ' ' unless defined $opt2;
202 90 100 100     159 if ($base_href and ($cmd eq "open" or
      66        
203             $cmd =~ /(?:assert|verify)Location/)) {
204 2         7 $opt1 =~ s#^/##;
205 2         6 $opt1 = "$base_href/$opt1";
206             }
207 90         534 push @rows, [ $cmd, $opt1, $opt2 ];
208             }
209             elsif (/^\s*include\s+(.+)\s*$/) {
210 2         4 my $incl = $1;
211 2 50       20 $incl = "$base_dir/$1" unless -e $1;
212 2 100       26 unless (-e $incl) {
213 1         5 $parse_error->("Can't include $incl - file doesn't exist!");
214 1         8 next;
215             }
216 1         9 my $r = parse_wikifile( %opts, filename => $incl,
217             include => 1);
218 1 50       4 push @rows, @{$r->{rows}} if $r->{rows};
  1         4  
219 1 50       13 push @errors, @{$r->{errors}} if $r->{errors};
  0         0  
220             }
221             else {
222 4         9 $parse_error->("Invalid line");
223             }
224             }
225 23 50       238 close $in or croak "Can't close $filename: $!";
226 23 100       278 return { $title ? (title => $title) : (),
    100          
227             @errors ? (errors => \@errors) : (),
228             rows => \@rows,
229             };
230             }
231              
232             sub find_title {
233 33     33 0 39 my $filename = shift;
234              
235 33 50       961 open(my $fh, $filename) or croak "Can't open $filename: $!";
236 33         47 my $contents;
237             {
238 33         30 local $/;
  33         95  
239 33         575 $contents = <$fh>;
240             }
241 33 50       310 close $fh or croak "Can't close $filename: $!";
242              
243 33 50       70 return $filename unless $contents;
244 33 100       209 return $1 if $contents =~ m#\s*(.+)\s*#;
245 19 50       181 return $1 if $filename =~ m#^.+/(.+)\.html$#;
246 0         0 return $filename;
247             }
248              
249             sub create_suite_index {
250 3     3 0 4 my ($testdir, $index) = @_;
251 3         6 my @suites;
252 3 100   15   196 find( sub { push @suites, $File::Find::name if /TestSuite\.html$/ }, $testdir);
  15         429  
253 3 100       15 return unless @suites;
254            
255 2         12 (my $index_dir = $index) =~ s#^(.+)/.+$#$1#;
256 2 50       120 open(my $fh, ">$index.tmp") or croak "Can't open $index.tmp: $!";
257 2         7 print $fh html_header(title => "Selenium TestSuites");
258 2         5 foreach my $s (@suites) {
259 3         4 my $name = "Main";
260 3 100       47 $name = $1 if $s =~ m#\Q$testdir\E/(.+)/TestSuite\.html$#;
261 3         17 (my $link = $s) =~ s#\Q$index_dir\E/##;
262 3         12 print $fh qq(\t
$name TestSuite
263             }
264 2         5 print $fh html_footer;
265 2 50       67 close $fh or croak "Can't write $index.tmp: $!";
266 2 50       166 rename "$index.tmp", $index or croak "Can't rename $index.tmp to $index: $!";
267             }
268              
269             sub html_header {
270 41     41 0 176 my %opts = @_;
271 41   50     100 my $title = $opts{title} || 'Generic Title';
272 41   100     90 my $text = $opts{text} || '';
273              
274 41         108 my $header = <
275            
276            
277            
278             http-equiv="content-type">
279             $title
280            
281            
282             $text
283            
284            
285            
286             $title
287            
288             EOT
289 41         224 return $header;
290             }
291              
292             sub html_footer {
293 33   100 33 0 101 my $text = shift || '';
294 33         81 return <
295            
296            
297             $text
298            
299            
300             EOT
301             }
302              
303             sub cat {
304 33     33 0 21307 my $file = shift;
305 33         36 my $contents;
306 33         46 eval {
307 33 50       1011 open(my $fh, $file) or croak "Can't open $file: $!";
308             {
309 33         52 local $/;
  33         98  
310 33         686 $contents = <$fh>;
311             }
312 33 50       429 close $fh or croak "Can't close $file: $!";
313             };
314 33 50       66 warn if $@;
315 33         213 return $contents;
316             }
317              
318             sub parse_config {
319 25   66 25 0 1262 my $file = ($ENV{SELUTILS_ROOT} || $Config{prefix}) . "/etc/selutils.conf";
320 25 100       3567 return () unless -e $file;
321             # try evaling the file (current file format)
322 5 50       153 open(my $fh, $file) or croak "Can't open $file: $!";
323 5         10 my $contents;
324             {
325 5         6 local $/ = undef;
  5         18  
326 5         91 $contents = <$fh>;
327             }
328 5 50       50 close $fh or die "Can't close $file: $!";
329              
330 5         8 our $perdir;
331 5         7 our $test_dir;
332 5         7 our $index;
333             {
334 5     2   7 local $SIG{__WARN__} = sub {}; # hide eval errors
  5         35  
  2         33  
335 5         375 eval $contents;
336             }
337 5         48 my $eval_err = $@;
338              
339             # failed to eval file - try reading as an old style config
340 5 100       12 if ($eval_err) {
341 1         10 while($contents =~ /^\s*(\w+)\s*=\s*['"]?([^'"]+)['"]?\s*$/mg) {
342 2 100       6 $perdir = $2 if $1 eq 'perdir';
343 2 50       5 $index = $2 if $1 eq 'index';
344 2 100       10 $test_dir = $2 if $1 eq 'test_dir';
345             }
346 1 50       3 warn "$file eval error: $eval_err\n" unless $test_dir;
347             }
348 5         20 my %config = ( perdir => $perdir,
349             test_dir => $test_dir,
350             index => $index,
351             );
352 5         48 return %config;
353             }
354              
355             1;
356             __END__