
use strict;
use warnings;

use Test::More tests => 129;

BEGIN { use_ok('Sleepycat::DbXml', 'simple') };
BEGIN { use_ok('File::Path') };


{
    my $doc ;

    $doc = new XmlDocument(); 

    ok ! $@, "Creating document doesn't throw an exception" ;
    ok defined $doc, "Document object created ok" ;

    is $doc->getID(), 0, "Doc ID should be 0 before it has any content" ;

    my $content = new Dbt '<def />';
    $doc->setContent($content);

    #ok $doc->getID() == 0, "Doc ID != 0 when doc has content, but not in container";

    my $dbt = $doc->getContent();
    is $dbt->get_data(), $content, "getContent returning dbt is ok";

    my $cont = $doc->getContentAsString();

    ok $cont eq $content, "getContentAsString returned correct content" ;
}

my $doc ;

eval { $doc = new XmlDocument(); };

ok ! $@, "Creating document doesn't throw an exception" ;
ok defined $doc, "Document object created ok" ;

is $doc->getID(), 0, "Doc ID should be 0 before it has any content" ;

my $content = '<abc />';
$doc->setContent($content);

ok $doc->getID() == 0, "Doc ID != 0 when doc has content, but not in container";

my $dbt = $doc->getContent();
is $dbt->get_data(), $content, "getContent returning dbt is ok";

my $cont = $doc->getContentAsString();

ok $cont eq $content, "getContentAsString returned correct content" ;


$doc->setName("fred");

is $doc->getName(), 'fred', "setName/getName works ok" ; 

{ 
    my $context = new XmlQueryContext() ;

    my $value1 = new XmlValue(XmlValue::NUMBER, 42) ;
    my $value2 = new XmlValue(XmlValue::NUMBER, 43) ;

    my $uri = 'http://fred.com/';
    my $prefix = 'fred';
    my $name1 = 'universe' ;
    my $name2 = 'everything' ;
    $doc->setMetaData($uri, $prefix, $name1, $value1) ;
    $doc->setMetaData($uri, $prefix, $name2, $value2) ;

    # uncomment next line to trigger an about
    #my $value3 = new XmlValue() ;
    my $value3 = new XmlValue(XmlValue::NUMBER, 1234) ;

    # try to fetch an unknown bit of meta data
    ok !$doc->getMetaData($uri."x", "xx who", $value3), "getMetaData returns FALSE" ;

    ok $doc->getMetaData($uri, $name1, $value3), "getMetaData returns TRUE" ;
    ok $value3->isNumber($context), "getMetaData returned a number";
    my $got = $value3->asNumber($context);
    is $got, 42, "getMeta returns 42";

    ok $doc->getMetaData($uri, $name2, $value3), "getMetaData returns TRUE" ;
    ok $value3->isNumber($context), "getMetaData returned a number";
    $got = $value3->asNumber($context);
    is $got, 43, "getMeta returns 43";

}

{ 
    my $context = new XmlQueryContext() ;

    my $uri = 'http://fred.com/';
    my $prefix = 'fred';

    my $name1 = 'hi' ;
    my $value1 = new XmlValue(XmlValue::STRING, "hello world") ;
    $doc->setMetaData($uri, $prefix, $name1, $value1) ;

    my $name2 = 'lo' ;
    my $value2 = new XmlValue(XmlValue::STRING, "goodbye cruel world") ;
    $doc->setMetaData($uri, $prefix, $name2, $value2) ;

    my $value3 = new XmlValue(XmlValue::STRING, "abc") ;

    ok $doc->getMetaData($uri, $name1, $value3), "getMetaData returns TRUE" ;
    ok $value3->isString($context), "getMetaData returned a string";
    my $got = $value3->asString($context);
    is $got, "hello world", "getMeta returns 'hello world'";

    ok $doc->getMetaData($uri, $name2, $value3), "getMetaData returns TRUE" ;
    ok $value3->isString($context), "getMetaData returned a string";
    $got = $value3->asString($context);
    is $got, "goodbye cruel world", "getMeta returns 'goodbye cruel world'";

}

