File Coverage

blib/lib/Test/HTML/Differences.pm
Criterion Covered Total %
statement 85 96 88.5
branch 18 28 64.2
condition 4 6 66.6
subroutine 18 19 94.7
pod 0 2 0.0
total 125 151 82.7


line stmt bran cond sub pod time code
1             package Test::HTML::Differences;
2              
3 3     3   121205 use strict;
  3         6  
  3         99  
4 3     3   15 use warnings;
  3         4  
  3         94  
5 3     3   1430 use parent qw(Exporter);
  3         832  
  3         15  
6 3     3   2067 use HTML::Parser;
  3         18077  
  3         146  
7 3     3   27 use HTML::Entities;
  3         6  
  3         258  
8 3     3   1391 use Text::Diff;
  3         18871  
  3         183  
9 3     3   1767 use Text::Diff::Table;
  3         43873  
  3         237  
10 3     3   1230 use Test::Differences;
  3         11430  
  3         712  
11              
12             our $VERSION = '0.05';
13              
14             our @EXPORT = qw(
15             eq_or_diff_html
16             );
17              
18             sub import {
19 3     3   33 my $class = shift;
20 3 50 33     17 if ($_[0] && $_[0] eq '-color') {
21 0         0 shift @_;
22 0         0 eval "use Test::Differences::Color"; ## no critic
23 0 0       0 $@ and die $@;
24             }
25 3         3605 __PACKAGE__->export_to_level(1, @_);
26             }
27              
28             sub eq_or_diff_html ($$;$) { ## no critic
29 6     6 0 14402 my ($got_raw, $expected_raw, $desc) = @_;
30              
31 6         14 my $got = normalize_html($got_raw);
32 6         11 my $expected = normalize_html($expected_raw);
33              
34 6         10 my $got_pretty = normalize_html($got_raw, 1);
35 6         10 my $expected_pretty = normalize_html($expected_raw, 1);
36              
37 3     3   22 no warnings 'redefine';
  3         6  
  3         2793  
38 6         8 my $orig = \&Text::Diff::Table::file_footer;
39             local *Text::Diff::Table::file_footer = sub {
40 0     0   0 my ($self, $seqa, $seqb, $options) = @_;
41 0         0 my $elts = $self->{ELTS};
42 0         0 for my $elt (@$elts) {
43 0 0       0 next if $elt->[-1] eq 'bar';
44 0 0       0 $elt->[1] = $got_pretty->[$elt->[0]] unless $elt->[-1] eq 'B';
45 0 0       0 $elt->[3] = $expected_pretty->[$elt->[2]] unless $elt->[-1] eq 'A';
46             }
47 0         0 $orig->(@_);
48 6         31 };
49              
50 6         9 local $Test::Builder::Level = $Test::Builder::Level + 1;
51 6         17 table_diff();
52 6         48 eq_or_diff($got, $expected, $desc);
53             }
54              
55             sub normalize_html {
56 32     32 0 18918 my ($s, $pretty) = @_;
57              
58 32         56 my $root = [ root => {} => [] ];
59 32         38 my $stack = [ $root ];
60             my $p = HTML::Parser->new(
61             api_version => 3,
62             handlers => {
63             start => [
64             sub {
65 33     33   163 my ($tagname, $attr) = @_;
66 33         60 my $e = [
67             $tagname => $attr => []
68             ];
69 33         31 push @{ $stack->[-1]->[2] }, $e;
  33         57  
70 33         121 push @$stack, $e;
71             },
72             "tagname, attr"
73             ],
74             end => [
75             sub {
76 33     33   150 pop @$stack;
77             },
78             "tagname",
79             ],
80             comment => [
81             sub {
82 10     10   13 my ($text) = @_;
83 10         8 push @{ $stack->[-1]->[2] }, $text;
  10         42  
84             },
85             "text"
86             ],
87             text => [
88             sub {
89 66     66   79 my ($dtext) = @_;
90 66         188 $dtext =~ s/^\s+|\s+$//g;
91 66 100       207 push @{ $stack->[-1]->[2] }, encode_entities($dtext) if $dtext =~ /\S/;
  23         72  
92             },
93 32         616 "dtext"
94             ]
95             }
96             );
97 32         1152 $p->unbroken_text(1);
98 32         56 $p->empty_element_tags(1);
99 32         194 $p->parse($s);
100 32         102 $p->eof;
101              
102 32 100   40   174 my $indent = $pretty ? sub { " " x shift() . sprintf(shift, @_) } : sub { shift; sprintf(shift, @_) };
  40         191  
  22         18  
  22         81  
103              
104 32         36 my $ret = [];
105 32         33 my $walker; $walker = sub {
106 65     65   79 my ($parent, $level) = @_;
107 65         88 my ($tag, $attr, $children) = @$parent;
108              
109 65         207 my $a = join ' ', map { sprintf('%s="%s"', $_, encode_entities($attr->{$_})) } sort { $a cmp $b } keys %$attr;
  30         241  
  10         24  
110 65   100     380 my $has_element = @$children > 1 || grep { ref($_) } @$children;
111 65 100       88 if ($has_element) {
112 39 100       90 push @$ret, $indent->($level, '<%s%s>', $tag, $a ? " $a" : "") unless $tag eq 'root';
    100          
113 39         53 for my $node (@$children) {
114 55 100       82 if (ref($node)) {
115 33         186 $walker->($node, $level + 1);
116             } else {
117 22         39 push @$ret, $indent->($level + 1, '%s', $node);
118             }
119             }
120 39 100       91 push @$ret, $indent->($level, '', $tag) unless $tag eq 'root';
121             } else {
122 26 50       44 if ($tag eq 'root') {
123 0         0 push @$ret, join(' ', @$children);
124             } else {
125 26 100       104 push @$ret, $indent->($level, '<%s%s>%s', $tag, $a ? " $a" : "", join(' ', @$children), $tag);
126             }
127             }
128 32         140 };
129 32         57 $walker->($root, -1);
130              
131 32         348 $ret;
132             }
133              
134              
135             1;
136             __END__