File Coverage

blib/lib/Test/XML/Simple.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


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