{ 
    my $context = new XmlQueryContext() ;

    my $value = new XmlValue(XmlValue::BOOLEAN, 1) ;
    my $value3 = new XmlValue(XmlValue::BOOLEAN, 0) ;
    my $uri = 'http://fred.com/';
    my $prefix = 'fred';
    my $name = 'truth' ;
    my $name1 = 'falsehood' ;

    $doc->setMetaData($uri, $prefix, $name, $value) ;
    $doc->setMetaData($uri, $prefix, $name1, $value3) ;

    my $value1 = new XmlValue(XmlValue::BOOLEAN, 0) ;

    ok $doc->getMetaData($uri, $name, $value1), "getMetaData returns TRUE" ;
    ok $value1->isBoolean($context), "getMetaData returned a boolean";
    my $got = $value1->asBoolean($context);
    is $got, 1, "getMeta returns 'true'";
    is $value1->asString($context), 'true', "asString should retuen 'true'";
    

    ok $doc->getMetaData($uri, $name1, $value1), "getMetaData returns TRUE" ;
    ok $value1->isBoolean($context), "getMetaData returned a boolean";
    $got = $value1->asBoolean($context);
    isnt $got, 0, "getMeta returns 'false'";
    is $value1->asString($context), 'false', "asString should return 'false'";

}

{ 
    my $value1 = "something" ;
    my $value2 = "else" ;
    my $uri = 'http://freddy.com/';
    my $prefix = 'joe';
    my $name1 = 'blah' ;
    my $name2 = 'bloh' ;
    $doc->setMetaData($uri, $prefix, $name1, $value1) ;
    $doc->setMetaData($uri, $prefix, $name2, $value2) ;


    my $value3 ;
    ok !$doc->getMetaData($uri, "xunknown", $value3), "getMetaData returns FALSE" ;
    ok $doc->getMetaData($uri, $name1, $value3), "getMetaData returns TRUE" ;
    is $value3, $value1, "getMeta returns 'something'";

    ok $doc->getMetaData($uri, $name2, $value3), "getMetaData returns TRUE" ;
    is $value3, $value2, "getMeta returns 'else'";

}

{ 
    # get/setMetaData - via Dbt
    my $value1 = new Dbt "green" ;
    my $value2 = new Dbt "blue" ;
    my $uri = 'http://freddy.com/';
    my $prefix = 'joe';
    my $name1 = 'gamma' ;
    my $name2 = 'delta' ;
    $doc->setMetaData($uri, $prefix, $name1, $value1) ;
    $doc->setMetaData($uri, $prefix, $name2, $value2) ;


    my $value3 = new Dbt ;
    ok !$doc->getMetaData($uri, "xunknown", $value3), "getMetaData returns FALSE" ;
    ok $doc->getMetaData($uri, $name1, $value3), "getMetaData returns TRUE" ;
    is $value3->get_data(), $value1->get_data(), "getMeta returns 'green'";
    is $value3->get_data(), "green", "Dbt->getdata() returns 'green'";

    ok $doc->getMetaData($uri, $name2, $value3), "getMetaData returns TRUE" ;
    is $value3->get_data(), $value2->get_data(), "getMeta returns 'blue'";
    is $value3->get_data(), "blue", "Dbt->getdata() returns 'blue'";

}

{ 
    # get/setMetaData - via Perl scalar

    my $value1 = "pink" ;
    my $value2 = "black" ;
    my $uri = 'http://freddy.com/';
    my $prefix = 'moe';
    my $name1 = 'pi' ;
    my $name2 = 'omega' ;
    $doc->setMetaData($uri, $prefix, $name1, $value1) ;
    $doc->setMetaData($uri, $prefix, $name2, $value2) ;


    my $value3  ;
    ok !$doc->getMetaData($uri, "xunknown", $value3), "getMetaData returns FALSE" ;
    ok $doc->getMetaData($uri, $name1, $value3), "getMetaData returns TRUE" ;
    is $value3, $value1, "getMeta returns '$value1'";

    ok $doc->getMetaData($uri, $name2, $value3), "getMetaData returns TRUE" ;
    is $value3, $value2, "getMeta returns '$value2'";

}

{ 
    # getMetaData with NULL XmlValue should not throw exception

    my $uri = 'http://fred.com/';
    my $name = 'hi' ;
    my $value1 = new XmlValue() ;
    eval { $doc->getMetaData($uri, $name, $value1) ; };
    ok !$@, "getMetaData with NULL XmlValue should not throw exception";

}

{ 
    # setMetaData with NULL XmlValue should throw exception

    my $context = new XmlQueryContext() ;

    my $value1 = new XmlValue() ;

    my $uri = 'http://fred.com/';
    my $prefix = 'fred';
    my $name1 = 'blank' ;

    eval { $doc->setMetaData($uri, $prefix, $name1, $value1); } ;
    ok $@, "setMetaData with NULL XmlValue should throw exception";

}

