File Coverage

blib/lib/Test/HTML/Form.pm
Criterion Covered Total %
statement 233 250 93.2
branch 64 94 68.0
condition 16 31 51.6
subroutine 36 37 97.3
pod 16 16 100.0
total 365 428 85.2


line stmt bran cond sub pod time code
1             package Test::HTML::Form;
2 3     3   159854 use strict;
  3         15  
  3         86  
3 3     3   14 use warnings;
  3         5  
  3         76  
4 3     3   13 no warnings 'redefine';
  3         4  
  3         108  
5              
6             =head1 NAME
7              
8             Test::HTML::Form - HTML Testing and Value Extracting
9              
10             =head1 VERSION
11              
12             1.01
13              
14             =head1 SYNOPSIS
15              
16             use Test::HTML::Form;
17              
18             my $filename = 't/form_with_errors.html';
19              
20             my $response = $ua->request($request)
21              
22             # test functions
23              
24             title_matches($filename,'Foo Bar','title matches');
25              
26             no_title($filename,'test site','no english title');
27              
28             tag_matches($response,
29             'p',
30             { class => 'formError',
31             _content => 'There is an error in this form.' },
32             'main error message appears as expected' );
33              
34             no_tag($filename,
35             'p',
36             { class => 'formError',
37             _content => 'Error' },
38             'no unexpected errors' );
39              
40              
41             text_matches($filename,'koncerty','found text : koncerty'); # check text found in file
42              
43             no_text($filename,'Concert','no text matching : Concert'); # check text found in file
44              
45             image_matches($filename,'/images/error.gif','matching image found image in HTML');
46              
47             link_matches($filename,'/post/foo.html','Found link in HTML');
48              
49             script_matches($response, qr/function someWidget/, 'found widget in JS');
50              
51             form_field_value_matches($response,'category_id', 12345678, undef, 'category_id matches');
52              
53             form_select_field_matches($filename,{ field_name => $field_name, selected => $field_value, form_name => $form_name}, $description);
54              
55             form_checkbox_field_matches($response,{ field_name => $field_name, selected => $field_value, form_name => $form_name}, $description);
56              
57             # Data extraction functions
58              
59             my $form_values = Test::HTML::Form->get_form_values({filename => $filename, form_name => 'form1'});
60              
61             my $posting_id = Test::HTML::Form->extract_text({filename => 'publish.html', pattern => 'Reference :\s(\d+)'});
62              
63             =head1 DESCRIPTION
64              
65             Test HTML pages and forms, and extract values.
66              
67             Developed for and released with permission of Slando (http://www.slando.com)
68              
69             All test functions will take either a filename or an HTTP::Response compatible object (i.e. any object with a content method)
70              
71             =cut
72              
73 3     3   593 use Data::Dumper;
  3         6587  
  3         139  
74 3     3   16 use Digest::MD5;
  3         5  
  3         104  
75              
76 3     3   2166 use HTML::TreeBuilder;
  3         93693  
  3         24  
77              
78 3     3   119 use base qw( Exporter Test::Builder::Module);
  3         6  
  3         5837  
79             our @EXPORT = qw(
80             link_matches no_link
81             image_matches no_image
82             tag_matches no_tag
83             text_matches no_text
84             script_matches
85             title_matches no_title
86             form_field_value_matches
87             form_select_field_matches
88             form_checkbox_field_matches
89             clear_test_html_form_cache
90             );
91              
92             my $Test = Test::Builder->new;
93             my $CLASS = __PACKAGE__;
94             our %parsed_files = ();
95             our %parsed_file_forms = ();
96              
97             our $VERSION = 1.01;
98              
99             =head1 FUNCTIONS
100              
101             =head2 image_matches
102              
103             Test that some HTML contains an img tag with a src attribute matching the link provided.
104              
105             image_matches($filename,$image_source,'matching image found image in HTML');
106              
107             Passes when at least one instance found, fails if no matches found.
108              
109             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
110              
111             =cut
112              
113             sub image_matches {
114 1     1 1 8 my ($filename,$link,$name) = (@_);
115 1         2 local $Test::Builder::Level = 2;
116 1         5 return tag_matches($filename,'img',{ src => $link }, $name);
117             };
118              
119              
120             =head2 no_image
121              
122             Test that some HTML doesn't contain any img tag with a src attribute matching the link provided.
123              
124             no_image($response,$image_source,'no matching image found in HTML');
125              
126             Passes when no matches found, fails if any matches found.
127              
128             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
129              
130             =cut
131              
132             sub no_image {
133 1     1 1 7 my ($filename,$link,$name) = (@_);
134 1         3 local $Test::Builder::Level = 2;
135 1         4 return no_tag($filename,'img',{ src => $link },$name);
136             };
137              
138              
139             =head2 link_matches
140              
141             Test that some HTML contains a href tag with a src attribute matching the link provided.
142              
143             link_matches($response,$link_destination,'Found link in HTML');
144              
145             Passes when at least one instance found, fails if no matches found.
146              
147             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
148              
149             =cut
150              
151             sub link_matches {
152 3     3 1 1693 my ($filename,$link,$name) = (@_);
153 3         5 local $Test::Builder::Level = 2;
154 3         17 return tag_matches($filename,['a','link'],{ href => $link },$name);
155             };
156              
157             =head2 no_link
158              
159             Test that some HTML does not contain a href tag with a src attribute matching the link provided.
160              
161             link_matches($filename,$link_destination,'Link not in HTML');
162              
163             Passes when if no matches found, fails when at least one instance found.
164              
165             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
166              
167             =cut
168              
169             sub no_link {
170 1     1 1 7 my ($filename,$link,$name) = (@_);
171 1         3 local $Test::Builder::Level = 2;
172 1         4 return no_tag($filename,'a',{ href => $link },$name);
173             };
174              
175             =head2 title_matches
176              
177             Test that some HTML contains a title tag with content matching the pattern/string provided.
178              
179             title_matches($filename,'Foo bar home page','title matches');
180              
181             Passes when at least one instance found, fails if no matches found.
182              
183             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
184              
185             =cut
186              
187             sub title_matches {
188 1     1 1 96 my ($filename,$title,$name) = @_;
189 1         3 local $Test::Builder::Level = 2;
190 1         5 return tag_matches($filename,"title", { _content => $title } ,$name);
191             };
192              
193             =head2 no_title
194              
195             Test that some HTML does not contain a title tag with content matching the pattern/string provided.
196              
197             no_title($filename,'Foo bar home page','title matches');
198              
199             Passes if no matches found, fails when at least one instance found.
200              
201             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
202              
203             =cut
204              
205             sub no_title {
206 1     1 1 9 my ($filename,$title,$name) = (@_);
207 1         2 local $Test::Builder::Level = 2;
208 1     1   6 return no_tag($filename,'title', sub { shift->as_trimmed_text =~ m/$title/ },$name);
  1         74  
209             }
210              
211              
212             =head2 tag_matches
213              
214             Test that some HTML contains a tag with content or attributes matching the pattern/string provided.
215              
216             tag_matches($filename,'a',{ href => $link },$name); # check matching tag found in file
217              
218             Passes when at least one instance found, fails if no matches found.
219              
220             Takes a list of arguments
221              
222             =over 4
223              
224             =item filename/response - string of path/name of file, or an HTTP::Response object
225              
226             =item tag type(s) - string or arrarref of strings naming which tag(s) to match
227              
228             =item attributes - hashref of attributes and strings or quoted-regexps to match
229              
230             =item comment - an optional test comment/name
231              
232             =back
233              
234             =cut
235              
236             sub tag_matches {
237 7     7 1 35 my ($filename, $tag, $attr_ref, $name) = @_;
238 7         13 my $count = 0;
239              
240 7 100       16 if (ref $tag ) {
241 4         12 foreach my $this_tag (@$tag) {
242 8         17 $count += _tag_count($filename, $this_tag, $attr_ref);
243             }
244             } else {
245 3         20 $count = _tag_count($filename, $tag, $attr_ref);
246             }
247              
248 7         52 my $tb = $CLASS->builder;
249 7         94 my $ok = $tb->ok( $count, $name);
250 7 100       3139 unless ($ok) {
251 1 50       7 my $tagname = ( ref $tag ) ? join (' or ', @$tag) : $tag ;
252 1         5 $tb->diag("Expected at least one tag of type '$tagname' in file $filename matching condition, but got 0\n");
253             }
254 7         256 return $ok;
255             }
256              
257              
258              
259             =head2 no_tag
260              
261             Test that some HTML does not contain a tag with content or attributes matching the pattern/string provided.
262              
263             no_tag($filename,'a',{ href => $link },$name); # check matching tag NOT found in file
264              
265             Passes if no matches found, fails when at least one instance found.
266              
267             Takes a list of arguments filename/response, hashref of attributes and strings or quoted-regexps to match, and optional test comment/name
268              
269             =cut
270              
271             sub no_tag {
272 4     4 1 16 my ($filename,$tag,$attr_ref,$name) = @_;
273 4         9 my $count = _tag_count($filename, $tag, $attr_ref);
274 4         20 my $tb = $CLASS->builder;
275 4         46 my $ok = $tb->is_eq( $count, 0, $name);
276 4 50       2245 unless ($ok) {
277 0         0 $tb->diag("Expected no tags of type $tag matching criteria in file $filename, but got $count\n");
278             }
279 4         12 return $ok;
280             };
281              
282             =head2 text_matches
283              
284             Test that some HTML contains some content matching the pattern/string provided.
285              
286             text_matches($filename,$text,$name); # check text found in file
287              
288             Passes when at least one instance found, fails if no matches found.
289              
290             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
291              
292             =cut
293              
294             sub text_matches {
295 1     1 1 7 my ($filename,$text,$name) = @_;
296 1         7 my $count = _count_text({filename => $filename, text => $text });
297 1         7 my $tb = $CLASS->builder;
298 1         12 my $ok = $tb->ok( $count, $name);
299 1 50       303 unless ($ok) {
300 0         0 $tb->diag("Expected HTML to contain at least one instance of text '$text' in file $filename but not found\n");
301             }
302 1         3 return $ok;
303             };
304              
305             =head2 no_text
306              
307             Test that some HTML does not contain some content matching the pattern/string provided.
308              
309             no_text($filename,$text,$name); # check text NOT found in file
310              
311             Passes if no matches found, fails when at least one instance found.
312              
313             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
314              
315             =cut
316              
317             sub no_text {
318 1     1 1 5 my ($filename,$text,$name) = @_;
319 1         5 my $count = _count_text({filename => $filename, text => $text });
320 1         11 my $tb = $CLASS->builder;
321 1         14 my $ok = $tb->is_eq( $count, 0 , $name);
322 1 50       527 unless ($ok) {
323 0         0 $tb->diag("Expected HTML to not contain text '$text' in file $filename but $count instances found\n");
324             }
325 1         3 return $ok;
326             };
327              
328              
329             =head2 script_matches
330              
331             Test that HTML script element contains text matcging that provided.
332              
333             script_matches($response, qr/function someWidget/, 'found widget in JS');
334              
335             Passes when at least one instance found, fails if no matches found.
336              
337             Takes a list of arguments filename/response, string or quoted-regexp to match, and optional test comment/name
338              
339             =cut
340              
341             sub script_matches {
342 1     1 1 10 my ($filename,$text_to_match,$name) = @_;
343 1         2 my $pattern;
344 1 50       4 if (ref($text_to_match) eq 'Regexp') {
345 1         2 $pattern = $text_to_match;
346             }
347 1         3 my $tree = _get_tree($filename);
348              
349             my @parse_args = sub {
350 1     1   88 my $elem = shift;
351 1 50       4 return 0 unless (ref $elem eq 'HTML::Element' );
352 1         3 my $ok = 0;
353 1         4 (my $text = $elem->as_HTML) =~ s/<(.|\n)*?>//g;
354 1 50       308 if ($pattern) {
355 1         6 my $ok = $text =~ m/$pattern/;
356 1   33     5 return $ok || $text =~ m/$pattern/;
357             } else {
358 0         0 $text eq $text_to_match;
359             }
360 1         8 };
361              
362 1         6 my $count = $tree->look_down( _tag => 'script', @parse_args );
363              
364 1         11 my $tb = $CLASS->builder;
365 1         13 my $ok = $tb->ok( $count, $name);
366 1 50       289 unless ($ok) {
367 0         0 $tb->diag("Expected script tag in file $filename matching $text_to_match, but got 0\n");
368             }
369 1         7 return $ok;
370             };
371              
372              
373              
374             =head2 form_field_value_matches
375              
376             Test that the HTML contains a form element with the value matching that provided.
377              
378             form_field_value_matches($filename,$field_name, $field_value, $form_name, $description);
379              
380             form_field_value_matches($filename,$field_name, qr/some pattern/, undef, 'test for foo in bar form field');
381              
382             Takes a list of arguments : filename/response, string or quoted-regexp to match, optional form_name, and optional test comment/name
383              
384             Field value argument can be a string (for exact matches) or a quoted regexp (for pattern matches)
385              
386             Use form_select_field_matches for select elements.
387              
388             Use form_checkbox_field_matches for checkbox elements
389              
390             =cut
391              
392             sub form_field_value_matches {
393 3     3 1 338 my ($filename,$field_name, $field_value, $form_name, $description) = @_;
394 3         16 my $form_fields = __PACKAGE__->get_form_values({ filename => $filename, form_name => $form_name });
395 3         15 my $tb = $CLASS->builder;
396              
397 3         33 my $elems = $form_fields->{$field_name};
398              
399 3         4 my $ok = 0;
400 3         6 foreach my $elem (@$elems) {
401 3         7 my $matches = _compare($elem,$field_value);
402 3 50       7 if ($matches) {
403 3         9 $ok = $tb->ok( $matches , $description);
404 3         914 last;
405             }
406             }
407              
408 3 50       8 unless ($ok) {
409 0         0 $tb->ok( 0 , $description);
410 0         0 $tb->diag("Expected form to contain field '$field_name' and have value of '$field_value' but not found in file $filename\n");
411             }
412 3         8 return $ok;
413             };
414              
415             =head2 form_select_field_matches
416              
417             Test that the HTML contains a form element with the value matching that provided.
418              
419             form_select_field_matches($filename,{ field_name => $field_name, selected => $field_value, form_name => $form_name}, $description);
420              
421             Takes a mixed list/ hashref of arguments :
422              
423             =over 4
424              
425             =item filename/response,
426              
427             =item hashref of search attributes, keys are : field_name, selected, form_name (optional)
428              
429             =item optional test comment/name
430              
431             =back
432              
433             Selected field value can be string or quoted regexp
434              
435             =cut
436              
437             sub form_select_field_matches {
438 3     3 1 2423 my ($filename, $field_value_args, $description) = @_;
439 3         14 my $form_fields = __PACKAGE__->get_form_values({ filename => $filename, form_name => $field_value_args->{form_name} });
440 3         18 my $tb = $CLASS->builder;
441 3         31 my $ok = 0;
442 3         6 my $field_value = $field_value_args->{selected};
443 3         6 my $field_name = $field_value_args->{field_name};
444              
445 3         8 my $select_elem = $form_fields->{$field_name}[0];
446              
447              
448 3 100       8 if ($select_elem) {
449 2 50       9 unless (UNIVERSAL::can($select_elem,'descendants')) {
450 0         0 die "$select_elem (",$select_elem->tag,") is not a select html element for field : $field_name - did you mean to call form_checkbox_field_matches ?";
451             }
452 2         3 my $selected_option;
453 2         5 foreach my $option ( $select_elem->descendants ) {
454 12 50 33     777 next unless (ref($option) && ( lc($option->tag) eq 'option') );
455 12 100       88 if ( _compare($option, $field_value) ) {
456 2         4 $selected_option = $option;
457 2         4 last;
458             }
459             }
460              
461 2   50     10 $ok = $tb->ok( $selected_option && scalar grep (m/selected/i && $selected_option->attr($_), $selected_option->all_external_attr_names), $description);
462             } else {
463 1         5 $ok = $tb->ok(0, $description);
464             }
465 3 100       1651 unless ($ok) {
466 1         6 $tb->diag("Expected form to contain field '$field_name' and have option with value of '$field_value' selected but not found in file $filename \n");
467             }
468 3         444 return $ok;
469             }
470              
471             =head2 form_checkbox_field_matches
472              
473             Test that the HTML contains a form element with the value matching that provided.
474              
475             form_checkbox_field_matches($filename,{ field_name => $field_name, selected => $field_value, form_name => $form_name}, $description);
476              
477             Takes a mixed list/ hashref of arguments :
478              
479             =over 4
480              
481             =item filename/response,
482              
483             =item hashref of search attributes, keys are : field_name, selected, form_name (optional)
484              
485             =item optional test comment/name
486              
487             =back
488              
489             Selected field value can be string or quoted regexp
490              
491             =cut
492              
493             sub form_checkbox_field_matches {
494 1     1 1 9 my ($filename, $field_value_args, $description) = @_;
495 1         6 my $form_fields = __PACKAGE__->get_form_values({ filename => $filename, form_name => $field_value_args->{form_name} });
496 1         6 my $tb = $CLASS->builder;
497              
498 1         15 my $field_value = $field_value_args->{selected};
499 1         2 my $field_name = $field_value_args->{field_name};
500 1         1 my $selected_box;
501 1   50     5 my $checkbox_elems = $form_fields->{$field_name} || [];
502              
503 1         3 foreach my $checkbox ( @$checkbox_elems ) {
504 1 50       2 if ( _compare($checkbox, $field_value) ) {
505 1         2 $selected_box = $checkbox;
506 1         2 last;
507             }
508             }
509              
510 1   50     8 my $ok = $tb->ok( $selected_box && scalar grep (m/checked/i && $selected_box->attr($_), $selected_box->all_attr_names), $description);
511 1 50       316 unless ($ok) {
512 0         0 $tb->diag("Expected form to contain field '$field_name' and have option with value of '$field_value' selected but not found in file $filename\n");
513             }
514 1         3 return $ok;
515             }
516              
517             =head2 get_form_values
518              
519             Extract form fields and their values from HTML content
520              
521             my $form_values = Test::HTML::Form->get_form_values({filename => $filename, form_name => 'form1'});
522              
523             Takes a hashref of arguments : filename (name of file or an HTTP::Response object, required), form_name (optional).
524              
525             Returns a hashref of form fields, with name as key, and arrayref of XML elements for that field.
526              
527             =cut
528              
529             sub get_form_values {
530 8     8 1 586 my $class = shift;
531 8         10 my $args = shift;
532 3     3   25 no warnings 'uninitialized';
  3         6  
  3         4218  
533 8         13 my $form_name = $args->{form_name};
534 8         16 my $internal_form_name = $form_name . ' form';
535 8 100       34 if ($parsed_file_forms{$args->{filename}}{$internal_form_name}) {
536 5 100       13 if ($parsed_files{$args->{filename}}{md5} eq _get_md5_sum($args->{filename})) {
537 4         17 return $parsed_file_forms{$args->{filename}}{$internal_form_name};
538             }
539             }
540              
541 4         11 my $tree = _get_tree($args->{filename});
542 4         8 my $form_fields = { };
543             my ($form) = $tree->look_down('_tag', 'form',
544             sub {
545 4     4   471 my $form = shift;
546 4 50       12 if ($form_name) {
547 0 0       0 return 1 if $form->attr('name') eq $form_name;
548 0 0       0 return 1 if $form->attr('id') eq $form_name;
549             } else {
550 4         8 return 1;
551             }
552             }
553 4         31 );
554 4 50       1155 if (ref $form) {
555 4         25 my @form_nodes = $form->descendants();
556 4         3521 foreach my $node (@form_nodes) {
557 130 50       965 next unless (ref($node));
558 130 100       196 if (lc($node->tag) =~ /^(input|select|textarea|button)$/i) {
559 24 100       192 if (lc $node->attr('type') =~ /(radio|checkbox)/) {
560 6         88 push (@{$form_fields->{$node->attr('name')}},$node);
  6         29  
561             } else {
562 18         205 $form_fields->{$node->attr('name')} = [ $node ];
563             }
564             }
565             }
566             }
567 4         54 $parsed_file_forms{$args->{filename}}{$internal_form_name} = $form_fields;
568              
569 4         9 return $form_fields;
570             }
571              
572             =head2 extract_text
573              
574             my $posting_id = Test::HTML::Form->extract_text({filename => 'publish.html', pattern => 'Reference :\s(\d+)'});
575              
576             =cut
577              
578             sub extract_text {
579 1     1 1 8 my $class = shift;
580 1         2 my $args = shift;
581 1         4 my $tree = _get_tree($args->{filename});
582 1         3 my $pattern = $args->{pattern};
583             my ($node) = $tree->look_down( sub {
584 76     76   5382 my $thisnode = shift;
585 76         140 $thisnode->normalize_content;
586 76 100       1470 return 1 if ($thisnode->as_trimmed_text =~ m/$pattern/i);
587 1         9 });
588 1         39 my ($match) = ($node->as_trimmed_text =~ m/$pattern/i);
589              
590 1         616 return $match;
591             }
592              
593             sub _clear_test_html_form_cache {
594 0     0   0 %parsed_files = ();
595 0         0 %parsed_file_forms = ();
596             }
597              
598             #
599             ##########################################
600             # Private / Internal methods and functions
601              
602             sub _compare {
603 16     16   25 my ($elem, $field_value) = @_;
604 16 50 33     52 unless ($elem && (ref$elem eq 'HTML::Element') ) {
605 0         0 warn "_compare passed $elem and value $field_value, $elem should be HTML::Element but is : ", ref $elem, "\n";
606 0         0 return 0 ;
607             }
608              
609 16 50       26 my $have_regexp = ( ref($field_value) eq 'Regexp' ) ? 1 : 0;
610 16         28 my $value = $elem->attr('value') ;
611 16 100       165 unless (defined $value) {
612 11         21 $value = $elem->as_trimmed_text;
613             }
614 16         392 my $ok;
615 16 50       24 if ($have_regexp) {
616 0 0 0     0 $ok = ( $elem && $value =~ m/$field_value/ ) ? 1 : 0 ;
617             } else {
618 16 100 66     50 $ok = ( $elem && $value eq $field_value ) ? 1 : 0 ;
619             }
620 16         29 return $ok
621             }
622              
623             sub _tag_count {
624 15     15   29 my ($filename, $tag, $attr_ref) = @_;
625 15         31 my $tree = _get_tree($filename);
626 15         27 my @parse_args = ();
627 15 100       31 if ( ref $attr_ref eq 'HASH' ) {
628 14         16 my $pattern;
629 14 100       44 if (ref($attr_ref->{_content}) eq 'Regexp') {
630 3         5 $pattern = $attr_ref->{_content};
631 3         6 delete $attr_ref->{_content};
632             }
633              
634 14         42 @parse_args = %$attr_ref ;
635 14 100       29 if ($pattern) {
636             push( @parse_args, sub {
637 2 50   2   270 return 0 unless (ref $_[0] eq 'HTML::Element' );
638 2         7 return $_[0]->as_trimmed_text =~ m/$pattern/;
639 3         16 } );
640             }
641             } else {
642 1         2 @parse_args = $attr_ref ;
643             }
644 15         66 my $count = $tree->look_down( _tag => $tag, @parse_args );
645              
646 15   100     6874 return $count || 0;
647             }
648              
649              
650             sub _count_text {
651 2     2   5 my $args = shift;
652 2         4 my $tree = _get_tree($args->{filename});
653 2         4 my $text = $args->{text};
654             my $count = $tree->look_down( sub {
655 77     77   5438 my $node = shift;
656 77         142 $node->normalize_content;
657 77 100       1459 return 1 if ($node->as_trimmed_text =~ m/$text/);
658 2         14 });
659 2   100     693 return $count || 0;
660             }
661              
662             sub _get_tree {
663 23     23   31 my $filename = shift;
664              
665 23 100       54 unless ($parsed_files{$filename}) {
666 3         7 return _parse_tree($filename);
667             }
668              
669 20 100       44 if ($parsed_files{$filename}{md5} eq _get_md5_sum($filename)) {
670 19         61 return $parsed_files{$filename}{tree};
671             } else {
672 1         4 $parsed_file_forms{$filename} = ();
673 1         4 return _parse_tree($filename);
674             }
675              
676 0         0 return $parsed_files{$filename};
677             }
678              
679             sub _parse_tree {
680 4     4   5 my $filename = shift;
681 4         24 my $tree = HTML::TreeBuilder->new;
682 4         1206 $tree->store_comments(1);
683 4 100 66     65 if (ref $filename && $filename->can('content')) {
684 2         7 $tree->parse_content($filename->content);
685             } else {
686 2 50       41 die "can't find file $filename" unless (-f $filename);
687 2         26 $tree->parse_file($filename);
688             }
689 4         56939 $parsed_files{$filename}{md5} = _get_md5_sum($filename);
690 4         34 $parsed_files{$filename}{tree} = $tree;
691 4         14 return $tree;
692             }
693              
694             sub _get_md5_sum {
695 29     29   36 my $filename = shift;
696 29         151 my $digester = Digest::MD5->new;
697 29 100 66     96 if (ref $filename && $filename->can('content')) {
698 4         12 $digester->add($filename->content);
699             } else {
700 25 50       412 die "can't find file $filename" unless (-f $filename);
701 25 50       831 open (my $fh, '<', $filename) or die "Can't open '$filename': $!";
702 25         75 binmode ($fh);
703 25         766 $digester->addfile($fh);
704 25         275 close $fh;
705             }
706 29         157 my $md5 = $digester->digest;
707 29         162 return $md5;
708             }
709              
710             =head1 SEE ALSO
711              
712             =over 4
713              
714             =item Test::HTML::Content
715              
716             =item HTML::TreeBuilder
717              
718             =item Test::HTTP::Response
719              
720             =back
721              
722             =head1 AUTHOR
723              
724             Aaron Trevena
725              
726             =head1 BUGS
727              
728             Please report any bugs or feature requests to http://rt.cpan.org
729              
730             =head1 COPYRIGHT & LICENSE
731              
732             Copyright 2008 Slando.
733             Copyright 2009 Aaron Trevena.
734              
735             This library is free software; you can redistribute it and/or modify
736             it under the same terms as Perl itself, either Perl version 5.8.8 or,
737             at your option, any later version of Perl 5 you may have available.
738              
739             =cut
740              
741              
742             1;