1# $Id$
2
3use strict;
4use warnings;
5
6# Should be 54.
7use Test::More tests => 54;
8
9use lib './t/lib';
10use TestHelpers qw(slurp);
11
12use XML::LibXML;
13use XML::LibXML::Common qw(:libxml);
14
15my $htmlPublic = "-//W3C//DTD XHTML 1.0 Transitional//EN";
16my $htmlSystem = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";
17
18{
19    my $doc = XML::LibXML::Document->new;
20    my $dtd = $doc->createExternalSubset( "html",
21                                          $htmlPublic,
22                                          $htmlSystem
23                                        );
24
25    # TEST
26    ok( $dtd->isSameNode(  $doc->externalSubset ), ' TODO : Add test name' );
27    # TEST
28    is( $dtd->publicId, $htmlPublic, ' TODO : Add test name' );
29    # TEST
30    is( $dtd->systemId, $htmlSystem, ' TODO : Add test name' );
31    # TEST
32    is( $dtd->getName, 'html', ' TODO : Add test name' );
33
34}
35
36{
37    my $doc = XML::LibXML::Document->new;
38    my $dtd = $doc->createInternalSubset( "html",
39                                          $htmlPublic,
40                                          $htmlSystem
41                                        );
42    # TEST
43    ok( $dtd->isSameNode( $doc->internalSubset ), ' TODO : Add test name' );
44
45    $doc->setExternalSubset( $dtd );
46    # TEST
47    ok(!defined ($doc->internalSubset), ' TODO : Add test name' );
48    # TEST
49    ok( $dtd->isSameNode( $doc->externalSubset ), ' TODO : Add test name' );
50
51    # TEST
52
53    is( $dtd->getPublicId, $htmlPublic, ' TODO : Add test name' );
54    # TEST
55    is( $dtd->getSystemId, $htmlSystem, ' TODO : Add test name' );
56
57    $doc->setInternalSubset( $dtd );
58    # TEST
59    ok(!defined ($doc->externalSubset), ' TODO : Add test name' );
60    # TEST
61    ok( $dtd->isSameNode( $doc->internalSubset ), ' TODO : Add test name' );
62
63    my $dtd2 = $doc->createDTD( "huhu",
64                                "-//W3C//DTD XHTML 1.0 Transitional//EN",
65                                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
66                              );
67
68    $doc->setInternalSubset( $dtd2 );
69    # TEST
70    ok( !defined($dtd->parentNode), ' TODO : Add test name' );
71    # TEST
72    ok( $dtd2->isSameNode( $doc->internalSubset ), ' TODO : Add test name' );
73
74
75    my $dtd3 = $doc->removeInternalSubset;
76    # TEST
77    ok( $dtd3->isSameNode($dtd2), ' TODO : Add test name' );
78    # TEST
79    ok( !defined($doc->internalSubset), ' TODO : Add test name' );
80
81    $doc->setExternalSubset( $dtd2 );
82
83    $dtd3 = $doc->removeExternalSubset;
84    # TEST
85    ok( $dtd3->isSameNode($dtd2), ' TODO : Add test name' );
86    # TEST
87    ok( !defined($doc->externalSubset), ' TODO : Add test name' );
88}
89
90{
91    my $parser = XML::LibXML->new();
92
93    my $doc = $parser->parse_file( "example/dtd.xml" );
94
95    # TEST
96
97    ok($doc, ' TODO : Add test name');
98
99    my $dtd = $doc->internalSubset;
100    # TEST
101    is( $dtd->getName, 'doc', ' TODO : Add test name' );
102    # TEST
103    is( $dtd->publicId, undef, ' TODO : Add test name' );
104    # TEST
105    is( $dtd->systemId, undef, ' TODO : Add test name' );
106
107    my $entity = $doc->createEntityReference( "foo" );
108    # TEST
109    ok($entity, ' TODO : Add test name');
110    # TEST
111    is($entity->nodeType, XML_ENTITY_REF_NODE, ' TODO : Add test name' );
112
113    # TEST
114
115    ok( $entity->hasChildNodes, ' TODO : Add test name' );
116    # TEST
117    is( $entity->firstChild->nodeType, XML_ENTITY_DECL, ' TODO : Add test name' );
118    # TEST
119    is( $entity->firstChild->nodeValue, " test ", ' TODO : Add test name' );
120
121    my $edcl = $entity->firstChild;
122    # TEST
123    is( $edcl->previousSibling->nodeType, XML_ELEMENT_DECL, ' TODO : Add test name' );
124
125    {
126        my $doc2  = XML::LibXML::Document->new;
127        my $e = $doc2->createElement("foo");
128        $doc2->setDocumentElement( $e );
129
130        my $dtd2 = $doc->internalSubset->cloneNode(1);
131        # TEST
132        ok($dtd2, ' TODO : Add test name');
133
134#        $doc2->setInternalSubset( $dtd2 );
135#        warn $doc2->toString;
136
137#        $e->appendChild( $entity );
138#        warn $doc2->toString;
139    }
140}
141
142
143{
144    my $parser = XML::LibXML->new();
145    $parser->validation(1);
146    $parser->keep_blanks(1);
147    my $doc=$parser->parse_string(<<'EOF');
148<?xml version='1.0'?>
149<!DOCTYPE test [
150 <!ELEMENT test (#PCDATA)>
151]>
152<test>
153</test>
154EOF
155
156    # TEST
157    ok($doc->validate(), ' TODO : Add test name');
158
159    # TEST
160    ok($doc->is_valid(), ' TODO : Add test name');
161
162}
163
164{
165    my $parser = XML::LibXML->new();
166    $parser->validation(0);
167    $parser->load_ext_dtd(0); # This should make libxml not try to get the DTD
168
169    my $xml = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://localhost/does_not_exist.dtd">
170    <html xmlns="http://www.w3.org/1999/xhtml"><head><title>foo</title></head><body><p>bar</p></body></html>';
171    my $doc = eval {
172        $parser->parse_string($xml);
173    };
174
175    # TEST
176    ok(!$@, ' TODO : Add test name');
177    if ($@) {
178        warn "Parsing error: $@\n";
179    }
180
181    # TEST
182    ok($doc, ' TODO : Add test name');
183}
184
185{
186    my $bad = 'example/bad.dtd';
187    # TEST
188    ok( -f $bad, ' TODO : Add test name' );
189    eval { XML::LibXML::Dtd->new("-//Foo//Test DTD 1.0//EN", 'example/bad.dtd') };
190    # TEST
191    ok ($@, ' TODO : Add test name');
192
193    undef $@;
194    my $dtd = slurp($bad);
195
196    # TEST
197    ok( length($dtd) > 5, ' TODO : Add test name' );
198    eval { XML::LibXML::Dtd->parse_string($dtd) };
199    # TEST
200    ok ($@, ' TODO : Add test name');
201
202    my $xml = "<!DOCTYPE test SYSTEM \"example/bad.dtd\">\n<test/>";
203
204    {
205        my $parser = XML::LibXML->new;
206        $parser->load_ext_dtd(0);
207        $parser->validation(0);
208        my $doc = $parser->parse_string($xml);
209        # TEST
210        ok( $doc, ' TODO : Add test name' );
211    }
212    {
213        my $parser = XML::LibXML->new;
214        $parser->load_ext_dtd(1);
215        $parser->validation(0);
216        undef $@;
217        eval { $parser->parse_string($xml) };
218        # TEST
219        ok( $@, ' TODO : Add test name' );
220    }
221}
222
223{
224    # RT #71076: https://rt.cpan.org/Public/Bug/Display.html?id=71076
225
226    my $parser = XML::LibXML->new();
227    my $doc = $parser->parse_string(<<'EOF');
228<!DOCTYPE test [
229 <!ELEMENT test (#PCDATA)>
230 <!ATTLIST test
231  attr CDATA #IMPLIED
232 >
233]>
234<test>
235</test>
236EOF
237    my $dtd = $doc->internalSubset;
238
239    # TEST
240    ok( !$dtd->hasAttributes, 'hasAttributes' );
241    # TEST
242    is_deeply( [ $dtd->attributes ], [], 'attributes' );
243}
244
245# Remove DTD nodes
246
247sub test_remove_dtd {
248    my ($test_name, $remove_sub) = @_;
249
250    my $parser = XML::LibXML->new;
251    my $doc    = $parser->parse_file('example/dtd.xml');
252    my $dtd    = $doc->internalSubset;
253
254    $remove_sub->($doc, $dtd);
255
256    # TEST*3
257    ok( !$doc->internalSubset, "remove DTD via $test_name" );
258}
259
260test_remove_dtd( "unbindNode", sub {
261    my ($doc, $dtd) = @_;
262    $dtd->unbindNode;
263} );
264test_remove_dtd( "removeChild", sub {
265    my ($doc, $dtd) = @_;
266    $doc->removeChild($dtd);
267} );
268test_remove_dtd( "removeChildNodes", sub {
269    my ($doc, $dtd) = @_;
270    $doc->removeChildNodes;
271} );
272
273# Insert DTD nodes
274
275sub test_insert_dtd {
276    my ($test_name, $insert_sub) = @_;
277
278    my $parser  = XML::LibXML->new;
279    my $src_doc = $parser->parse_file('example/dtd.xml');
280    my $dtd     = $src_doc->internalSubset;
281    my $doc     = $parser->parse_file('example/dtd.xml');
282
283    $insert_sub->($doc, $dtd);
284
285    # TEST*11
286    ok( $doc->internalSubset->isSameNode($dtd), "insert DTD via $test_name" );
287}
288
289test_insert_dtd( "insertBefore internalSubset", sub {
290    my ($doc, $dtd) = @_;
291    $doc->insertBefore($dtd, $doc->internalSubset);
292} );
293test_insert_dtd( "insertBefore documentElement", sub {
294    my ($doc, $dtd) = @_;
295    $doc->insertBefore($dtd, $doc->documentElement);
296} );
297test_insert_dtd( "insertAfter internalSubset", sub {
298    my ($doc, $dtd) = @_;
299    $doc->insertAfter($dtd, $doc->internalSubset);
300} );
301test_insert_dtd( "insertAfter documentElement", sub {
302    my ($doc, $dtd) = @_;
303    $doc->insertAfter($dtd, $doc->documentElement);
304} );
305test_insert_dtd( "replaceChild internalSubset", sub {
306    my ($doc, $dtd) = @_;
307    $doc->replaceChild($dtd, $doc->internalSubset);
308} );
309test_insert_dtd( "replaceChild documentElement", sub {
310    my ($doc, $dtd) = @_;
311    $doc->replaceChild($dtd, $doc->documentElement);
312} );
313test_insert_dtd( "replaceNode internalSubset", sub {
314    my ($doc, $dtd) = @_;
315    $doc->internalSubset->replaceNode($dtd);
316} );
317test_insert_dtd( "replaceNode documentElement", sub {
318    my ($doc, $dtd) = @_;
319    $doc->documentElement->replaceNode($dtd);
320} );
321test_insert_dtd( "appendChild", sub {
322    my ($doc, $dtd) = @_;
323    $doc->appendChild($dtd);
324} );
325test_insert_dtd( "addSibling internalSubset", sub {
326    my ($doc, $dtd) = @_;
327    $doc->internalSubset->addSibling($dtd);
328} );
329test_insert_dtd( "addSibling documentElement", sub {
330    my ($doc, $dtd) = @_;
331    $doc->documentElement->addSibling($dtd);
332} );
333
334