#!/usr/bin/perl -w
use strict;
use Carp;
use File::Spec;
use lib File::Spec->catdir(File::Spec->curdir,"t");
use tools;
$|=1;
my $DEBUG=0;
use XML::Twig;
my $TMAX=96;
print "1..$TMAX\n";
{ my $d="titlep 1 p 2";
is( lf_in_t( XML::Twig->parse( pretty_print => 'indented', discard_spaces => 1, $d)), 1, 'space prevents indentation');
is( lf_in_t( XML::Twig->parse( pretty_print => 'indented', discard_all_spaces => 1, $d)), 5, 'discard_all_spaces restores indentation');
}
sub lf_in_t
{ my($t)= @_;
my @lfs= $t->sprint=~ m{\n}g;
return scalar @lfs;
}
{ my $d='';
my @tests=
( [ 't1|t2', HN => 't1t2' ],
[ 't1|t2|t3[@att="a|b"]', HN => 't1t2t3-1' ],
[ 't1|t2|t3[@att!="a|b"]', HN => 't1t2t3-2t3-3' ],
[ 't1|level(1)', H => 't1t1t2t3-1t3-2t3-3' ],
[ 't1|level(2)', H => 't1t4' ],
[ 't1|_all_', H => 't1t1t2t3-1t3-2t4t3-3d'],
[ qr/t[12]/ . '|t3/t4', H => 't1t2t4' ],
[ 't3[@a2="a|b"]', HN => 't3-2' ],
[ 't3[@a2="a|b"]|t3|t3/t4', H => 't3-1t3-2t3-2t4t3-3' ],
);
foreach my $test (@tests)
{ my $nb=0;
my $ids='';
my( $trigger, $test_cat, $expected_ids)= @$test;
my $handlers= $test_cat =~ m{H} ? { $trigger => sub { $ids.=$_->id; 1; } } : {};
my $t= XML::Twig->new( twig_handlers => $handlers )->parse( $d);
is( $ids, $expected_ids, "(H) trigger with alt: '$trigger'");
my $uniq_ids= join '', sort $expected_ids=~m{(t\d(?:-\d)?)}g;
if( $test_cat =~ m{X})
{ (my $xpath= "//$trigger")=~ s{\|t}{|//t}g;
is( join( '', map { $_->id } $t->findnodes( $xpath)), $uniq_ids, " (X) path with |: '$trigger'");
}
if( $test_cat =~ m{N})
{ is( join( '', map { $_->id } $t->root->children( $trigger)), $uniq_ids, "(N)navigation with |: '$trigger'"); }
}
}
{ my $t1= XML::Twig->parse( '');
is( XML::Twig->active_twig()->root->id, 'd1', 'active_twig, one twig');
my $t2= XML::Twig->parse( '');
is( XML::Twig->active_twig()->root->id, 'd2', 'active_twig, second twig');
}
{ eval { XML::Twig->new(error_context => 1)->parse( $0); };
matches( $@, "you seem to have used the parse method on a filename", 'parse on a file name');
}
{ my $got;
XML::Twig->parse( twig_handlers => { 'e[@a]' => sub { $got .= $_->id; } }, '');
is( $got, 'i1i3', 'bare attribute in handler condition');
}
{ my $doc= q{]>&ext;};
ok( XML::Twig->parse( expand_external_ents => -1, $doc), 'failsafe expand_external_ents');
}
{ my $t=XML::Twig->parse( q{e11e21e12});
is( join( ':', $t->findvalues( [$t->root->children], "./e1")), 'e11:e12', 'findvalues on array');
}
{ my $t=XML::Twig->parse( "");
$t->set_encoding( "UTF-8");
is( $t->sprint, qq{\n}, 'set_encoding without XML declaration');
}
{ my $t=XML::Twig->parse( "");
$t->set_standalone( 1);
is( $t->sprint, qq{\n}, 'set_standalone (yes) without XML declaration');
}
{ my $t=XML::Twig->parse( "");
$t->set_standalone( 0);
is( $t->sprint, qq{\n}, 'set_standalone (no) without XML declaration');
}
{ my $t=XML::Twig->parse( "");
nok( $t->xml_version, 'xml_version with no XML declaration');
$t->set_xml_version( 1.1);
is( $t->sprint, qq{\n}, 'set_xml_version without XML declaration');
is( $t->xml_version, 1.1, 'xml_version after being set');
}
{ my $t= XML::Twig->new;
is( $t->_dump, "document\n", '_dump on an empty twig');
}
{ my $t=XML::Twig->parse( pretty_print => 'none', 'foobar');
$t->root->field_to_att( 'f[@a="b"]', 'g');
is( $t->sprint, 'foo', 'field_to_att on non-simple condition');
$t->root->att_to_field( g => 'gg');
is( $t->sprint, 'barfoo', 'att_to_field with att != field');
}
{ my $t=XML::Twig->parse( '');
$t->root->wrap_in( 'nroot');
is( $t->sprint, '', 'wrapping the root');
}
{
my $t=XML::Twig->new;
XML::Twig::_set_weakrefs(0);
my $doc='\n texttext more text foo\n more';
$t->parse( $doc);
$doc=~ s{\n }{}; # just the first one
is( $t->sprint, $doc, 'parse with no weakrefs');
$t->root->insert_new_elt( first_child => x => 'text');
$doc=~ s{}{text};
is( $t->sprint, $doc, 'insert first child with no weakrefs');
$t->root->insert_new_elt( last_child => x => 'text');
$doc=~ s{}{text};
is( $t->sprint, $doc, 'insert last child with no weakrefs');
$t->root->wrap_in( 'dd');
$doc=~ s{}{}; $doc=~s{}{};
is( $t->sprint, $doc, 'wrap with no weakrefs');
$t->root->unwrap;
$doc=~s{?dd>}{}g;
is( $t->sprint, $doc, 'unwrap with no weakrefs');
my $new_e= XML::Twig::Elt->new( ee => { c => 1 }, 'ee text');
$new_e->replace( $t->root->first_child( 'e'));
$doc=~ s{}{ee text};
is( $t->sprint, $doc, 'replace with no weakrefs');
XML::Twig::_set_weakrefs(1);
}
{
my $t= XML::Twig->new( no_expand => 1);
XML::Twig::_set_weakrefs(0);
my $doc=']> bar &bar; bar&bar;&foo; &bar; bar &foo;&bar; na &foo;';
$t->parse( $doc);
(my $got= $t->sprint)=~ s{\n}{}g;
is( $got, $doc, 'external entities without weakrefs');
XML::Twig::_set_weakrefs(1);
}
{
XML::Twig::_set_weakrefs(0);
{ my $t= XML::Twig->new; undef $t; }
ok( 1, "DESTROY doesn't crash when weakrefs is off");
XML::Twig::_set_weakrefs(1);
}
{ my $doc= 'foobarbar';
my( $got1, $got2);
XML::Twig->new( twig_handlers => { e1 => sub { $_->parent->set_att( get1 => 1); },
e2 => sub { $_->parent->set_att( '#get2' => 1); },
'[@get1]' => sub { $got1 .= 'a' . $_->id; },
'[@#get2]' => sub { $got2 .= 'a' . $_->id; },
'e[@get1]' => sub { $got1 .= 'b' . $_->id; },
'e[@#get2]' => sub { $got2 .= 'b' . $_->id; },
},
)
->parse( $doc);
is( $got1, 'be1ae1', 'handler on bare attribute');
is( $got2, 'be3ae3', 'handler on private (starting with #) bare attribute');
}
{ my $t=XML::Twig->parse( 'foo');
my $root= $t->root;
ok( $root->closed, 'closed on completely parsed tree');
ok( $root->_extra_data_before_end_tag, '_extra_data_before_end_tag (success)');
nok( $root->first_child->_extra_data_before_end_tag, '_extra_data_before_end_tag (no data)');
}
{ my $t= XML::Twig->parse( pi => 'process', '');
is( $t->first_elt( '#PI')->pi_string, '', 'pi_string with empty data');
}
{ my $t= XML::Twig->parse( '');
is( ids( $t->root->children( '.a')), 'e1:f1', 'nav on class');
}
{ my $t=XML::Twig->parse( 'foobarfoobar123');
is ( ids( $t->root->children( 'e[string()="foo"]')), 'e1', 'navigation condition using string() =');
is ( ids( $t->root->children( 'e[string()=~/foo/]')), 'e1:e3', 'navigation condition using string() =~');
is ( ids( $t->root->children( 'e[string()!~/foo/]')), 'e2:e4', 'navigation condition using string() !~');
is ( ids( $t->root->children( 'e[string()!="foo"]')), 'e2:e3:e4', 'navigation condition using string() !=');
is ( ids( $t->root->children( 'e[string()]')), 'e1:e2:e3', 'navigation condition using bare string()');
is ( ids( $t->root->findnodes( './e[string()="foo"]')), 'e1', 'xpath condition using string() =');
is ( ids( $t->root->findnodes( './e[string()=~/foo/]')), 'e1:e3', 'xpath condition using string() =~');
is ( ids( $t->root->findnodes( './e[string()!~/foo/]')), 'e2:e4', 'xpath condition using string() !~');
is ( ids( $t->root->findnodes( './e[string()!="foo"]')), 'e2:e3:e4', 'xpath condition using string() !=');
is ( ids( $t->root->findnodes( './e[string()]')), 'e1:e2:e3', 'xpath condition using bare string()');
is( ids( $t->root->children( 'n[string()=2]')), 'n2', 'navigation string() =');
is( ids( $t->root->children( 'n[string()!=2]')), 'n1:n3', 'navigation string() !=');
is( ids( $t->root->children( 'n[string()>2]')), 'n3', 'navigation string() >');
is( ids( $t->root->children( 'n[string()>=2]')), 'n2:n3', 'navigation string() >=');
is( ids( $t->root->children( 'n[string()<2]')), 'n1', 'navigation string() <');
is( ids( $t->root->findnodes( './n[string()=2]')), 'n2', 'xpath string() =');
is( ids( $t->root->findnodes( './n[string()!=2]')), 'n1:n3', 'xpath string() !=');
is( ids( $t->root->findnodes( './n[string()>2]')), 'n3', 'xpath string() >');
is( ids( $t->root->findnodes( './n[string()>=2]')), 'n2:n3', 'xpath string() >=');
is( ids( $t->root->findnodes( './n[string()<2]')), 'n1', 'xpath string() <');
is( ids( $t->root->findnodes( './n[string()<=2]')), 'n1:n2', 'xpath string() <=');
}
{ my $got;
my $t=XML::Twig->parse( twig_handlers => { d => sub { $got .="wrong"; },
'd[@id]' => sub { $got .= "ok"; 0 },
},
''
);
is( $got, 'ok', 'returning 0 prevents the next handler to be called');
}
{ my $d=q{foofooblank
};
my $expected=qq{\n \n foo\n \n \n fooblank
\n
\n };
XML::Twig::_indent_xhtml( \$d);
is( $d, $expected, '_indent_xhtml');
}
{ my $d='c';
my @handlers= ( '/d/e[@a="a" or @b="b"]',
'/d/e[@a="a" or @b="c"]|e',
'/d/e[@a="a"]',
'/d/e[@b="b"]',
'/d/e',
'd/e[@a="a" and @b="b"]',
'd/e[@a="a"]',
'd/e[@b="b"]',
'd/e',
'e[@a="a" or @b="b"]',
'e[@b="b" or @a="a"]',
'e[@a="a"]|f',
'e[@b="b"]',
'e',
qr/e|f/,
qr/e|f|g/,
'level(1)',
);
my $t= XML::Twig->new();
for my $stem ( 1, 100)
{ my $i= $stem;
my $expected= join '', ($stem..$stem+$#handlers);
my $got;
$t->setTwigHandlers( { map { $_ => sub { $got .= $i++; } } @handlers });
$t->parse( $d);
is( $got, $expected, 'handler order');
}
}
{ my $t=XML::Twig->parse( "");
$t->{twig_dtd}="";
is( $t->doctype(UpdateDTD => 1), "\n", 'doctype with an updated DTD');
}
{ my $t=XML::Twig->parse( '');
$t->elt_accessors( 'e', 'e');
$t->elt_accessors( { e2 => 'e[2]', se => 'se', sea => 'se[@a]' });
my $root= $t->root;
is( $root->e->id, 'e1', 'accessor, no alias, scalar context');
my $e2= ($root->e)[-1];
is( $e2->id, 'e2', 'accessor no alias, list context');
$e2= $root->e2;
is( $e2->id, 'e2', 'accessor alias, list context');
is( $e2->se->id, 'se1', 'accessor alias, scalar context');
is( $e2->sea->id, 'se2', 'accessor, with complex step, alias, scalar context');
}
{ my $t=XML::Twig->new( elt_accessors => [ 'e', 'se' ])
->parse( '');
my $root= $t->root;
is( $root->e->id, 'e1', 'accessor (created in new), no alias, scalar context');
my $se= ($root->e)[-1]->se;
is( $se->id, 'se1', 'accessor (created in new) no alias, scalar context, 2');
}
{ my $t=XML::Twig->new( elt_accessors => { e2 => 'e[2]', se => 'se', sea => 'se[@a]' })
->parse( '');
my $e2= $t->root->e2;
is( $e2->id, 'e2', 'accessor (created in new) alias, list context');
is( $e2->se->id, 'se1', 'accessor (created in new) alias, scalar context');
is( $e2->sea->id, 'se2', 'accessor (created in new), with complex step, alias, scalar context');
}
{ my $doc= ']>';
my $t= XML::Twig->parse( do_not_output_DTD => 1, $doc);
is( $t->sprint, qq{\n}, 'do_not_output_DTD');
}
{ my $t= XML::Twig->parse( no_prolog => 1, ']>');
is( $t->sprint, qq{}, 'no_prolog');
}
{ my $t= XML::Twig->parse( ']>');
is( $t->sprint, qq{\n\n]>\n}, 'no_prolog');
}
{ my $e= XML::Twig::Elt->new( 'e');
$e->set_empty;
is( $e->sprint, '', 'set_empty with no value');
$e->set_empty( 0);
is( $e->sprint, '', 'set_empty(0)');
$e->set_empty;
is( $e->sprint, '', 'set_empty with no value');
$e->set_empty( 1);
is( $e->sprint, '', 'set_empty(1');
$e->set_empty;
is( $e->sprint, '', 'set_empty with no value');
$e->set_empty( 1);
is( $e->sprint, '', 'set_empty(1)');
my $e2= XML::Twig::Elt->parse( '');
$e2->set_not_empty();
is( $e2->sprint, '', 'set_not_empty');
ok( ! $e2->closed, 'closed on an orphan elt');
}
{ my $t= XML::Twig->parse( '');
my $l2= $t->first_elt( 'l2');
my $l4= $t->first_elt( 'l4');
$l2->cut;
$l4->cut;
is( $l4->_root_through_cut->tag, 'd', '_root_through_cut');
is( $l4->_inherit_att_through_cut( 'a', 'd'), 'd', '_inherit_att_through_cut');
}
{ my $s= "foo";
is( XML::Twig::_to_utf8( 'iso-8859-1', $s), $s, 'trivial test of _to_utf8');
}