File Coverage

blib/lib/Test/XML/Simple.pm
Criterion Covered Total %
statement 121 125 96.8
branch 32 48 66.6
condition 1 3 33.3
subroutine 19 21 90.4
pod 8 8 100.0
total 181 205 88.2


line stmt bran cond sub pod time code
1             package Test::XML::Simple;
2              
3 9     9   1449157 use strict;
  9         25  
  9         349  
4 9     9   54 use warnings;
  9         22  
  9         738  
5              
6             our $VERSION = '1.06';
7              
8 9     9   58 use Test::Builder;
  9         24  
  9         273  
9 9     9   2614 use Test::More;
  9         29351  
  9         75  
10 9     9   9308 use Test::LongString;
  9         24195  
  9         64  
11 9     9   7590 use XML::LibXML;
  9         561196  
  9         71  
12              
13             my $Test = Test::Builder->new();
14             my $Xml;
15              
16             sub import {
17 8     8   93 my $self = shift;
18 8         27 my $caller = caller;
19 9     9   2373 no strict 'refs';
  9         25  
  9         14129  
20 8         23 *{$caller.'::xml_valid'} = \&xml_valid;
  8         87  
21 8         18 *{$caller.'::xml_node'} = \&xml_node;
  8         31  
22 8         15 *{$caller.'::xml_is'} = \&xml_is;
  8         29  
23 8         16 *{$caller.'::xml_is_long'} = \&xml_is_long;
  8         28  
24 8         13 *{$caller.'::xml_is_deeply'} = \&xml_is_deeply;
  8         33  
25 8         39 *{$caller.'::xml_is_deeply_long'} = \&xml_is_deeply_long;
  8         25  
26 8         15 *{$caller.'::xml_like'} = \&xml_like;
  8         29  
27 8         13 *{$caller.'::xml_like_long'} = \&xml_like_long;
  8         31  
28              
29 8         58 $Test->exported_to($caller);
30 8         119 $Test->plan(@_);
31             }
32              
33             sub xml_valid($;$) {
34 2     2 1 133581 my ($xml, $comment) = @_;
35 2         8 my $parsed_xml = _valid_xml($xml);
36 2 50       52 return 0 unless $parsed_xml;
37              
38 2         16 ok $parsed_xml, $comment;
39             }
40              
41             sub _valid_xml {
42 22     22   48 my $xml = shift;
43              
44 22         50 local $Test::Builder::Level = $Test::Builder::Level + 2;
45 22 50       73 return fail("XML is not defined") unless defined $xml;
46 22 50       66 return fail("XML is missing") unless $xml;
47 22 100       60 if ( ref $xml ) {
48 1 50       5 return fail("accept only 'XML::LibXML::Document' as object") unless ref $xml eq 'XML::LibXML::Document';
49 1         2 $Xml = $xml;
50             }
51             else {
52 21 50 33     200 return fail("string can't contain XML: no tags")
53             unless ($xml =~ //);
54 21         43 eval { $Xml = XML::LibXML->new->parse_string($xml); };
  21         137  
55 21 50       5487 do { chomp $@; return fail($@) } if $@;
  0         0  
  0         0  
56             }
57 22         99 return $Xml;
58             }
59              
60             sub _find {
61 18     18   56 my ($xml_xpath, $xpath) = @_;
62 18         81 my @nodeset = $xml_xpath->findnodes($xpath);
63 18         670 local $Test::Builder::Level = $Test::Builder::Level + 2;
64 18 100       75 return fail("Couldn't find $xpath") unless @nodeset;
65 16 50       57 wantarray ? @nodeset : \@nodeset;
66             }
67              
68              
69             sub xml_node($$;$) {
70 4     4 1 149201 my ($xml, $xpath, $comment) = @_;
71              
72 4         15 my $parsed_xml = _valid_xml($xml);
73 4 50       58 return 0 unless $parsed_xml;
74              
75 4         31 my $nodeset = _find($parsed_xml, $xpath);
76 4 100       2174 return 0 if !$nodeset;
77              
78 2         15 ok(scalar @$nodeset, $comment);
79             }
80              
81              
82             sub xml_is($$$;$) {
83 7     7 1 387563 return _xml_is( \&is_string, @_ );
84             }
85              
86             sub xml_is_long($$$;$) {
87 2     2 1 9397 _xml_is(\&is, @_);
88             }
89              
90             sub _xml_is {
91 9     9   32 my ($comp_sub, $xml, $xpath, $value, $comment) = @_;
92              
93 9         37 local $Test::Builder::Level = $Test::Builder::Level + 2;
94 9         30 my $parsed_xml = _valid_xml($xml);
95 9 50       138 return 0 unless $parsed_xml;
96              
97 9         69 my $nodeset = _find($parsed_xml, $xpath);
98 9 50       91 return 0 if !$nodeset;
99              
100 9         17 my $ok = 1;
101 9         25 foreach my $node (@$nodeset) {
102 9         54 my @kids = $node->getChildNodes;
103 9         195 my $node_ok;
104 9 100       26 if (@kids) {
105 6         133 $node_ok = $comp_sub->( $kids[0]->toString, $value, $comment );
106             }
107             else {
108 3         55 my $got = $node->toString;
109 3         28 $got =~ s/^.*="(.*)"/$1/;
110 3         13 $node_ok = is $got, $value, $comment;
111             }
112              
113             # returns NOT OK if even one of tests fails
114 9 100       9450 $ok = 0 unless $node_ok;
115             }
116              
117 9         45 return $ok;
118             }
119              
120             sub xml_is_deeply($$$;$) {
121 2     2 1 226853 _xml_is_deeply(\&is_string, @_);
122             }
123              
124             sub xml_is_deeply_long($$$;$) {
125 0     0 1 0 _xml_is_deeply(\&is, @_);
126             }
127              
128             sub _xml_is_deeply {
129 2     2   9 my ($is_sub, $xml, $xpath, $candidate, $comment) = @_;
130              
131 2         7 my $parsed_xml = _valid_xml($xml);
132 2 50       63 return 0 unless $parsed_xml;
133              
134 2         16 my $candidate_xp;
135 2         5 eval {$candidate_xp = XML::LibXML->new->parse_string($candidate) };
  2         8  
136 2 50       373 return 0 unless $candidate_xp;
137              
138 2         23 my $parsed_thing = $parsed_xml->findnodes($xpath)->[0];
139 2         215 my $candidate_thing = $candidate_xp->findnodes('/')->[0];
140              
141 2 100       112 $candidate_thing = $candidate_thing->documentElement
142             if $parsed_thing->isa('XML::LibXML::Element');
143              
144 2         55 $is_sub->($parsed_thing->toString,
145             $candidate_thing->toString,
146             $comment);
147             }
148              
149             sub xml_like($$$;$) {
150 5     5 1 247513 _xml_like(\&like_string, @_);
151             }
152              
153             sub xml_like_long($$$;$) {
154 0     0 1 0 _xml_like(\&like, @_);
155             }
156              
157             sub _xml_like {
158 5     5   18 my ($like_sub, $xml, $xpath, $regex, $comment) = @_;
159              
160 5         34 my $parsed_xml = _valid_xml($xml);
161 5 50       106 return 0 unless $parsed_xml;
162              
163 5         42 my $nodeset = _find($parsed_xml, $xpath);
164 5 50       25 return 0 if !$nodeset;
165              
166 5         14 foreach my $node (@$nodeset) {
167 5         34 my @kids = $node->getChildNodes;
168 5         87 my $found;
169 5 100       11 if (@kids) {
170 4         10 foreach my $kid (@kids) {
171 4 100       98 if ($kid->toString =~ /$regex/) {
172 2         5 $found = 1;
173 2         22 return $like_sub->($kid->toString, $regex, $comment);
174             }
175             }
176 2 50       7 if (! $found) {
177 2 50       7 $comment = "(no comment)" unless defined $comment;
178 2         5 local $Test::Builder::Level = $Test::Builder::Level + 2;
179 2         15 return ok(0, "$comment - no match in tag contents (including CDATA)");
180             }
181             }
182             else {
183 1         31 my $got = $node->toString;
184 1         14 $got =~ s/^.*="(.*)"/$1/;
185 1         3 local $Test::Builder::Level = $Test::Builder::Level + 2;
186 1         6 return $like_sub->( $got, $regex, $comment );
187             }
188             }
189             }
190              
191             1;
192             __END__