{ 
    # setMetaData with VARIABLE XmlValue should throw exception

    my $context = new XmlQueryContext() ;

    my $value1 = new XmlValue(XmlValue::VARIABLE, "hello world") ;

    my $uri = 'http://fred.com/';
    my $prefix = 'fred';
    my $name1 = 'foo' ;
    my $name2 = 'bar' ;

    eval { $doc->setMetaData($uri, $prefix, $name1, $value1) } ;
    ok $@, "setMetaData with VARIABLE XmlValue should throw exception";
}


{ 
    my $context = new XmlQueryContext() ;

    my $value1 = new XmlValue(XmlValue::DOCUMENT, "<x />") ;
    my $value2 = new XmlValue(XmlValue::DOCUMENT, "<y />") ;

    my $uri = 'http://fred.com/';
    my $prefix = 'fred';
    my $name1 = 'foo' ;
    my $name2 = 'bar' ;

    $doc->setMetaData($uri, $prefix, $name1, $value1) ;
    $doc->setMetaData($uri, $prefix, $name2, $value2) ;

    #my $value1 = new XmlValue() ;
    my $value3 = new XmlValue(XmlValue::DOCUMENT, "<z />") ;

    ok $doc->getMetaData($uri, $name1, $value3), "getMetaData returns TRUE" ;
    ok $value3->isDocument($context), "getMetaData returned a Document";
    is $value3->asDocument()->getContentAsString(), "<x />";

    eval { $value3->asNumber($context); };
    is $@->getExceptionCode, XmlException::INVALID_VALUE, "exception is INVALID_VALUE";


    ok $doc->getMetaData($uri, $name2, $value3), "getMetaData returns TRUE" ;
    ok $value3->isDocument($context), "getMetaData returned a Document";
    is $value3->asDocument()->getContentAsString(), "<y />";



}

{
    # XmlDocument::queryWithXPath

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title') } ;
    ok !$@, "queryWithXPath returned 0";

    my $value = new XmlValue ;
    ok $results->next($value), "results.next returns true" ;
    ok !$value->isNull(), "results->next not null";
    ok !$value->isDocument(), "results->next is not document";
    ok !$value->isString(), "results->next is not string";
    ok $value->isNode(), "results->next is node";
    is $value->asString(), $title, "nodelist contents ok";

    ok ! $results->next($value), "results.next returns false";
    ok $value->isNull(), "results->next is null";

}

{
    # XmlDocument::queryWithXPath using XmlQueryExpression

    my $tmp_dir = "tmp" ;

    if (-d $tmp_dir)
    {
        rmtree($tmp_dir);
    }

    mkdir $tmp_dir, 0777 ;


    my $container_name = "$tmp_dir/fred1" ;
    my $x = new XmlContainer($container_name); 
    ok $x, "new XmlContainer returned object" ;

    eval { $x->open(Db::DB_CREATE); } ;
    if (my $E = XmlException::catch())
    {
        ok 0, "open should not throw an exception";
        print "# " . $E->what() . "\n" ;
        exit;
    }
    else
    {
        ok 1, "open should not throw an exception";
    }

    my $context = new XmlQueryContext(XmlQueryContext::ResultValues) ;
    my $path = '/book/title';
    my $expression;
    eval { $expression = $x->parseXPathExpression($path, $context) } ;
    ok !$@, "parseXPathExpression ok" ;
    print "$@\n";


    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title') } ;
    ok !$@, "queryWithXPath returned 0";

    my $value = new XmlValue ;
    ok $results->next($value), "results.next returns true" ;
    ok !$value->isNull(), "results->next not null";
    ok !$value->isDocument(), "results->next is not document";
    ok !$value->isString(), "results->next is not string";
    ok $value->isNode(), "results->next is node";
    is $value->asString(), $title, "nodelist contents ok";

    $x->close(); 
    $x->remove();     ok ! $results->next($value), "results.next returns false";
    ok $value->isNull(), "results->next is null";


}

{
    # XmlDocument::queryWithXPath - destroy document before calling results.next

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title') } ;
    ok !$@, "queryWithXPath returned 0";

    undef $doc ;

    my $value = new XmlValue ;
    ok $results->next($value), "results.next returns true" ;
    ok !$value->isNull(), "results->next not null";
    ok !$value->isDocument(), "results->next is not document";
    ok !$value->isString(), "results->next is not string";
    ok $value->isNode(), "results->next is node";
    is $value->asString(), $title, "nodelist contents ok";

    ok ! $results->next($value), "results.next returns false";
    ok $value->isNull(), "results->next is null";

}

