File Coverage

blib/lib/XML/Assert.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             ## ----------------------------------------------------------------------------
2             # Copyright (C) 2010 NZ Registry Services
3             ## ----------------------------------------------------------------------------
4             package XML::Assert;
5              
6 8     8   275593 use XML::LibXML;
  0            
  0            
7             use Any::Moose;
8              
9             our $VERSION = '0.03';
10             our $VERBOSE = $ENV{XML_ASSERT_VERBOSE} || 0;
11              
12             my $PARSER = XML::LibXML->new();
13              
14             has 'error' =>
15             is => "rw",
16             isa => "Str",
17             clearer => "_clear_error",
18             ;
19              
20             sub _self {
21             my $args = shift;
22             if ( ref $args->[0] eq __PACKAGE__ ) {
23             return shift @$args;
24             }
25             elsif ( $args->[0] eq __PACKAGE__ ) {
26             return do { shift @$args }->new();
27             }
28             return __PACKAGE__->new();
29             }
30              
31             # a hashref of all the namespaces being used (or asked for in the XPath)
32             has 'xmlns' =>
33             is => "rw",
34             isa => "HashRef[Str]",
35             ;
36              
37             has 'error' =>
38             is => "rw",
39             isa => "Str",
40             clearer => "_clear_error",
41             ;
42              
43             sub register_ns {
44             my ($self, $doc) = @_;
45              
46             if ( my $xmlns = $self->xmlns ) {
47             my $xpc = XML::LibXML::XPathContext->new($doc);
48             $xpc->registerNs($_ => $xmlns->{$_})
49             for keys %$xmlns;
50             # do the test against the XPath Context rather than the Document
51             $doc = $xpc;
52             }
53             return $doc;
54             }
55              
56             # assert_xpath_count
57             sub assert_xpath_count {
58             my $self = _self(\@_);
59             my ($doc, $xpath, $count) = @_;
60              
61             $doc = $self->register_ns($doc);
62              
63             my ($nodes) = $doc->find($xpath);
64             print 'assert_xpath_count: Found ' . (scalar @$nodes) . "\n" if $VERBOSE;
65             unless ( @$nodes == $count ) {
66             die "XPath '$xpath' has " . (scalar @$nodes) . " " . $self->_plural(scalar @$nodes, 'node') . ", not $count as expected";
67             }
68              
69             return 1;
70             }
71              
72             sub is_xpath_count {
73             my $self = _self(\@_);
74             my ($doc, $xpath, $count) = @_;
75              
76             $self->_clear_error();
77             eval { $self->assert_xpath_count($doc, $xpath, $count) };
78             if ( $@ ) {
79             $self->error($@);
80             return;
81             }
82             return 1;
83             }
84              
85             # assert_xpath_value_match
86             sub assert_xpath_value_match {
87             my $self = _self(\@_);
88             my ($doc, $xpath, $match) = @_;
89              
90             $doc = $self->register_ns($doc);
91              
92             # firstly, check that the node actually exists
93             my ($nodes) = $doc->find($xpath);
94             print 'assert_xpath_value_match: Found ' . (scalar @$nodes) . "\n" if $VERBOSE;
95             unless ( @$nodes == 1 ) {
96             die "XPath '$xpath' matched " . (scalar @$nodes) . " nodes when we expected to match one";
97             }
98              
99             # check the value is what we expect
100             my $node = $nodes->[0];
101             print "assert_xpath_value_match: This node's value : " . $node->string_value() . "\n" if $VERBOSE;
102             unless ( $node->string_value() ~~ $match ) {
103             die "XPath '$xpath' doesn't match '$match' as expected, instead it is '" . $node->string_value() . "'";
104             }
105              
106             return 1;
107             }
108              
109             sub does_xpath_value_match {
110             my $self = _self(\@_);
111             my ($doc, $xpath, $match) = @_;
112              
113             $self->_clear_error();
114             eval { $self->assert_xpath_value_match($doc, $xpath, $match) };
115             if ( $@ ) {
116             $self->error($@);
117             return;
118             }
119             return 1;
120             }
121              
122             # assert_xpath_values_match
123             sub assert_xpath_values_match {
124             my $self = _self(\@_);
125             my ($doc, $xpath, $match) = @_;
126              
127             $doc = $self->register_ns($doc);
128              
129             # firstly, check that the node actually exists
130             my ($nodes) = $doc->find($xpath);
131             print 'assert_xpath_values_match: Found ' . (scalar @$nodes) . "\n" if $VERBOSE;
132             unless ( @$nodes ) {
133             die "XPath '$xpath' matched no nodes when we expected to match at least one";
134             }
135              
136             # check the values are what we expect
137             my $i = 0;
138             foreach my $node ( @$nodes ) {
139             print "assert_xpath_value_match: This node's value : " . $node->string_value() . "\n" if $VERBOSE;
140             unless ( $node->string_value() ~~ $match ) {
141             die "Elment $i of XPath '$xpath' doesn't match '$match' as expected, instead it is '" . $node->string_value() . "'";
142             }
143             $i++;
144             }
145              
146             return 1;
147             }
148              
149             sub do_xpath_values_match {
150             my $self = _self(\@_);
151             my ($doc, $xpath, $match) = @_;
152              
153             $self->_clear_error();
154             eval { $self->assert_xpath_values_match($doc, $xpath, $match) };
155             if ( $@ ) {
156             $self->error($@);
157             return;
158             }
159             return 1;
160             }
161              
162             # assert_attr_value_match
163             sub assert_attr_value_match {
164             my $self = _self(\@_);
165             my ($doc, $xpath, $attr, $match) = @_;
166              
167             $doc = $self->register_ns($doc);
168              
169             # firstly, check that the node actually exists
170             my ($nodes) = $doc->find($xpath);
171             print 'assert_attr_value_match: Found ' . (scalar @$nodes) . "\n" if $VERBOSE;
172             unless ( @$nodes == 1 ) {
173             die "XPath '$xpath' matched " . (scalar @$nodes) . " nodes when we expected to match one";
174             }
175              
176             # check that this node has this attribute
177             my $node = $nodes->[0];
178             my $value = $node->getAttribute( $attr );
179             print "assert_xpath_value_match: This attr's value : " . $value . "\n" if $VERBOSE;
180             unless ( $value ~~ $match ) {
181             die "XPath '$xpath', attribute '$attr' doesn't match '$match' as expected, instead it is '" . $value . "'";
182             }
183              
184             return 1;
185             }
186              
187             sub does_attr_value_match {
188             my $self = _self(\@_);
189             my ($doc, $xpath, $attr, $match) = @_;
190              
191             $self->_clear_error();
192             eval { $self->assert_attr_value_match($doc, $xpath, $attr, $match) };
193             if ( $@ ) {
194             $self->error($@);
195             return;
196             }
197             return 1;
198              
199             }
200              
201             # assert_attr_values_match
202             sub assert_attr_values_match {
203             my $self = _self(\@_);
204             my ($doc, $xpath, $attr, $match) = @_;
205              
206             $doc = $self->register_ns($doc);
207              
208             # firstly, check that the node actually exists
209             my ($nodes) = $doc->find($xpath);
210             print 'assert_attr_values_match: Found ' . (scalar @$nodes) . "\n" if $VERBOSE;
211             unless ( @$nodes ) {
212             die "XPath '$xpath' matched no nodes when we expected to match at least one";
213             }
214              
215             # check the values are what we expect
216             my $i = 0;
217             foreach my $node ( @$nodes ) {
218             my $value = $node->getAttribute( $attr );
219             print "assert_xpath_values_match: This attr's value : " . $value . "\n" if $VERBOSE;
220             unless ( $value ~~ $match ) {
221             die "Attribute '$attr' of element $i of XPath '$xpath' doesn't match '$match' as expected, instead it is '" . $value . "'";
222             }
223             $i++;
224             }
225              
226             return 1;
227             }
228              
229             sub do_attr_values_match {
230             my $self = _self(\@_);
231             my ($doc, $xpath, $attr, $match) = @_;
232              
233             $self->_clear_error();
234             eval { $self->assert_attr_values_match($doc, $xpath, $attr, $match) };
235             if ( $@ ) {
236             $self->error($@);
237             return;
238             }
239             return 1;
240              
241             }
242              
243             # private functions
244             sub _plural {
245             my ($class, $number, $single, $plural) = @_;
246              
247             return $number == 1 ? $single : defined $plural ? $plural : "${single}s";
248             }
249              
250             1;
251             __END__