Skip to content

Commit

Permalink
Removed leading "xpath_" from method names
Browse files Browse the repository at this point in the history
Also added support for multiple namespace prefixes, and tweaked the docs on namespaces.
  • Loading branch information
theory committed Aug 30, 2009
1 parent 1ce8e05 commit 2b89620
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 70 deletions.
70 changes: 39 additions & 31 deletions lib/Test/XPath.pm
Expand Up @@ -10,14 +10,18 @@ sub new {
my ($class, %p) = @_;
my $doc = delete $p{doc} || _doc(\%p);
my $xpc = XML::LibXML::XPathContext->new( $doc->documentElement );
$xpc->registerNs( %{ $p{xmlns} }) if $p{xmlns};
if (my $ns = $p{xmlns}) {
while (my ($k, $v) = each %{ $ns }) {
$xpc->registerNs( $k => $v );
}
}
return bless {
xpc => $xpc,
node => $doc->documentElement,
};
}

sub xpath_ok {
sub ok {
my ($self, $xpath, $code, $desc) = @_;
my $xpc = $self->{xpc};
my $Test = Test::Builder->new;
Expand Down Expand Up @@ -47,23 +51,23 @@ sub xpath_ok {
sub node { shift->{node} }
sub xpc { shift->{xpc} }

sub xpath_is {
sub is {
Test::Builder::new->is_eq( _findv(shift, shift), @_);
}

sub xpath_isnt {
sub isnt {
Test::Builder::new->isnt_eq( _findv(shift, shift), @_);
}

sub xpath_like {
sub like {
Test::Builder::new->like( _findv(shift, shift), @_);
}

sub xpath_unlike {
sub unlike {
Test::Builder::new->unlike( _findv(shift, shift), @_);
}

sub xpath_cmp_ok {
sub cmp_ok {
Test::Builder::new->cmp_ok( _findv(shift, shift), @_);
}

Expand Down Expand Up @@ -132,19 +136,19 @@ Test::XPath - Test XML and HTML content and structure with XPath expressions
no_network => 1,
);
$tx->xpath_ok( $xpath, $description );
$tx->xpath_is( $xpath, $want, $description );
$tx->ok( $xpath, $description );
$tx->is( $xpath, $want, $description );
# Recursing into a document:
my @css = qw(foo.css bar.css);
$tx->xpath_ok( '/html/head/style', sub {
shift->xpath_is( './@src', shift @css);
$tx->ok( '/html/head/style', sub {
shift->is( './@src', shift @css);
}, $description);
=head1 Description
Use the power of the XPath syntax supported by XML::LibXML to validate the
structure of your XML and HTML documents.
Use the power of XPath expressions to validate the structure of your XML and
HTML documents.
=head2 Interface
Expand All @@ -168,8 +172,8 @@ is passed.
file => 'rss.xml',
Name of the file containing the XML to be parsed and tested. Required unless
the C<xml> or C<doc> option is passed.
Name of a file containing the XML to be parsed and tested. Required unless the
C<xml> or C<doc> option is passed.
=item doc
Expand All @@ -187,9 +191,13 @@ XML::LibXML's HTML parser will be used instead of the XML parser.
=item xmlns
xmlns => { x => 'http://www.w3.org/1999/xhtml' },
xmlns => {
x => 'http://www.w3.org/1999/xhtml',
a => 'http://www.w3.org/2007/app',
},
Default XML namespace to be used in the XPath queries.
Set up prefixes for XML namespaces. Required if your XML uses namespaces and
you want to write reasonable XPath expressions.
=item options
Expand All @@ -201,33 +209,33 @@ L<XML::LibXML::Parser options|XML::LibXML::Parser/"PARSER OPTIONS">, such as
=back
=head3 xpath_is
=head3 is
$xp->xpath_is('/html/head/title', 'Welcome');
$xp->is('/html/head/title', 'Welcome');
=head3 xpath_isnt
=head3 isnt
$xp->xpath_isnt('/html/head/link[@type]', 'hello');
$xp->isnt('/html/head/link[@type]', 'hello');
=head3 xpath_like
=head3 like
$xp->xpath_like('/html/head/title', qr/^Foobar Inc.: .+/);
$xp->like('/html/head/title', qr/^Foobar Inc.: .+/);
=head3 xpath_unlike
=head3 unlike
$xp->xpath_unlike()
$xp->unlike()
=head3 xpath_cmp_ok
=head3 cmp_ok
$xp->xpath_cmp_ok()
$xp->cmp_ok()
=head3 xpath_ok
=head3 ok
$xp->xpath_ok( '//foo/bar', 'Should have bar element under foo element' );
$xp->xpath_ok( '//assets/story', sub {
$xp->ok( '//foo/bar', 'Should have bar element under foo element' );
$xp->ok( '//assets/story', sub {
my $i;
for my $story (@_) {
$story->xpath_is('[@id]/text()', ++$i, "ID should be $i in story" );
$story->is('[@id]/text()', ++$i, "ID should be $i in story" );
}
}, 'Should have story elements' );
Expand Down
40 changes: 20 additions & 20 deletions t/simple.t
Expand Up @@ -13,50 +13,50 @@ ok my $xp = Test::XPath->new(
is_html => 1,
), 'Create Test::XPath object';

# Try successful xpath_ok.
# Try successful ok.
test_out( 'ok 1 - whatever');
$xp->xpath_ok('/html/head/title', 'whatever');
test_test('xpath_ok works');
$xp->ok('/html/head/title', 'whatever');
test_test('ok works');

# Try failed xpath_ok.
# Try failed ok.
test_out('not ok 1 - whatever');
test_err(qq{# Failed test 'whatever'\n# at t/simple.t line 24.});
$xp->xpath_ok('/html/head/foo', 'whatever');
test_test('xpath_ok fail works');
$xp->ok('/html/head/foo', 'whatever');
test_test('ok fail works');

# Try a recursive call.
test_out( 'ok 1 - p');
test_out( 'ok 2 - em');
test_out( 'ok 3 - b');
test_out( 'ok 4 - em');
test_out( 'ok 5 - b');
$xp->xpath_ok( '/html/body/p', sub {
shift->xpath_ok('./em', sub {
$_->xpath_ok('./b', 'b');
$xp->ok( '/html/body/p', sub {
shift->ok('./em', sub {
$_->ok('./b', 'b');
}, 'em');
}, 'p');
test_test('recursive xpath_ok should work');
test_test('recursive ok should work');

# Try is, like, and cmp_ok.
$xp->xpath_is( '/html/head/title', 'Hello', 'xpath_is should work');
$xp->xpath_isnt( '/html/head/title', 'Bye', 'xpath_isnt should work');
$xp->xpath_like( '/html/head/title', qr{^Hel{2}o$}, 'xpath_like should work');
$xp->xpath_unlike( '/html/head/title', qr{^Bye$}, 'xpath_unlike should work');
$xp->xpath_cmp_ok('/html/head/title', 'eq', 'Hello', 'xpath_cmp_ok should work');
$xp->is( '/html/head/title', 'Hello', 'is should work');
$xp->isnt( '/html/head/title', 'Bye', 'isnt should work');
$xp->like( '/html/head/title', qr{^Hel{2}o$}, 'like should work');
$xp->unlike( '/html/head/title', qr{^Bye$}, 'unlike should work');
$xp->cmp_ok('/html/head/title', 'eq', 'Hello', 'cmp_ok should work');

# Try multiples.
$xp->xpath_is('/html/body/p', 'firstpost', 'Should work for multiples');
$xp->is('/html/body/p', 'firstpost', 'Should work for multiples');

# Try an attribute.
$xp->xpath_is('/html/body/p/@class', 'foo', 'Should get attribute value');
$xp->is('/html/body/p/@class', 'foo', 'Should get attribute value');

# Try a function.
$xp->xpath_is('count(/html/body/p)', 2, 'Should work for functions');
$xp->is('count(/html/body/p)', 2, 'Should work for functions');

# Try a boolean function.
$xp->xpath_ok('boolean(1)', 'Boolean should work');
$xp->ok('boolean(1)', 'Boolean should work');

# Try a false boolean.
test_out('not ok 1 - false boolean');
$xp->xpath_ok('false()', 'false boolean');
$xp->ok('false()', 'false boolean');
test_test( skip_err => 1 );
38 changes: 19 additions & 19 deletions t/xpath.t
Expand Up @@ -33,51 +33,51 @@ isa_ok $xp, 'Test::XPath';
isa_ok $xp->{xpc}, 'XML::LibXML::XPathContext';

# Do some tests with it.
$xp->xpath_ok('/html/head/title', 'Should find the title');
$xp->ok('/html/head/title', 'Should find the title');

# Try a recursive call.
$xp->xpath_ok( '/html/body/p', sub {
shift->xpath_ok('./em', sub {
$_->xpath_ok('./b', 'Find b under em');
$xp->ok( '/html/body/p', sub {
shift->ok('./em', sub {
$_->ok('./b', 'Find b under em');
}, 'Find em under para');
}, 'Find paragraphs');

# Try is, like, and cmp_ok.
$xp->xpath_is( '/html/head/title', 'Hello', 'xpath_is should work');
$xp->xpath_isnt( '/html/head/title', 'Bye', 'xpath_isnt should work');
$xp->xpath_like( '/html/head/title', qr{^Hel{2}o$}, 'xpath_like should work');
$xp->xpath_unlike( '/html/head/title', qr{^Bye$}, 'xpath_unlike should work');
$xp->xpath_cmp_ok('/html/head/title', 'eq', 'Hello', 'xpath_cmp_ok should work');
$xp->is( '/html/head/title', 'Hello', 'is should work');
$xp->isnt( '/html/head/title', 'Bye', 'isnt should work');
$xp->like( '/html/head/title', qr{^Hel{2}o$}, 'like should work');
$xp->unlike( '/html/head/title', qr{^Bye$}, 'unlike should work');
$xp->cmp_ok('/html/head/title', 'eq', 'Hello', 'cmp_ok should work');

# Try multiples.
$xp->xpath_is('/html/body/p', 'firstpost', 'Two values should concatenate');
$xp->is('/html/body/p', 'firstpost', 'Two values should concatenate');

# Try loading a file.
my $file = catfile qw(t menu.xml);
ok $xp = Test::XPath->new( file => $file ), 'Should create with file';

# Do some tests on the XML.
$xp->xpath_is('/menu/restaurant', 'Trébol', 'Should find Unicode value in file');
$xp->is('/menu/restaurant', 'Trébol', 'Should find Unicode value in file');

# Use recursive xpath_ok() to ensure all items have the appropriate parts.
# Use recursive ok() to ensure all items have the appropriate parts.
my $i = 0;
$xp->xpath_ok('/menu/item', sub {
$xp->ok('/menu/item', sub {
++$i;
$_->xpath_ok('./name', "Item $i should have a name");
$_->xpath_ok('./price', "Item $i should have a price");
$_->xpath_ok('./description', "Item $i should have a description");
$_->ok('./name', "Item $i should have a name");
$_->ok('./price', "Item $i should have a price");
$_->ok('./description', "Item $i should have a description");
}, 'Should have items' );

# Hey, so no try using the doc param.
ok $xp = Test::XPath->new(
doc => XML::LibXML->new->parse_file($file),
), 'Should create with doc';
$xp->xpath_is('/menu/restaurant', 'Trébol', 'Should find Unicode value in doc');
$xp->is('/menu/restaurant', 'Trébol', 'Should find Unicode value in doc');

# Use a namespace.
ok $xp = Test::XPath->new(
xml => $xml,
xmlns => { 'ex' => 'http://w3.org/ex' },
), 'Should create with real namespace';
$xp->xpath_ok('/ex:foo/ex:bar', 'We should find an ex:bar');
$xp->xpath_is('/ex:foo/ex:bar[1]', 'first', 'Should be able to check the first ex:bar value');
$xp->ok('/ex:foo/ex:bar', 'We should find an ex:bar');
$xp->is('/ex:foo/ex:bar[1]', 'first', 'Should be able to check the first ex:bar value');

0 comments on commit 2b89620

Please sign in to comment.