{
    # XmlDocument::queryWithXPath -- ResultDocumentsAndValues

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $context = new XmlQueryContext() ;
    $context->setReturnType(XmlQueryContext::ResultDocumentsAndValues);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title', $context) } ;
    ok !$@, "queryWithXPath returned 0";

    my $doc1 = new XmlDocument ;
    my $value = new XmlValue ;
    ok $results->next($doc1, $value), "results.next returns true" ;

    is $doc->getID(), $doc1->getID(), "returned document matches";

    ok !$value->isNull(), "results->next not null";
    ok !$value->isDocument(), "results->next is not document";
    ok !$value->isString(), "results->next is not string";
    ok $value->isNode(), "results->next is node";
    is $value->asString(), $title, "nodelist contents ok";

    my $doc2 = new XmlDocument ;
    ok ! $results->next($doc2, $value), "results.next returns false";
    is $doc->getID(), $doc2->getID(), "returned document matches";
    ok $value->isNull(), "results->next is null";

}

{
    # XmlDocument::queryWithXPath -- ResultDocuments

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $context = new XmlQueryContext() ;
    $context->setReturnType(XmlQueryContext::ResultDocuments);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title', $context) } ;
    ok !$@, "queryWithXPath returned 0";

    my $doc1 = new XmlDocument ;
    ok $results->next($doc1), "results.next returns true" ;

    is $doc->getID(), $doc1->getID(), "returned document matches";

    my $doc2 = new XmlDocument ;
    ok ! $results->next($doc2), "results.next returns false";
    is $doc->getID(), $doc2->getID(), "returned document matches";

}


{
    # XmlDocument::queryWithXPath -- ResultDocuments, but use next XMLValue

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $context = new XmlQueryContext() ;
    $context->setReturnType(XmlQueryContext::ResultDocuments);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title', $context) } ;
    ok !$@, "queryWithXPath returned 0";

    my $value = new XmlValue ;
    ok $results->next($value), "results.next returns true" ;
    ok !$value->isNull(), "results->next not null";
    ok $value->isDocument(), "results->next is document";
    ok !$value->isString(), "results->next is not string";
    ok !$value->isNode(), "results->next is not node";
    is $value->asString(), $content, "document contents ok";

}


{
    # XmlDocument::queryWithXPath -- ResultValues, but use next XMLDocument

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $context = new XmlQueryContext() ;
    $context->setReturnType(XmlQueryContext::ResultValues);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title', $context) } ;
    ok !$@, "queryWithXPath returned 0";

    my $doc1 = new XmlDocument ;
    eval { $results->next($doc1) } ;
    ok $@, "next failed";
    is $@->getExceptionCode(), XmlException::INVALID_VALUE, "exception is INVALID_VALUE";

}



{
    # XmlDocument::queryWithXPath -- ResultValues, 
    # but use next XMLDocument, XmlValue

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $context = new XmlQueryContext() ;
    $context->setReturnType(XmlQueryContext::ResultValues);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title', $context) } ;
    ok !$@, "queryWithXPath returned 0";

    my $doc1 = new XmlDocument ;
    my $value = new XmlValue ;
    eval { $results->next($doc1, $value) } ;
    ok $@, "next failed";
    is $@->getExceptionCode(), XmlException::INVALID_VALUE, "exception is INVALID_VALUE";



}



{
    # XmlDocument::queryWithXPath -- ResultDocuments, 
    # but use next XMLDocument, XmlValue

    my $doc = new XmlDocument(); 
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);

    my $context = new XmlQueryContext() ;
    $context->setReturnType(XmlQueryContext::ResultDocuments);

    my $results ;
    eval { $results = $doc->queryWithXPath('/book/title', $context) } ;
    ok !$@, "queryWithXPath returned 0";

    my $doc1 = new XmlDocument ;
    my $value = new XmlValue ;
    ok $results->next($doc1, $value), "results.next returns true" ;

    ok !$value->isNull(), "results->next not null";
    ok $value->isDocument(), "results->next is document";
    ok !$value->isString(), "results->next is not string";
    ok !$value->isNode(), "results->next is not node";
    is $value->asString(), $content, "document contents ok";

    ok ! $results->next($doc1, $value), "results.next returns false" ;
}


