# -*- cperl -*-
use Test;
BEGIN { plan tests => 28 };

use XML::LibXML;
use XML::LibXML::XPathContext;

my $doc = XML::LibXML->new->parse_string(<<'XML');
<foo><bar a="b">Bla</bar><bar/></foo>
XML
ok($doc);

my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('foo','urn:foo');

$xc->registerFunctionNS('copy','urn:foo',
			sub { @_==1 ? $_[0] : die "too many parameters"}
		       );

# copy string, real, integer, nodelist
ok($xc->findvalue('foo:copy("bar")') eq 'bar');
ok($xc->findvalue('foo:copy(3.14)') < 3.141); # can't use == here because of
ok($xc->findvalue('foo:copy(3.14)') > 3.139); # float math
ok($xc->findvalue('foo:copy(7)') == 7);
ok($xc->find('foo:copy(//*)')->size() == 3);
my ($foo)=$xc->findnodes('(//*)[2]');
ok($xc->findnodes('foo:copy(//*)[2]')->pop->isSameNode($foo));

# too many arguments
eval { $xc->findvalue('foo:copy(1,xyz)') };
ok ($@);

# without a namespace
$xc->registerFunction('dummy', sub { 'DUMMY' });
ok($xc->findvalue('dummy()') eq 'DUMMY');

# unregister it
$xc->unregisterFunction('dummy');
eval { $xc->findvalue('dummy()') };
ok ($@);

# retister by name
sub dummy2 { 'DUMMY2' };
$xc->registerFunction('dummy2', 'dummy2');
ok($xc->findvalue('dummy2()') eq 'DUMMY2');

# unregister
$xc->unregisterFunction('dummy2');
eval { $xc->findvalue('dummy2()') };
ok ($@);


# a mix of different arguments types
$xc->registerFunction('join',
    sub { join shift,
          map { (ref($_)&&$_->isa('XML::LibXML::Node')) ? $_->nodeName : $_ }
          map { (ref($_)&&$_->isa('XML::LibXML::NodeList')) ? @$_ : $_ }
	  @_
	});

ok($xc->findvalue('join("","a","b","c")') eq 'abc');
ok($xc->findvalue('join("-","a",/foo,//*)') eq 'a-foo-foo-bar-bar');
ok($xc->findvalue('join("-",foo:copy(//*))') eq 'foo-bar-bar');

# unregister foo:copy
$xc->unregisterFunctionNS('copy','urn:foo');
eval { $xc->findvalue('foo:copy("bar")') };
ok ($@);

# test context locking mechanism
$xc->registerFunction('test-lock1', sub { $xc->find('1') });
$xc->registerFunction('test-lock2', sub { $xc->findnodes('1') });
eval { $xc->find('test-lock1()') };
ok($@);
eval { $xc->findnodes('test-lock1()') };
ok($@);
eval { $xc->find('test-lock2()') };
ok($@);
eval { $xc->findnodes('test-lock2()') };
ok($@);

# function creating new nodes
$xc->registerFunction('new-foo',
		      sub {
			return $doc->createElement('foo');
		      });
ok($xc->findnodes('new-foo()')->pop()->nodeName eq 'foo');
my ($test_node) = $xc->findnodes('new-foo()');

$xc->registerFunction('new-chunk',
		      sub {
			XML::LibXML->new->parse_string('<x><y><a/><a/></y><y><a/></y></x>')->find('//a')
		      });
ok($xc->findnodes('new-chunk()')->size() == 3);
my ($x)=$xc->findnodes('new-chunk()/parent::*');
ok($x->nodeName() eq 'y');
ok($xc->findvalue('name(new-chunk()/parent::*)') eq 'y');
ok($xc->findvalue('count(new-chunk()/parent::*)=2'));

my $largedoc=XML::LibXML->new->parse_string('<a>'.('<b/>' x 3000).'</a>');
$xc->setContextNode($largedoc);
$xc->registerFunction('pass1',
			sub {
			  [$largedoc->findnodes('(//*)')]
			});
$xc->registerFunction('pass2',sub { $_[0] } );
$xc->registerVarLookupFunc( sub { [$largedoc->findnodes('(//*)')] }, undef);
$largedoc->toString();

ok($xc->find('$a[name()="b"]')->size()==3000);
my @pass1=$xc->findnodes('pass1()');
ok(@pass1==3001);
ok($xc->find('pass2(//*)')->size()==3001);
