File Coverage

blib/lib/Test/HTML/Differences.pm
Criterion Covered Total %
statement 30 96 31.2
branch 1 28 3.5
condition 1 6 16.6
subroutine 10 19 52.6
pod 0 2 0.0
total 42 151 27.8


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