use Test;
BEGIN {
if ($^O eq 'linux' && $ENV{MEMORY_TEST}) {
plan tests => 22;
}
else {
plan tests => 0;
print "# Skipping test on this platform\n";
}
}
use XML::LibXML;
{
if ($^O eq 'linux' && $ENV{MEMORY_TEST}) {
require Devel::Peek;
my $peek = 0;
ok(1);
my $times_through = $ENV{MEMORY_TIMES} || 100_000;
print("# BASELINE\n");
check_mem(1);
print("# MAKE DOC IN SUB\n");
{
my $doc = make_doc();
ok($doc);
ok($doc->toString);
}
check_mem();
print("# MAKE DOC IN SUB II\n");
# same test as the first one. if this still leaks, it's
# our problem, otherwise it's perl :/
{
my $doc = make_doc();
ok($doc);
ok($doc->toString);
}
check_mem();
{
my $elem = XML::LibXML::Element->new("foo");
my $elem2= XML::LibXML::Element->new("bar");
$elem->appendChild($elem2);
ok( $elem->toString );
}
check_mem();
print("# SET DOCUMENT ELEMENT\n");
{
my $doc2 = XML::LibXML::Document->new();
make_doc_elem( $doc2 );
ok( $doc2 );
ok( $doc2->documentElement );
}
check_mem();
# multiple parsers:
print("# MULTIPLE PARSERS\n");
for (1..$times_through) {
my $parser = XML::LibXML->new();
}
ok(1);
check_mem();
# multiple parses
print("# MULTIPLE PARSES\n");
for (1..$times_through) {
my $parser = XML::LibXML->new();
my $dom = $parser->parse_string("foo");
}
ok(1);
check_mem();
# multiple failing parses
print("# MULTIPLE FAILURES\n");
for (1..$times_through) {
# warn("$_\n") unless $_ % 100;
my $parser = XML::LibXML->new();
eval {
my $dom = $parser->parse_string("foo"); # Thats meant to be an error, btw!
};
}
ok(1);
check_mem();
# building custom docs
print("# CUSTOM DOCS\n");
my $doc = XML::LibXML::Document->new();
for (1..$times_through) {
my $elem = $doc->createElement('x');
if($peek) {
warn("Doc before elem\n");
Devel::Peek::Dump($doc);
warn("Elem alone\n");
Devel::Peek::Dump($elem);
}
$doc->setDocumentElement($elem);
if ($peek) {
warn("Elem after attaching\n");
Devel::Peek::Dump($elem);
warn("Doc after elem\n");
Devel::Peek::Dump($doc);
}
}
if ($peek) {
warn("Doc should be freed\n");
Devel::Peek::Dump($doc);
}
ok(1);
check_mem();
print("# DTD string parsing\n");
my $dtdstr;
{
local $/; local *DTD;
open(DTD, 'example/test.dtd') || die $!;
$dtdstr = ;
$dtdstr =~ s/\r//g;
$dtdstr =~ s/[\r\n]*$//;
close DTD;
}
ok($dtdstr);
for ( 1..$times_through ) {
my $dtd = XML::LibXML::Dtd->parse_string($dtdstr);
}
ok(1);
check_mem();
print( "# DTD URI parsing \n");
# parse a DTD from a SYSTEM ID
for ( 1..$times_through ) {
my $dtd = XML::LibXML::Dtd->new('ignore', 'example/test.dtd');
}
ok(1);
check_mem();
print("# Document validation\n");
{
print "# is_valid()\n";
my $dtd = XML::LibXML::Dtd->parse_string($dtdstr);
my $xml = XML::LibXML->new->parse_file('example/article_bad.xml');
for ( 1..$times_through ) {
$xml->is_valid($dtd);
}
ok(1);
check_mem();
print "# validate() \n";
for ( 1..$times_through ) {
eval { $xml->validate($dtd);};
}
ok(1);
check_mem();
}
print "# FIND NODES \n";
my $xml=<<'dromeds.xml';
1 or 2
Cranky
1 (sort of)
Aloof
(see Llama)
Friendly
dromeds.xml
{
# my $str = "";
my $str = $xml;
my $doc = XML::LibXML->new->parse_string( $str );
for ( 1..$times_through ) {
processMessage($xml, '/dromedaries/species' );
# my @nodes = $doc->findnodes("/foo/bar/foo");
}
ok(1);
check_mem();
}
{
my $str = "";
my $doc = XML::LibXML->new->parse_string( $str );
for ( 1..$times_through ) {
my $nodes = $doc->find("/foo/bar/foo");
}
ok(1);
check_mem();
}
{
print "# ENCODING TESTS \n";
my $string = "test ä ø is a test string to test iso encoding";
my $encstr = encodeToUTF8( "iso-8859-1" , $string );
for ( 1..$times_through ) {
my $str = encodeToUTF8( "iso-8859-1" , $string );
}
ok(1);
check_mem();
for ( 1..$times_through ) {
my $str = encodeToUTF8( "iso-8859-2" , "abc" );
}
ok(1);
check_mem();
for ( 1..$times_through ) {
my $str = decodeFromUTF8( "iso-8859-1" , $encstr );
}
ok(1);
check_mem();
}
}
}
sub processMessage {
my ($msg, $xpath) = @_;
my $parser = XML::LibXML->new();
my $doc = $parser->parse_string($msg);
my $elm = $doc->getDocumentElement;
my $node = $doc->findnodes($xpath);
my $text = $node->to_literal->value;
# undef $doc; # comment this line to make memory leak much worse
# undef $parser;
}
sub make_doc {
# code taken from an AxKit XSP generated page
my ($r, $cgi) = @_;
my $document = XML::LibXML::Document->createDocument("1.0", "UTF-8");
# warn("document: $document\n");
my ($parent);
{
my $elem = $document->createElement(q(p));
$document->setDocumentElement($elem);
$parent = $elem;
}
$parent->setAttribute("xmlns:" . q(param), q(http://axkit.org/XSP/param));
{
my $elem = $document->createElementNS(q(http://axkit.org/XSP/param),q(param:foo),);
$parent->appendChild($elem);
$parent = $elem;
}
$parent = $parent->parentNode;
# warn("parent now: $parent\n");
$parent = $parent->parentNode;
# warn("parent now: $parent\n");
return $document
}
sub check_mem {
my $initialise = shift;
# Log Memory Usage
local $^W;
my %mem;
if (open(FH, "/proc/self/status")) {
my $units;
while () {
if (/^VmSize.*?(\d+)\W*(\w+)$/) {
$mem{Total} = $1;
$units = $2;
}
if (/^VmRSS:.*?(\d+)/) {
$mem{Resident} = $1;
}
}
close FH;
if ($LibXML::TOTALMEM != $mem{Total}) {
warn("LEAK! : ", $mem{Total} - $LibXML::TOTALMEM, " $units\n") unless $initialise;
$LibXML::TOTALMEM = $mem{Total};
}
print("# Mem Total: $mem{Total} $units, Resident: $mem{Resident} $units\n");
}
}
# some tests for document fragments
sub make_doc_elem {
my $doc = shift;
my $dd = XML::LibXML::Document->new();
my $node1 = $doc->createElement('test1');
my $node2 = $doc->createElement('test2');
$doc->setDocumentElement( $node1 );
}