1 |
/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd |
2 |
See the file COPYING for copying permission. |
3 |
|
4 |
runtest.c : run the Expat test suite |
5 |
*/ |
6 |
|
7 |
#ifdef HAVE_EXPAT_CONFIG_H |
8 |
#include <expat_config.h> |
9 |
#endif |
10 |
|
11 |
#include <assert.h> |
12 |
#include <stdlib.h> |
13 |
#include <stdio.h> |
14 |
#include <string.h> |
15 |
#include <stdint.h> |
16 |
|
17 |
#include "expat.h" |
18 |
#include "chardata.h" |
19 |
#include "minicheck.h" |
20 |
|
21 |
#if defined(__amigaos__) && defined(__USE_INLINE__) |
22 |
#include <proto/expat.h> |
23 |
#endif |
24 |
|
25 |
#ifdef XML_LARGE_SIZE |
26 |
#define XML_FMT_INT_MOD "ll" |
27 |
#else |
28 |
#define XML_FMT_INT_MOD "l" |
29 |
#endif |
30 |
|
31 |
static XML_Parser parser; |
32 |
|
33 |
|
34 |
static void |
35 |
basic_setup(void) |
36 |
{ |
37 |
parser = XML_ParserCreate(NULL); |
38 |
if (parser == NULL) |
39 |
fail("Parser not created."); |
40 |
} |
41 |
|
42 |
static void |
43 |
basic_teardown(void) |
44 |
{ |
45 |
if (parser != NULL) |
46 |
XML_ParserFree(parser); |
47 |
} |
48 |
|
49 |
/* Generate a failure using the parser state to create an error message; |
50 |
this should be used when the parser reports an error we weren't |
51 |
expecting. |
52 |
*/ |
53 |
static void |
54 |
_xml_failure(XML_Parser parser, const char *file, int line) |
55 |
{ |
56 |
char buffer[1024]; |
57 |
enum XML_Error err = XML_GetErrorCode(parser); |
58 |
sprintf(buffer, |
59 |
" %d: %s (line %" XML_FMT_INT_MOD "u, offset %"\ |
60 |
XML_FMT_INT_MOD "u)\n reported from %s, line %d\n", |
61 |
err, |
62 |
XML_ErrorString(err), |
63 |
XML_GetCurrentLineNumber(parser), |
64 |
XML_GetCurrentColumnNumber(parser), |
65 |
file, line); |
66 |
_fail_unless(0, file, line, buffer); |
67 |
} |
68 |
|
69 |
#define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__) |
70 |
|
71 |
static void |
72 |
_expect_failure(char *text, enum XML_Error errorCode, char *errorMessage, |
73 |
char *file, int lineno) |
74 |
{ |
75 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) |
76 |
/* Hackish use of _fail_unless() macro, but let's us report |
77 |
the right filename and line number. */ |
78 |
_fail_unless(0, file, lineno, errorMessage); |
79 |
if (XML_GetErrorCode(parser) != errorCode) |
80 |
_xml_failure(parser, file, lineno); |
81 |
} |
82 |
|
83 |
#define expect_failure(text, errorCode, errorMessage) \ |
84 |
_expect_failure((text), (errorCode), (errorMessage), \ |
85 |
__FILE__, __LINE__) |
86 |
|
87 |
/* Dummy handlers for when we need to set a handler to tickle a bug, |
88 |
but it doesn't need to do anything. |
89 |
*/ |
90 |
|
91 |
static void XMLCALL |
92 |
dummy_start_doctype_handler(void *userData, |
93 |
const XML_Char *doctypeName, |
94 |
const XML_Char *sysid, |
95 |
const XML_Char *pubid, |
96 |
int has_internal_subset) |
97 |
{} |
98 |
|
99 |
static void XMLCALL |
100 |
dummy_end_doctype_handler(void *userData) |
101 |
{} |
102 |
|
103 |
static void XMLCALL |
104 |
dummy_entity_decl_handler(void *userData, |
105 |
const XML_Char *entityName, |
106 |
int is_parameter_entity, |
107 |
const XML_Char *value, |
108 |
int value_length, |
109 |
const XML_Char *base, |
110 |
const XML_Char *systemId, |
111 |
const XML_Char *publicId, |
112 |
const XML_Char *notationName) |
113 |
{} |
114 |
|
115 |
static void XMLCALL |
116 |
dummy_notation_decl_handler(void *userData, |
117 |
const XML_Char *notationName, |
118 |
const XML_Char *base, |
119 |
const XML_Char *systemId, |
120 |
const XML_Char *publicId) |
121 |
{} |
122 |
|
123 |
static void XMLCALL |
124 |
dummy_element_decl_handler(void *userData, |
125 |
const XML_Char *name, |
126 |
XML_Content *model) |
127 |
{} |
128 |
|
129 |
static void XMLCALL |
130 |
dummy_attlist_decl_handler(void *userData, |
131 |
const XML_Char *elname, |
132 |
const XML_Char *attname, |
133 |
const XML_Char *att_type, |
134 |
const XML_Char *dflt, |
135 |
int isrequired) |
136 |
{} |
137 |
|
138 |
static void XMLCALL |
139 |
dummy_comment_handler(void *userData, const XML_Char *data) |
140 |
{} |
141 |
|
142 |
static void XMLCALL |
143 |
dummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data) |
144 |
{} |
145 |
|
146 |
static void XMLCALL |
147 |
dummy_start_element(void *userData, |
148 |
const XML_Char *name, const XML_Char **atts) |
149 |
{} |
150 |
|
151 |
|
152 |
/* |
153 |
* Character & encoding tests. |
154 |
*/ |
155 |
|
156 |
START_TEST(test_nul_byte) |
157 |
{ |
158 |
char text[] = "<doc>\0</doc>"; |
159 |
|
160 |
/* test that a NUL byte (in US-ASCII data) is an error */ |
161 |
if (XML_Parse(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_OK) |
162 |
fail("Parser did not report error on NUL-byte."); |
163 |
if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN) |
164 |
xml_failure(parser); |
165 |
} |
166 |
END_TEST |
167 |
|
168 |
|
169 |
START_TEST(test_u0000_char) |
170 |
{ |
171 |
/* test that a NUL byte (in US-ASCII data) is an error */ |
172 |
expect_failure("<doc>�</doc>", |
173 |
XML_ERROR_BAD_CHAR_REF, |
174 |
"Parser did not report error on NUL-byte."); |
175 |
} |
176 |
END_TEST |
177 |
|
178 |
START_TEST(test_bom_utf8) |
179 |
{ |
180 |
/* This test is really just making sure we don't core on a UTF-8 BOM. */ |
181 |
char *text = "\357\273\277<e/>"; |
182 |
|
183 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
184 |
xml_failure(parser); |
185 |
} |
186 |
END_TEST |
187 |
|
188 |
START_TEST(test_bom_utf16_be) |
189 |
{ |
190 |
char text[] = "\376\377\0<\0e\0/\0>"; |
191 |
|
192 |
if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR) |
193 |
xml_failure(parser); |
194 |
} |
195 |
END_TEST |
196 |
|
197 |
START_TEST(test_bom_utf16_le) |
198 |
{ |
199 |
char text[] = "\377\376<\0e\0/\0>\0"; |
200 |
|
201 |
if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR) |
202 |
xml_failure(parser); |
203 |
} |
204 |
END_TEST |
205 |
|
206 |
static void XMLCALL |
207 |
accumulate_characters(void *userData, const XML_Char *s, int len) |
208 |
{ |
209 |
CharData_AppendXMLChars((CharData *)userData, s, len); |
210 |
} |
211 |
|
212 |
static void XMLCALL |
213 |
accumulate_attribute(void *userData, const XML_Char *name, |
214 |
const XML_Char **atts) |
215 |
{ |
216 |
CharData *storage = (CharData *)userData; |
217 |
if (storage->count < 0 && atts != NULL && atts[0] != NULL) { |
218 |
/* "accumulate" the value of the first attribute we see */ |
219 |
CharData_AppendXMLChars(storage, atts[1], -1); |
220 |
} |
221 |
} |
222 |
|
223 |
|
224 |
static void |
225 |
_run_character_check(XML_Char *text, XML_Char *expected, |
226 |
const char *file, int line) |
227 |
{ |
228 |
CharData storage; |
229 |
|
230 |
CharData_Init(&storage); |
231 |
XML_SetUserData(parser, &storage); |
232 |
XML_SetCharacterDataHandler(parser, accumulate_characters); |
233 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
234 |
_xml_failure(parser, file, line); |
235 |
CharData_CheckXMLChars(&storage, expected); |
236 |
} |
237 |
|
238 |
#define run_character_check(text, expected) \ |
239 |
_run_character_check(text, expected, __FILE__, __LINE__) |
240 |
|
241 |
static void |
242 |
_run_attribute_check(XML_Char *text, XML_Char *expected, |
243 |
const char *file, int line) |
244 |
{ |
245 |
CharData storage; |
246 |
|
247 |
CharData_Init(&storage); |
248 |
XML_SetUserData(parser, &storage); |
249 |
XML_SetStartElementHandler(parser, accumulate_attribute); |
250 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
251 |
_xml_failure(parser, file, line); |
252 |
CharData_CheckXMLChars(&storage, expected); |
253 |
} |
254 |
|
255 |
#define run_attribute_check(text, expected) \ |
256 |
_run_attribute_check(text, expected, __FILE__, __LINE__) |
257 |
|
258 |
/* Regression test for SF bug #491986. */ |
259 |
START_TEST(test_danish_latin1) |
260 |
{ |
261 |
char *text = |
262 |
"<?xml version='1.0' encoding='iso-8859-1'?>\n" |
263 |
"<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>"; |
264 |
run_character_check(text, |
265 |
"J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85"); |
266 |
} |
267 |
END_TEST |
268 |
|
269 |
|
270 |
/* Regression test for SF bug #514281. */ |
271 |
START_TEST(test_french_charref_hexidecimal) |
272 |
{ |
273 |
char *text = |
274 |
"<?xml version='1.0' encoding='iso-8859-1'?>\n" |
275 |
"<doc>éèàçêÈ</doc>"; |
276 |
run_character_check(text, |
277 |
"\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); |
278 |
} |
279 |
END_TEST |
280 |
|
281 |
START_TEST(test_french_charref_decimal) |
282 |
{ |
283 |
char *text = |
284 |
"<?xml version='1.0' encoding='iso-8859-1'?>\n" |
285 |
"<doc>éèàçêÈ</doc>"; |
286 |
run_character_check(text, |
287 |
"\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); |
288 |
} |
289 |
END_TEST |
290 |
|
291 |
START_TEST(test_french_latin1) |
292 |
{ |
293 |
char *text = |
294 |
"<?xml version='1.0' encoding='iso-8859-1'?>\n" |
295 |
"<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>"; |
296 |
run_character_check(text, |
297 |
"\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88"); |
298 |
} |
299 |
END_TEST |
300 |
|
301 |
START_TEST(test_french_utf8) |
302 |
{ |
303 |
char *text = |
304 |
"<?xml version='1.0' encoding='utf-8'?>\n" |
305 |
"<doc>\xC3\xA9</doc>"; |
306 |
run_character_check(text, "\xC3\xA9"); |
307 |
} |
308 |
END_TEST |
309 |
|
310 |
/* Regression test for SF bug #600479. |
311 |
XXX There should be a test that exercises all legal XML Unicode |
312 |
characters as PCDATA and attribute value content, and XML Name |
313 |
characters as part of element and attribute names. |
314 |
*/ |
315 |
START_TEST(test_utf8_false_rejection) |
316 |
{ |
317 |
char *text = "<doc>\xEF\xBA\xBF</doc>"; |
318 |
run_character_check(text, "\xEF\xBA\xBF"); |
319 |
} |
320 |
END_TEST |
321 |
|
322 |
/* Regression test for SF bug #477667. |
323 |
This test assures that any 8-bit character followed by a 7-bit |
324 |
character will not be mistakenly interpreted as a valid UTF-8 |
325 |
sequence. |
326 |
*/ |
327 |
START_TEST(test_illegal_utf8) |
328 |
{ |
329 |
char text[100]; |
330 |
int i; |
331 |
|
332 |
for (i = 128; i <= 255; ++i) { |
333 |
sprintf(text, "<e>%ccd</e>", i); |
334 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) { |
335 |
sprintf(text, |
336 |
"expected token error for '%c' (ordinal %d) in UTF-8 text", |
337 |
i, i); |
338 |
fail(text); |
339 |
} |
340 |
else if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN) |
341 |
xml_failure(parser); |
342 |
/* Reset the parser since we use the same parser repeatedly. */ |
343 |
XML_ParserReset(parser, NULL); |
344 |
} |
345 |
} |
346 |
END_TEST |
347 |
|
348 |
START_TEST(test_utf16) |
349 |
{ |
350 |
/* <?xml version="1.0" encoding="UTF-16"?> |
351 |
<doc a='123'>some text</doc> |
352 |
*/ |
353 |
char text[] = |
354 |
"\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o" |
355 |
"\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o" |
356 |
"\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066" |
357 |
"\000'\000?\000>\000\n" |
358 |
"\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'" |
359 |
"\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/" |
360 |
"\000d\000o\000c\000>"; |
361 |
if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR) |
362 |
xml_failure(parser); |
363 |
} |
364 |
END_TEST |
365 |
|
366 |
START_TEST(test_utf16_le_epilog_newline) |
367 |
{ |
368 |
unsigned int first_chunk_bytes = 17; |
369 |
char text[] = |
370 |
"\xFF\xFE" /* BOM */ |
371 |
"<\000e\000/\000>\000" /* document element */ |
372 |
"\r\000\n\000\r\000\n\000"; /* epilog */ |
373 |
|
374 |
if (first_chunk_bytes >= sizeof(text) - 1) |
375 |
fail("bad value of first_chunk_bytes"); |
376 |
if ( XML_Parse(parser, text, first_chunk_bytes, XML_FALSE) |
377 |
== XML_STATUS_ERROR) |
378 |
xml_failure(parser); |
379 |
else { |
380 |
enum XML_Status rc; |
381 |
rc = XML_Parse(parser, text + first_chunk_bytes, |
382 |
sizeof(text) - first_chunk_bytes - 1, XML_TRUE); |
383 |
if (rc == XML_STATUS_ERROR) |
384 |
xml_failure(parser); |
385 |
} |
386 |
} |
387 |
END_TEST |
388 |
|
389 |
/* Regression test for SF bug #481609, #774028. */ |
390 |
START_TEST(test_latin1_umlauts) |
391 |
{ |
392 |
char *text = |
393 |
"<?xml version='1.0' encoding='iso-8859-1'?>\n" |
394 |
"<e a='\xE4 \xF6 \xFC ä ö ü ä ö ü >'\n" |
395 |
" >\xE4 \xF6 \xFC ä ö ü ä ö ü ></e>"; |
396 |
char *utf8 = |
397 |
"\xC3\xA4 \xC3\xB6 \xC3\xBC " |
398 |
"\xC3\xA4 \xC3\xB6 \xC3\xBC " |
399 |
"\xC3\xA4 \xC3\xB6 \xC3\xBC >"; |
400 |
run_character_check(text, utf8); |
401 |
XML_ParserReset(parser, NULL); |
402 |
run_attribute_check(text, utf8); |
403 |
} |
404 |
END_TEST |
405 |
|
406 |
/* Regression test #1 for SF bug #653180. */ |
407 |
START_TEST(test_line_number_after_parse) |
408 |
{ |
409 |
char *text = |
410 |
"<tag>\n" |
411 |
"\n" |
412 |
"\n</tag>"; |
413 |
XML_Size lineno; |
414 |
|
415 |
if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR) |
416 |
xml_failure(parser); |
417 |
lineno = XML_GetCurrentLineNumber(parser); |
418 |
if (lineno != 4) { |
419 |
char buffer[100]; |
420 |
sprintf(buffer, |
421 |
"expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno); |
422 |
fail(buffer); |
423 |
} |
424 |
} |
425 |
END_TEST |
426 |
|
427 |
/* Regression test #2 for SF bug #653180. */ |
428 |
START_TEST(test_column_number_after_parse) |
429 |
{ |
430 |
char *text = "<tag></tag>"; |
431 |
XML_Size colno; |
432 |
|
433 |
if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR) |
434 |
xml_failure(parser); |
435 |
colno = XML_GetCurrentColumnNumber(parser); |
436 |
if (colno != 11) { |
437 |
char buffer[100]; |
438 |
sprintf(buffer, |
439 |
"expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno); |
440 |
fail(buffer); |
441 |
} |
442 |
} |
443 |
END_TEST |
444 |
|
445 |
static void XMLCALL |
446 |
start_element_event_handler2(void *userData, const XML_Char *name, |
447 |
const XML_Char **attr) |
448 |
{ |
449 |
CharData *storage = (CharData *) userData; |
450 |
char buffer[100]; |
451 |
|
452 |
sprintf(buffer, |
453 |
"<%s> at col:%" XML_FMT_INT_MOD "u line:%"\ |
454 |
XML_FMT_INT_MOD "u\n", name, |
455 |
XML_GetCurrentColumnNumber(parser), |
456 |
XML_GetCurrentLineNumber(parser)); |
457 |
CharData_AppendString(storage, buffer); |
458 |
} |
459 |
|
460 |
static void XMLCALL |
461 |
end_element_event_handler2(void *userData, const XML_Char *name) |
462 |
{ |
463 |
CharData *storage = (CharData *) userData; |
464 |
char buffer[100]; |
465 |
|
466 |
sprintf(buffer, |
467 |
"</%s> at col:%" XML_FMT_INT_MOD "u line:%"\ |
468 |
XML_FMT_INT_MOD "u\n", name, |
469 |
XML_GetCurrentColumnNumber(parser), |
470 |
XML_GetCurrentLineNumber(parser)); |
471 |
CharData_AppendString(storage, buffer); |
472 |
} |
473 |
|
474 |
/* Regression test #3 for SF bug #653180. */ |
475 |
START_TEST(test_line_and_column_numbers_inside_handlers) |
476 |
{ |
477 |
char *text = |
478 |
"<a>\n" /* Unix end-of-line */ |
479 |
" <b>\r\n" /* Windows end-of-line */ |
480 |
" <c/>\r" /* Mac OS end-of-line */ |
481 |
" </b>\n" |
482 |
" <d>\n" |
483 |
" <f/>\n" |
484 |
" </d>\n" |
485 |
"</a>"; |
486 |
char *expected = |
487 |
"<a> at col:0 line:1\n" |
488 |
"<b> at col:2 line:2\n" |
489 |
"<c> at col:4 line:3\n" |
490 |
"</c> at col:8 line:3\n" |
491 |
"</b> at col:2 line:4\n" |
492 |
"<d> at col:2 line:5\n" |
493 |
"<f> at col:4 line:6\n" |
494 |
"</f> at col:8 line:6\n" |
495 |
"</d> at col:2 line:7\n" |
496 |
"</a> at col:0 line:8\n"; |
497 |
CharData storage; |
498 |
|
499 |
CharData_Init(&storage); |
500 |
XML_SetUserData(parser, &storage); |
501 |
XML_SetStartElementHandler(parser, start_element_event_handler2); |
502 |
XML_SetEndElementHandler(parser, end_element_event_handler2); |
503 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
504 |
xml_failure(parser); |
505 |
|
506 |
CharData_CheckString(&storage, expected); |
507 |
} |
508 |
END_TEST |
509 |
|
510 |
/* Regression test #4 for SF bug #653180. */ |
511 |
START_TEST(test_line_number_after_error) |
512 |
{ |
513 |
char *text = |
514 |
"<a>\n" |
515 |
" <b>\n" |
516 |
" </a>"; /* missing </b> */ |
517 |
XML_Size lineno; |
518 |
if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR) |
519 |
fail("Expected a parse error"); |
520 |
|
521 |
lineno = XML_GetCurrentLineNumber(parser); |
522 |
if (lineno != 3) { |
523 |
char buffer[100]; |
524 |
sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno); |
525 |
fail(buffer); |
526 |
} |
527 |
} |
528 |
END_TEST |
529 |
|
530 |
/* Regression test #5 for SF bug #653180. */ |
531 |
START_TEST(test_column_number_after_error) |
532 |
{ |
533 |
char *text = |
534 |
"<a>\n" |
535 |
" <b>\n" |
536 |
" </a>"; /* missing </b> */ |
537 |
XML_Size colno; |
538 |
if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR) |
539 |
fail("Expected a parse error"); |
540 |
|
541 |
colno = XML_GetCurrentColumnNumber(parser); |
542 |
if (colno != 4) { |
543 |
char buffer[100]; |
544 |
sprintf(buffer, |
545 |
"expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno); |
546 |
fail(buffer); |
547 |
} |
548 |
} |
549 |
END_TEST |
550 |
|
551 |
/* Regression test for SF bug #478332. */ |
552 |
START_TEST(test_really_long_lines) |
553 |
{ |
554 |
/* This parses an input line longer than INIT_DATA_BUF_SIZE |
555 |
characters long (defined to be 1024 in xmlparse.c). We take a |
556 |
really cheesy approach to building the input buffer, because |
557 |
this avoids writing bugs in buffer-filling code. |
558 |
*/ |
559 |
char *text = |
560 |
"<e>" |
561 |
/* 64 chars */ |
562 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
563 |
/* until we have at least 1024 characters on the line: */ |
564 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
565 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
566 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
567 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
568 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
569 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
570 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
571 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
572 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
573 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
574 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
575 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
576 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
577 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
578 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
579 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+" |
580 |
"</e>"; |
581 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
582 |
xml_failure(parser); |
583 |
} |
584 |
END_TEST |
585 |
|
586 |
|
587 |
/* |
588 |
* Element event tests. |
589 |
*/ |
590 |
|
591 |
static void XMLCALL |
592 |
end_element_event_handler(void *userData, const XML_Char *name) |
593 |
{ |
594 |
CharData *storage = (CharData *) userData; |
595 |
CharData_AppendString(storage, "/"); |
596 |
CharData_AppendXMLChars(storage, name, -1); |
597 |
} |
598 |
|
599 |
START_TEST(test_end_element_events) |
600 |
{ |
601 |
char *text = "<a><b><c/></b><d><f/></d></a>"; |
602 |
char *expected = "/c/b/f/d/a"; |
603 |
CharData storage; |
604 |
|
605 |
CharData_Init(&storage); |
606 |
XML_SetUserData(parser, &storage); |
607 |
XML_SetEndElementHandler(parser, end_element_event_handler); |
608 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
609 |
xml_failure(parser); |
610 |
CharData_CheckString(&storage, expected); |
611 |
} |
612 |
END_TEST |
613 |
|
614 |
|
615 |
/* |
616 |
* Attribute tests. |
617 |
*/ |
618 |
|
619 |
/* Helpers used by the following test; this checks any "attr" and "refs" |
620 |
attributes to make sure whitespace has been normalized. |
621 |
|
622 |
Return true if whitespace has been normalized in a string, using |
623 |
the rules for attribute value normalization. The 'is_cdata' flag |
624 |
is needed since CDATA attributes don't need to have multiple |
625 |
whitespace characters collapsed to a single space, while other |
626 |
attribute data types do. (Section 3.3.3 of the recommendation.) |
627 |
*/ |
628 |
static int |
629 |
is_whitespace_normalized(const XML_Char *s, int is_cdata) |
630 |
{ |
631 |
int blanks = 0; |
632 |
int at_start = 1; |
633 |
while (*s) { |
634 |
if (*s == ' ') |
635 |
++blanks; |
636 |
else if (*s == '\t' || *s == '\n' || *s == '\r') |
637 |
return 0; |
638 |
else { |
639 |
if (at_start) { |
640 |
at_start = 0; |
641 |
if (blanks && !is_cdata) |
642 |
/* illegal leading blanks */ |
643 |
return 0; |
644 |
} |
645 |
else if (blanks > 1 && !is_cdata) |
646 |
return 0; |
647 |
blanks = 0; |
648 |
} |
649 |
++s; |
650 |
} |
651 |
if (blanks && !is_cdata) |
652 |
return 0; |
653 |
return 1; |
654 |
} |
655 |
|
656 |
/* Check the attribute whitespace checker: */ |
657 |
static void |
658 |
testhelper_is_whitespace_normalized(void) |
659 |
{ |
660 |
assert(is_whitespace_normalized("abc", 0)); |
661 |
assert(is_whitespace_normalized("abc", 1)); |
662 |
assert(is_whitespace_normalized("abc def ghi", 0)); |
663 |
assert(is_whitespace_normalized("abc def ghi", 1)); |
664 |
assert(!is_whitespace_normalized(" abc def ghi", 0)); |
665 |
assert(is_whitespace_normalized(" abc def ghi", 1)); |
666 |
assert(!is_whitespace_normalized("abc def ghi", 0)); |
667 |
assert(is_whitespace_normalized("abc def ghi", 1)); |
668 |
assert(!is_whitespace_normalized("abc def ghi ", 0)); |
669 |
assert(is_whitespace_normalized("abc def ghi ", 1)); |
670 |
assert(!is_whitespace_normalized(" ", 0)); |
671 |
assert(is_whitespace_normalized(" ", 1)); |
672 |
assert(!is_whitespace_normalized("\t", 0)); |
673 |
assert(!is_whitespace_normalized("\t", 1)); |
674 |
assert(!is_whitespace_normalized("\n", 0)); |
675 |
assert(!is_whitespace_normalized("\n", 1)); |
676 |
assert(!is_whitespace_normalized("\r", 0)); |
677 |
assert(!is_whitespace_normalized("\r", 1)); |
678 |
assert(!is_whitespace_normalized("abc\t def", 1)); |
679 |
} |
680 |
|
681 |
static void XMLCALL |
682 |
check_attr_contains_normalized_whitespace(void *userData, |
683 |
const XML_Char *name, |
684 |
const XML_Char **atts) |
685 |
{ |
686 |
int i; |
687 |
for (i = 0; atts[i] != NULL; i += 2) { |
688 |
const XML_Char *attrname = atts[i]; |
689 |
const XML_Char *value = atts[i + 1]; |
690 |
if (strcmp("attr", attrname) == 0 |
691 |
|| strcmp("ents", attrname) == 0 |
692 |
|| strcmp("refs", attrname) == 0) { |
693 |
if (!is_whitespace_normalized(value, 0)) { |
694 |
char buffer[256]; |
695 |
sprintf(buffer, "attribute value not normalized: %s='%s'", |
696 |
attrname, value); |
697 |
fail(buffer); |
698 |
} |
699 |
} |
700 |
} |
701 |
} |
702 |
|
703 |
START_TEST(test_attr_whitespace_normalization) |
704 |
{ |
705 |
char *text = |
706 |
"<!DOCTYPE doc [\n" |
707 |
" <!ATTLIST doc\n" |
708 |
" attr NMTOKENS #REQUIRED\n" |
709 |
" ents ENTITIES #REQUIRED\n" |
710 |
" refs IDREFS #REQUIRED>\n" |
711 |
"]>\n" |
712 |
"<doc attr=' a b c\t\td\te\t' refs=' id-1 \t id-2\t\t' \n" |
713 |
" ents=' ent-1 \t\r\n" |
714 |
" ent-2 ' >\n" |
715 |
" <e id='id-1'/>\n" |
716 |
" <e id='id-2'/>\n" |
717 |
"</doc>"; |
718 |
|
719 |
XML_SetStartElementHandler(parser, |
720 |
check_attr_contains_normalized_whitespace); |
721 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
722 |
xml_failure(parser); |
723 |
} |
724 |
END_TEST |
725 |
|
726 |
|
727 |
/* |
728 |
* XML declaration tests. |
729 |
*/ |
730 |
|
731 |
START_TEST(test_xmldecl_misplaced) |
732 |
{ |
733 |
expect_failure("\n" |
734 |
"<?xml version='1.0'?>\n" |
735 |
"<a/>", |
736 |
XML_ERROR_MISPLACED_XML_PI, |
737 |
"failed to report misplaced XML declaration"); |
738 |
} |
739 |
END_TEST |
740 |
|
741 |
/* Regression test for SF bug #584832. */ |
742 |
static int XMLCALL |
743 |
UnknownEncodingHandler(void *data,const XML_Char *encoding,XML_Encoding *info) |
744 |
{ |
745 |
if (strcmp(encoding,"unsupported-encoding") == 0) { |
746 |
int i; |
747 |
for (i = 0; i < 256; ++i) |
748 |
info->map[i] = i; |
749 |
info->data = NULL; |
750 |
info->convert = NULL; |
751 |
info->release = NULL; |
752 |
return XML_STATUS_OK; |
753 |
} |
754 |
return XML_STATUS_ERROR; |
755 |
} |
756 |
|
757 |
START_TEST(test_unknown_encoding_internal_entity) |
758 |
{ |
759 |
char *text = |
760 |
"<?xml version='1.0' encoding='unsupported-encoding'?>\n" |
761 |
"<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n" |
762 |
"<test a='&foo;'/>"; |
763 |
|
764 |
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL); |
765 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
766 |
xml_failure(parser); |
767 |
} |
768 |
END_TEST |
769 |
|
770 |
/* Regression test for SF bug #620106. */ |
771 |
static int XMLCALL |
772 |
external_entity_loader_set_encoding(XML_Parser parser, |
773 |
const XML_Char *context, |
774 |
const XML_Char *base, |
775 |
const XML_Char *systemId, |
776 |
const XML_Char *publicId) |
777 |
{ |
778 |
/* This text says it's an unsupported encoding, but it's really |
779 |
UTF-8, which we tell Expat using XML_SetEncoding(). |
780 |
*/ |
781 |
char *text = |
782 |
"<?xml encoding='iso-8859-3'?>" |
783 |
"\xC3\xA9"; |
784 |
XML_Parser extparser; |
785 |
|
786 |
extparser = XML_ExternalEntityParserCreate(parser, context, NULL); |
787 |
if (extparser == NULL) |
788 |
fail("Could not create external entity parser."); |
789 |
if (!XML_SetEncoding(extparser, "utf-8")) |
790 |
fail("XML_SetEncoding() ignored for external entity"); |
791 |
if ( XML_Parse(extparser, text, strlen(text), XML_TRUE) |
792 |
== XML_STATUS_ERROR) { |
793 |
xml_failure(parser); |
794 |
return 0; |
795 |
} |
796 |
return 1; |
797 |
} |
798 |
|
799 |
START_TEST(test_ext_entity_set_encoding) |
800 |
{ |
801 |
char *text = |
802 |
"<!DOCTYPE doc [\n" |
803 |
" <!ENTITY en SYSTEM 'http://xml.libexpat.org/dummy.ent'>\n" |
804 |
"]>\n" |
805 |
"<doc>&en;</doc>"; |
806 |
|
807 |
XML_SetExternalEntityRefHandler(parser, |
808 |
external_entity_loader_set_encoding); |
809 |
run_character_check(text, "\xC3\xA9"); |
810 |
} |
811 |
END_TEST |
812 |
|
813 |
/* Test that no error is reported for unknown entities if we don't |
814 |
read an external subset. This was fixed in Expat 1.95.5. |
815 |
*/ |
816 |
START_TEST(test_wfc_undeclared_entity_unread_external_subset) { |
817 |
char *text = |
818 |
"<!DOCTYPE doc SYSTEM 'foo'>\n" |
819 |
"<doc>&entity;</doc>"; |
820 |
|
821 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
822 |
xml_failure(parser); |
823 |
} |
824 |
END_TEST |
825 |
|
826 |
/* Test that an error is reported for unknown entities if we don't |
827 |
have an external subset. |
828 |
*/ |
829 |
START_TEST(test_wfc_undeclared_entity_no_external_subset) { |
830 |
expect_failure("<doc>&entity;</doc>", |
831 |
XML_ERROR_UNDEFINED_ENTITY, |
832 |
"Parser did not report undefined entity w/out a DTD."); |
833 |
} |
834 |
END_TEST |
835 |
|
836 |
/* Test that an error is reported for unknown entities if we don't |
837 |
read an external subset, but have been declared standalone. |
838 |
*/ |
839 |
START_TEST(test_wfc_undeclared_entity_standalone) { |
840 |
char *text = |
841 |
"<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n" |
842 |
"<!DOCTYPE doc SYSTEM 'foo'>\n" |
843 |
"<doc>&entity;</doc>"; |
844 |
|
845 |
expect_failure(text, |
846 |
XML_ERROR_UNDEFINED_ENTITY, |
847 |
"Parser did not report undefined entity (standalone)."); |
848 |
} |
849 |
END_TEST |
850 |
|
851 |
static int XMLCALL |
852 |
external_entity_loader(XML_Parser parser, |
853 |
const XML_Char *context, |
854 |
const XML_Char *base, |
855 |
const XML_Char *systemId, |
856 |
const XML_Char *publicId) |
857 |
{ |
858 |
char *text = (char *)XML_GetUserData(parser); |
859 |
XML_Parser extparser; |
860 |
|
861 |
extparser = XML_ExternalEntityParserCreate(parser, context, NULL); |
862 |
if (extparser == NULL) |
863 |
fail("Could not create external entity parser."); |
864 |
if ( XML_Parse(extparser, text, strlen(text), XML_TRUE) |
865 |
== XML_STATUS_ERROR) { |
866 |
xml_failure(parser); |
867 |
return XML_STATUS_ERROR; |
868 |
} |
869 |
return XML_STATUS_OK; |
870 |
} |
871 |
|
872 |
/* Test that an error is reported for unknown entities if we have read |
873 |
an external subset, and standalone is true. |
874 |
*/ |
875 |
START_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) { |
876 |
char *text = |
877 |
"<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n" |
878 |
"<!DOCTYPE doc SYSTEM 'foo'>\n" |
879 |
"<doc>&entity;</doc>"; |
880 |
char *foo_text = |
881 |
"<!ELEMENT doc (#PCDATA)*>"; |
882 |
|
883 |
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); |
884 |
XML_SetUserData(parser, foo_text); |
885 |
XML_SetExternalEntityRefHandler(parser, external_entity_loader); |
886 |
expect_failure(text, |
887 |
XML_ERROR_UNDEFINED_ENTITY, |
888 |
"Parser did not report undefined entity (external DTD)."); |
889 |
} |
890 |
END_TEST |
891 |
|
892 |
/* Test that no error is reported for unknown entities if we have read |
893 |
an external subset, and standalone is false. |
894 |
*/ |
895 |
START_TEST(test_wfc_undeclared_entity_with_external_subset) { |
896 |
char *text = |
897 |
"<?xml version='1.0' encoding='us-ascii'?>\n" |
898 |
"<!DOCTYPE doc SYSTEM 'foo'>\n" |
899 |
"<doc>&entity;</doc>"; |
900 |
char *foo_text = |
901 |
"<!ELEMENT doc (#PCDATA)*>"; |
902 |
|
903 |
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); |
904 |
XML_SetUserData(parser, foo_text); |
905 |
XML_SetExternalEntityRefHandler(parser, external_entity_loader); |
906 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
907 |
xml_failure(parser); |
908 |
} |
909 |
END_TEST |
910 |
|
911 |
START_TEST(test_wfc_no_recursive_entity_refs) |
912 |
{ |
913 |
char *text = |
914 |
"<!DOCTYPE doc [\n" |
915 |
" <!ENTITY entity '&entity;'>\n" |
916 |
"]>\n" |
917 |
"<doc>&entity;</doc>"; |
918 |
|
919 |
expect_failure(text, |
920 |
XML_ERROR_RECURSIVE_ENTITY_REF, |
921 |
"Parser did not report recursive entity reference."); |
922 |
} |
923 |
END_TEST |
924 |
|
925 |
/* Regression test for SF bug #483514. */ |
926 |
START_TEST(test_dtd_default_handling) |
927 |
{ |
928 |
char *text = |
929 |
"<!DOCTYPE doc [\n" |
930 |
"<!ENTITY e SYSTEM 'http://xml.libexpat.org/e'>\n" |
931 |
"<!NOTATION n SYSTEM 'http://xml.libexpat.org/n'>\n" |
932 |
"<!ELEMENT doc EMPTY>\n" |
933 |
"<!ATTLIST doc a CDATA #IMPLIED>\n" |
934 |
"<?pi in dtd?>\n" |
935 |
"<!--comment in dtd-->\n" |
936 |
"]><doc/>"; |
937 |
|
938 |
XML_SetDefaultHandler(parser, accumulate_characters); |
939 |
XML_SetDoctypeDeclHandler(parser, |
940 |
dummy_start_doctype_handler, |
941 |
dummy_end_doctype_handler); |
942 |
XML_SetEntityDeclHandler(parser, dummy_entity_decl_handler); |
943 |
XML_SetNotationDeclHandler(parser, dummy_notation_decl_handler); |
944 |
XML_SetElementDeclHandler(parser, dummy_element_decl_handler); |
945 |
XML_SetAttlistDeclHandler(parser, dummy_attlist_decl_handler); |
946 |
XML_SetProcessingInstructionHandler(parser, dummy_pi_handler); |
947 |
XML_SetCommentHandler(parser, dummy_comment_handler); |
948 |
run_character_check(text, "\n\n\n\n\n\n\n<doc/>"); |
949 |
} |
950 |
END_TEST |
951 |
|
952 |
/* See related SF bug #673791. |
953 |
When namespace processing is enabled, setting the namespace URI for |
954 |
a prefix is not allowed; this test ensures that it *is* allowed |
955 |
when namespace processing is not enabled. |
956 |
(See Namespaces in XML, section 2.) |
957 |
*/ |
958 |
START_TEST(test_empty_ns_without_namespaces) |
959 |
{ |
960 |
char *text = |
961 |
"<doc xmlns:prefix='http://www.example.com/'>\n" |
962 |
" <e xmlns:prefix=''/>\n" |
963 |
"</doc>"; |
964 |
|
965 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
966 |
xml_failure(parser); |
967 |
} |
968 |
END_TEST |
969 |
|
970 |
/* Regression test for SF bug #824420. |
971 |
Checks that an xmlns:prefix attribute set in an attribute's default |
972 |
value isn't misinterpreted. |
973 |
*/ |
974 |
START_TEST(test_ns_in_attribute_default_without_namespaces) |
975 |
{ |
976 |
char *text = |
977 |
"<!DOCTYPE e:element [\n" |
978 |
" <!ATTLIST e:element\n" |
979 |
" xmlns:e CDATA 'http://example.com/'>\n" |
980 |
" ]>\n" |
981 |
"<e:element/>"; |
982 |
|
983 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
984 |
xml_failure(parser); |
985 |
} |
986 |
END_TEST |
987 |
|
988 |
static char *long_character_data_text = |
989 |
"<?xml version='1.0' encoding='iso-8859-1'?><s>" |
990 |
"012345678901234567890123456789012345678901234567890123456789" |
991 |
"012345678901234567890123456789012345678901234567890123456789" |
992 |
"012345678901234567890123456789012345678901234567890123456789" |
993 |
"012345678901234567890123456789012345678901234567890123456789" |
994 |
"012345678901234567890123456789012345678901234567890123456789" |
995 |
"012345678901234567890123456789012345678901234567890123456789" |
996 |
"012345678901234567890123456789012345678901234567890123456789" |
997 |
"012345678901234567890123456789012345678901234567890123456789" |
998 |
"012345678901234567890123456789012345678901234567890123456789" |
999 |
"012345678901234567890123456789012345678901234567890123456789" |
1000 |
"012345678901234567890123456789012345678901234567890123456789" |
1001 |
"012345678901234567890123456789012345678901234567890123456789" |
1002 |
"012345678901234567890123456789012345678901234567890123456789" |
1003 |
"012345678901234567890123456789012345678901234567890123456789" |
1004 |
"012345678901234567890123456789012345678901234567890123456789" |
1005 |
"012345678901234567890123456789012345678901234567890123456789" |
1006 |
"012345678901234567890123456789012345678901234567890123456789" |
1007 |
"012345678901234567890123456789012345678901234567890123456789" |
1008 |
"012345678901234567890123456789012345678901234567890123456789" |
1009 |
"012345678901234567890123456789012345678901234567890123456789" |
1010 |
"</s>"; |
1011 |
|
1012 |
static XML_Bool resumable = XML_FALSE; |
1013 |
|
1014 |
static void |
1015 |
clearing_aborting_character_handler(void *userData, |
1016 |
const XML_Char *s, int len) |
1017 |
{ |
1018 |
XML_StopParser(parser, resumable); |
1019 |
XML_SetCharacterDataHandler(parser, NULL); |
1020 |
} |
1021 |
|
1022 |
/* Regression test for SF bug #1515266: missing check of stopped |
1023 |
parser in doContext() 'for' loop. */ |
1024 |
START_TEST(test_stop_parser_between_char_data_calls) |
1025 |
{ |
1026 |
/* The sample data must be big enough that there are two calls to |
1027 |
the character data handler from within the inner "for" loop of |
1028 |
the XML_TOK_DATA_CHARS case in doContent(), and the character |
1029 |
handler must stop the parser and clear the character data |
1030 |
handler. |
1031 |
*/ |
1032 |
char *text = long_character_data_text; |
1033 |
|
1034 |
XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler); |
1035 |
resumable = XML_FALSE; |
1036 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR) |
1037 |
xml_failure(parser); |
1038 |
if (XML_GetErrorCode(parser) != XML_ERROR_ABORTED) |
1039 |
xml_failure(parser); |
1040 |
} |
1041 |
END_TEST |
1042 |
|
1043 |
/* Regression test for SF bug #1515266: missing check of stopped |
1044 |
parser in doContext() 'for' loop. */ |
1045 |
START_TEST(test_suspend_parser_between_char_data_calls) |
1046 |
{ |
1047 |
/* The sample data must be big enough that there are two calls to |
1048 |
the character data handler from within the inner "for" loop of |
1049 |
the XML_TOK_DATA_CHARS case in doContent(), and the character |
1050 |
handler must stop the parser and clear the character data |
1051 |
handler. |
1052 |
*/ |
1053 |
char *text = long_character_data_text; |
1054 |
|
1055 |
XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler); |
1056 |
resumable = XML_TRUE; |
1057 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_SUSPENDED) |
1058 |
xml_failure(parser); |
1059 |
if (XML_GetErrorCode(parser) != XML_ERROR_NONE) |
1060 |
xml_failure(parser); |
1061 |
} |
1062 |
END_TEST |
1063 |
|
1064 |
|
1065 |
/* |
1066 |
* Namespaces tests. |
1067 |
*/ |
1068 |
|
1069 |
static void |
1070 |
namespace_setup(void) |
1071 |
{ |
1072 |
parser = XML_ParserCreateNS(NULL, ' '); |
1073 |
if (parser == NULL) |
1074 |
fail("Parser not created."); |
1075 |
} |
1076 |
|
1077 |
static void |
1078 |
namespace_teardown(void) |
1079 |
{ |
1080 |
basic_teardown(); |
1081 |
} |
1082 |
|
1083 |
/* Check that an element name and attribute name match the expected values. |
1084 |
The expected values are passed as an array reference of string pointers |
1085 |
provided as the userData argument; the first is the expected |
1086 |
element name, and the second is the expected attribute name. |
1087 |
*/ |
1088 |
static void XMLCALL |
1089 |
triplet_start_checker(void *userData, const XML_Char *name, |
1090 |
const XML_Char **atts) |
1091 |
{ |
1092 |
char **elemstr = (char **)userData; |
1093 |
char buffer[1024]; |
1094 |
if (strcmp(elemstr[0], name) != 0) { |
1095 |
sprintf(buffer, "unexpected start string: '%s'", name); |
1096 |
fail(buffer); |
1097 |
} |
1098 |
if (strcmp(elemstr[1], atts[0]) != 0) { |
1099 |
sprintf(buffer, "unexpected attribute string: '%s'", atts[0]); |
1100 |
fail(buffer); |
1101 |
} |
1102 |
} |
1103 |
|
1104 |
/* Check that the element name passed to the end-element handler matches |
1105 |
the expected value. The expected value is passed as the first element |
1106 |
in an array of strings passed as the userData argument. |
1107 |
*/ |
1108 |
static void XMLCALL |
1109 |
triplet_end_checker(void *userData, const XML_Char *name) |
1110 |
{ |
1111 |
char **elemstr = (char **)userData; |
1112 |
if (strcmp(elemstr[0], name) != 0) { |
1113 |
char buffer[1024]; |
1114 |
sprintf(buffer, "unexpected end string: '%s'", name); |
1115 |
fail(buffer); |
1116 |
} |
1117 |
} |
1118 |
|
1119 |
START_TEST(test_return_ns_triplet) |
1120 |
{ |
1121 |
char *text = |
1122 |
"<foo:e xmlns:foo='http://expat.sf.net/' bar:a='12'\n" |
1123 |
" xmlns:bar='http://expat.sf.net/'></foo:e>"; |
1124 |
char *elemstr[] = { |
1125 |
"http://expat.sf.net/ e foo", |
1126 |
"http://expat.sf.net/ a bar" |
1127 |
}; |
1128 |
XML_SetReturnNSTriplet(parser, XML_TRUE); |
1129 |
XML_SetUserData(parser, elemstr); |
1130 |
XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker); |
1131 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
1132 |
xml_failure(parser); |
1133 |
} |
1134 |
END_TEST |
1135 |
|
1136 |
static void XMLCALL |
1137 |
overwrite_start_checker(void *userData, const XML_Char *name, |
1138 |
const XML_Char **atts) |
1139 |
{ |
1140 |
CharData *storage = (CharData *) userData; |
1141 |
CharData_AppendString(storage, "start "); |
1142 |
CharData_AppendXMLChars(storage, name, -1); |
1143 |
while (*atts != NULL) { |
1144 |
CharData_AppendString(storage, "\nattribute "); |
1145 |
CharData_AppendXMLChars(storage, *atts, -1); |
1146 |
atts += 2; |
1147 |
} |
1148 |
CharData_AppendString(storage, "\n"); |
1149 |
} |
1150 |
|
1151 |
static void XMLCALL |
1152 |
overwrite_end_checker(void *userData, const XML_Char *name) |
1153 |
{ |
1154 |
CharData *storage = (CharData *) userData; |
1155 |
CharData_AppendString(storage, "end "); |
1156 |
CharData_AppendXMLChars(storage, name, -1); |
1157 |
CharData_AppendString(storage, "\n"); |
1158 |
} |
1159 |
|
1160 |
static void |
1161 |
run_ns_tagname_overwrite_test(char *text, char *result) |
1162 |
{ |
1163 |
CharData storage; |
1164 |
CharData_Init(&storage); |
1165 |
XML_SetUserData(parser, &storage); |
1166 |
XML_SetElementHandler(parser, |
1167 |
overwrite_start_checker, overwrite_end_checker); |
1168 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
1169 |
xml_failure(parser); |
1170 |
CharData_CheckString(&storage, result); |
1171 |
} |
1172 |
|
1173 |
/* Regression test for SF bug #566334. */ |
1174 |
START_TEST(test_ns_tagname_overwrite) |
1175 |
{ |
1176 |
char *text = |
1177 |
"<n:e xmlns:n='http://xml.libexpat.org/'>\n" |
1178 |
" <n:f n:attr='foo'/>\n" |
1179 |
" <n:g n:attr2='bar'/>\n" |
1180 |
"</n:e>"; |
1181 |
char *result = |
1182 |
"start http://xml.libexpat.org/ e\n" |
1183 |
"start http://xml.libexpat.org/ f\n" |
1184 |
"attribute http://xml.libexpat.org/ attr\n" |
1185 |
"end http://xml.libexpat.org/ f\n" |
1186 |
"start http://xml.libexpat.org/ g\n" |
1187 |
"attribute http://xml.libexpat.org/ attr2\n" |
1188 |
"end http://xml.libexpat.org/ g\n" |
1189 |
"end http://xml.libexpat.org/ e\n"; |
1190 |
run_ns_tagname_overwrite_test(text, result); |
1191 |
} |
1192 |
END_TEST |
1193 |
|
1194 |
/* Regression test for SF bug #566334. */ |
1195 |
START_TEST(test_ns_tagname_overwrite_triplet) |
1196 |
{ |
1197 |
char *text = |
1198 |
"<n:e xmlns:n='http://xml.libexpat.org/'>\n" |
1199 |
" <n:f n:attr='foo'/>\n" |
1200 |
" <n:g n:attr2='bar'/>\n" |
1201 |
"</n:e>"; |
1202 |
char *result = |
1203 |
"start http://xml.libexpat.org/ e n\n" |
1204 |
"start http://xml.libexpat.org/ f n\n" |
1205 |
"attribute http://xml.libexpat.org/ attr n\n" |
1206 |
"end http://xml.libexpat.org/ f n\n" |
1207 |
"start http://xml.libexpat.org/ g n\n" |
1208 |
"attribute http://xml.libexpat.org/ attr2 n\n" |
1209 |
"end http://xml.libexpat.org/ g n\n" |
1210 |
"end http://xml.libexpat.org/ e n\n"; |
1211 |
XML_SetReturnNSTriplet(parser, XML_TRUE); |
1212 |
run_ns_tagname_overwrite_test(text, result); |
1213 |
} |
1214 |
END_TEST |
1215 |
|
1216 |
|
1217 |
/* Regression test for SF bug #620343. */ |
1218 |
static void XMLCALL |
1219 |
start_element_fail(void *userData, |
1220 |
const XML_Char *name, const XML_Char **atts) |
1221 |
{ |
1222 |
/* We should never get here. */ |
1223 |
fail("should never reach start_element_fail()"); |
1224 |
} |
1225 |
|
1226 |
static void XMLCALL |
1227 |
start_ns_clearing_start_element(void *userData, |
1228 |
const XML_Char *prefix, |
1229 |
const XML_Char *uri) |
1230 |
{ |
1231 |
XML_SetStartElementHandler((XML_Parser) userData, NULL); |
1232 |
} |
1233 |
|
1234 |
START_TEST(test_start_ns_clears_start_element) |
1235 |
{ |
1236 |
/* This needs to use separate start/end tags; using the empty tag |
1237 |
syntax doesn't cause the problematic path through Expat to be |
1238 |
taken. |
1239 |
*/ |
1240 |
char *text = "<e xmlns='http://xml.libexpat.org/'></e>"; |
1241 |
|
1242 |
XML_SetStartElementHandler(parser, start_element_fail); |
1243 |
XML_SetStartNamespaceDeclHandler(parser, start_ns_clearing_start_element); |
1244 |
XML_UseParserAsHandlerArg(parser); |
1245 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
1246 |
xml_failure(parser); |
1247 |
} |
1248 |
END_TEST |
1249 |
|
1250 |
/* Regression test for SF bug #616863. */ |
1251 |
static int XMLCALL |
1252 |
external_entity_handler(XML_Parser parser, |
1253 |
const XML_Char *context, |
1254 |
const XML_Char *base, |
1255 |
const XML_Char *systemId, |
1256 |
const XML_Char *publicId) |
1257 |
{ |
1258 |
intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser); |
1259 |
char *text; |
1260 |
XML_Parser p2; |
1261 |
|
1262 |
if (callno == 1) |
1263 |
text = ("<!ELEMENT doc (e+)>\n" |
1264 |
"<!ATTLIST doc xmlns CDATA #IMPLIED>\n" |
1265 |
"<!ELEMENT e EMPTY>\n"); |
1266 |
else |
1267 |
text = ("<?xml version='1.0' encoding='us-ascii'?>" |
1268 |
"<e/>"); |
1269 |
|
1270 |
XML_SetUserData(parser, (void *) callno); |
1271 |
p2 = XML_ExternalEntityParserCreate(parser, context, NULL); |
1272 |
if (XML_Parse(p2, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) { |
1273 |
xml_failure(p2); |
1274 |
return 0; |
1275 |
} |
1276 |
XML_ParserFree(p2); |
1277 |
return 1; |
1278 |
} |
1279 |
|
1280 |
START_TEST(test_default_ns_from_ext_subset_and_ext_ge) |
1281 |
{ |
1282 |
char *text = |
1283 |
"<?xml version='1.0'?>\n" |
1284 |
"<!DOCTYPE doc SYSTEM 'http://xml.libexpat.org/doc.dtd' [\n" |
1285 |
" <!ENTITY en SYSTEM 'http://xml.libexpat.org/entity.ent'>\n" |
1286 |
"]>\n" |
1287 |
"<doc xmlns='http://xml.libexpat.org/ns1'>\n" |
1288 |
"&en;\n" |
1289 |
"</doc>"; |
1290 |
|
1291 |
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS); |
1292 |
XML_SetExternalEntityRefHandler(parser, external_entity_handler); |
1293 |
/* We actually need to set this handler to tickle this bug. */ |
1294 |
XML_SetStartElementHandler(parser, dummy_start_element); |
1295 |
XML_SetUserData(parser, NULL); |
1296 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
1297 |
xml_failure(parser); |
1298 |
} |
1299 |
END_TEST |
1300 |
|
1301 |
/* Regression test #1 for SF bug #673791. */ |
1302 |
START_TEST(test_ns_prefix_with_empty_uri_1) |
1303 |
{ |
1304 |
char *text = |
1305 |
"<doc xmlns:prefix='http://xml.libexpat.org/'>\n" |
1306 |
" <e xmlns:prefix=''/>\n" |
1307 |
"</doc>"; |
1308 |
|
1309 |
expect_failure(text, |
1310 |
XML_ERROR_UNDECLARING_PREFIX, |
1311 |
"Did not report re-setting namespace" |
1312 |
" URI with prefix to ''."); |
1313 |
} |
1314 |
END_TEST |
1315 |
|
1316 |
/* Regression test #2 for SF bug #673791. */ |
1317 |
START_TEST(test_ns_prefix_with_empty_uri_2) |
1318 |
{ |
1319 |
char *text = |
1320 |
"<?xml version='1.0'?>\n" |
1321 |
"<docelem xmlns:pre=''/>"; |
1322 |
|
1323 |
expect_failure(text, |
1324 |
XML_ERROR_UNDECLARING_PREFIX, |
1325 |
"Did not report setting namespace URI with prefix to ''."); |
1326 |
} |
1327 |
END_TEST |
1328 |
|
1329 |
/* Regression test #3 for SF bug #673791. */ |
1330 |
START_TEST(test_ns_prefix_with_empty_uri_3) |
1331 |
{ |
1332 |
char *text = |
1333 |
"<!DOCTYPE doc [\n" |
1334 |
" <!ELEMENT doc EMPTY>\n" |
1335 |
" <!ATTLIST doc\n" |
1336 |
" xmlns:prefix CDATA ''>\n" |
1337 |
"]>\n" |
1338 |
"<doc/>"; |
1339 |
|
1340 |
expect_failure(text, |
1341 |
XML_ERROR_UNDECLARING_PREFIX, |
1342 |
"Didn't report attr default setting NS w/ prefix to ''."); |
1343 |
} |
1344 |
END_TEST |
1345 |
|
1346 |
/* Regression test #4 for SF bug #673791. */ |
1347 |
START_TEST(test_ns_prefix_with_empty_uri_4) |
1348 |
{ |
1349 |
char *text = |
1350 |
"<!DOCTYPE doc [\n" |
1351 |
" <!ELEMENT prefix:doc EMPTY>\n" |
1352 |
" <!ATTLIST prefix:doc\n" |
1353 |
" xmlns:prefix CDATA 'http://xml.libexpat.org/'>\n" |
1354 |
"]>\n" |
1355 |
"<prefix:doc/>"; |
1356 |
/* Packaged info expected by the end element handler; |
1357 |
the weird structuring lets us re-use the triplet_end_checker() |
1358 |
function also used for another test. */ |
1359 |
char *elemstr[] = { |
1360 |
"http://xml.libexpat.org/ doc prefix" |
1361 |
}; |
1362 |
XML_SetReturnNSTriplet(parser, XML_TRUE); |
1363 |
XML_SetUserData(parser, elemstr); |
1364 |
XML_SetEndElementHandler(parser, triplet_end_checker); |
1365 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
1366 |
xml_failure(parser); |
1367 |
} |
1368 |
END_TEST |
1369 |
|
1370 |
START_TEST(test_ns_default_with_empty_uri) |
1371 |
{ |
1372 |
char *text = |
1373 |
"<doc xmlns='http://xml.libexpat.org/'>\n" |
1374 |
" <e xmlns=''/>\n" |
1375 |
"</doc>"; |
1376 |
if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) |
1377 |
xml_failure(parser); |
1378 |
} |
1379 |
END_TEST |
1380 |
|
1381 |
/* Regression test for SF bug #692964: two prefixes for one namespace. */ |
1382 |
START_TEST(test_ns_duplicate_attrs_diff_prefixes) |
1383 |
{ |
1384 |
char *text = |
1385 |
"<doc xmlns:a='http://xml.libexpat.org/a'\n" |
1386 |
" xmlns:b='http://xml.libexpat.org/a'\n" |
1387 |
" a:a='v' b:a='v' />"; |
1388 |
expect_failure(text, |
1389 |
XML_ERROR_DUPLICATE_ATTRIBUTE, |
1390 |
"did not report multiple attributes with same URI+name"); |
1391 |
} |
1392 |
END_TEST |
1393 |
|
1394 |
/* Regression test for SF bug #695401: unbound prefix. */ |
1395 |
START_TEST(test_ns_unbound_prefix_on_attribute) |
1396 |
{ |
1397 |
char *text = "<doc a:attr=''/>"; |
1398 |
expect_failure(text, |
1399 |
XML_ERROR_UNBOUND_PREFIX, |
1400 |
"did not report unbound prefix on attribute"); |
1401 |
} |
1402 |
END_TEST |
1403 |
|
1404 |
/* Regression test for SF bug #695401: unbound prefix. */ |
1405 |
START_TEST(test_ns_unbound_prefix_on_element) |
1406 |
{ |
1407 |
char *text = "<a:doc/>"; |
1408 |
expect_failure(text, |
1409 |
XML_ERROR_UNBOUND_PREFIX, |
1410 |
"did not report unbound prefix on element"); |
1411 |
} |
1412 |
END_TEST |
1413 |
|
1414 |
static Suite * |
1415 |
make_suite(void) |
1416 |
{ |
1417 |
Suite *s = suite_create("basic"); |
1418 |
TCase *tc_basic = tcase_create("basic tests"); |
1419 |
TCase *tc_namespace = tcase_create("XML namespaces"); |
1420 |
|
1421 |
suite_add_tcase(s, tc_basic); |
1422 |
tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown); |
1423 |
tcase_add_test(tc_basic, test_nul_byte); |
1424 |
tcase_add_test(tc_basic, test_u0000_char); |
1425 |
tcase_add_test(tc_basic, test_bom_utf8); |
1426 |
tcase_add_test(tc_basic, test_bom_utf16_be); |
1427 |
tcase_add_test(tc_basic, test_bom_utf16_le); |
1428 |
tcase_add_test(tc_basic, test_illegal_utf8); |
1429 |
tcase_add_test(tc_basic, test_utf16); |
1430 |
tcase_add_test(tc_basic, test_utf16_le_epilog_newline); |
1431 |
tcase_add_test(tc_basic, test_latin1_umlauts); |
1432 |
/* Regression test for SF bug #491986. */ |
1433 |
tcase_add_test(tc_basic, test_danish_latin1); |
1434 |
/* Regression test for SF bug #514281. */ |
1435 |
tcase_add_test(tc_basic, test_french_charref_hexidecimal); |
1436 |
tcase_add_test(tc_basic, test_french_charref_decimal); |
1437 |
tcase_add_test(tc_basic, test_french_latin1); |
1438 |
tcase_add_test(tc_basic, test_french_utf8); |
1439 |
tcase_add_test(tc_basic, test_utf8_false_rejection); |
1440 |
tcase_add_test(tc_basic, test_line_number_after_parse); |
1441 |
tcase_add_test(tc_basic, test_column_number_after_parse); |
1442 |
tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers); |
1443 |
tcase_add_test(tc_basic, test_line_number_after_error); |
1444 |
tcase_add_test(tc_basic, test_column_number_after_error); |
1445 |
tcase_add_test(tc_basic, test_really_long_lines); |
1446 |
tcase_add_test(tc_basic, test_end_element_events); |
1447 |
tcase_add_test(tc_basic, test_attr_whitespace_normalization); |
1448 |
tcase_add_test(tc_basic, test_xmldecl_misplaced); |
1449 |
tcase_add_test(tc_basic, test_unknown_encoding_internal_entity); |
1450 |
tcase_add_test(tc_basic, |
1451 |
test_wfc_undeclared_entity_unread_external_subset); |
1452 |
tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset); |
1453 |
tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone); |
1454 |
tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset); |
1455 |
tcase_add_test(tc_basic, |
1456 |
test_wfc_undeclared_entity_with_external_subset_standalone); |
1457 |
tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs); |
1458 |
tcase_add_test(tc_basic, test_ext_entity_set_encoding); |
1459 |
tcase_add_test(tc_basic, test_dtd_default_handling); |
1460 |
tcase_add_test(tc_basic, test_empty_ns_without_namespaces); |
1461 |
tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces); |
1462 |
tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls); |
1463 |
tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls); |
1464 |
|
1465 |
suite_add_tcase(s, tc_namespace); |
1466 |
tcase_add_checked_fixture(tc_namespace, |
1467 |
namespace_setup, namespace_teardown); |
1468 |
tcase_add_test(tc_namespace, test_return_ns_triplet); |
1469 |
tcase_add_test(tc_namespace, test_ns_tagname_overwrite); |
1470 |
tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet); |
1471 |
tcase_add_test(tc_namespace, test_start_ns_clears_start_element); |
1472 |
tcase_add_test(tc_namespace, test_default_ns_from_ext_subset_and_ext_ge); |
1473 |
tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1); |
1474 |
tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2); |
1475 |
tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3); |
1476 |
tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4); |
1477 |
tcase_add_test(tc_namespace, test_ns_default_with_empty_uri); |
1478 |
tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes); |
1479 |
tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute); |
1480 |
tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element); |
1481 |
|
1482 |
return s; |
1483 |
} |
1484 |
|
1485 |
|
1486 |
int |
1487 |
main(int argc, char *argv[]) |
1488 |
{ |
1489 |
int i, nf; |
1490 |
int verbosity = CK_NORMAL; |
1491 |
Suite *s = make_suite(); |
1492 |
SRunner *sr = srunner_create(s); |
1493 |
|
1494 |
/* run the tests for internal helper functions */ |
1495 |
testhelper_is_whitespace_normalized(); |
1496 |
|
1497 |
for (i = 1; i < argc; ++i) { |
1498 |
char *opt = argv[i]; |
1499 |
if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0) |
1500 |
verbosity = CK_VERBOSE; |
1501 |
else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0) |
1502 |
verbosity = CK_SILENT; |
1503 |
else { |
1504 |
fprintf(stderr, "runtests: unknown option '%s'\n", opt); |
1505 |
return 2; |
1506 |
} |
1507 |
} |
1508 |
if (verbosity != CK_SILENT) |
1509 |
printf("Expat version: %s\n", XML_ExpatVersion()); |
1510 |
srunner_run_all(sr, verbosity); |
1511 |
nf = srunner_ntests_failed(sr); |
1512 |
srunner_free(sr); |
1513 |
|
1514 |
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE; |
1515 |
} |