1178848Scokane/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
2178848Scokane   See the file COPYING for copying permission.
3178848Scokane
4178848Scokane   runtest.c : run the Expat test suite
5178848Scokane*/
6178848Scokane
7178848Scokane#ifdef HAVE_EXPAT_CONFIG_H
8178848Scokane#include <expat_config.h>
9178848Scokane#endif
10178848Scokane
11104349Sphk#include <assert.h>
12104349Sphk#include <stdlib.h>
13104349Sphk#include <stdio.h>
14104349Sphk#include <string.h>
15247513Sdelphij#include <stdint.h>
16104349Sphk
17104349Sphk#include "expat.h"
18104349Sphk#include "chardata.h"
19178848Scokane#include "minicheck.h"
20104349Sphk
21178848Scokane#if defined(__amigaos__) && defined(__USE_INLINE__)
22178848Scokane#include <proto/expat.h>
23178848Scokane#endif
24104349Sphk
25178848Scokane#ifdef XML_LARGE_SIZE
26178848Scokane#define XML_FMT_INT_MOD "ll"
27178848Scokane#else
28178848Scokane#define XML_FMT_INT_MOD "l"
29178848Scokane#endif
30178848Scokane
31104349Sphkstatic XML_Parser parser;
32104349Sphk
33104349Sphk
34104349Sphkstatic void
35104349Sphkbasic_setup(void)
36104349Sphk{
37104349Sphk    parser = XML_ParserCreate(NULL);
38104349Sphk    if (parser == NULL)
39104349Sphk        fail("Parser not created.");
40104349Sphk}
41104349Sphk
42104349Sphkstatic void
43104349Sphkbasic_teardown(void)
44104349Sphk{
45104349Sphk    if (parser != NULL)
46104349Sphk        XML_ParserFree(parser);
47104349Sphk}
48104349Sphk
49104349Sphk/* Generate a failure using the parser state to create an error message;
50104349Sphk   this should be used when the parser reports an error we weren't
51104349Sphk   expecting.
52104349Sphk*/
53104349Sphkstatic void
54104349Sphk_xml_failure(XML_Parser parser, const char *file, int line)
55104349Sphk{
56104349Sphk    char buffer[1024];
57178848Scokane    enum XML_Error err = XML_GetErrorCode(parser);
58104349Sphk    sprintf(buffer,
59178848Scokane            "    %d: %s (line %" XML_FMT_INT_MOD "u, offset %"\
60178848Scokane                XML_FMT_INT_MOD "u)\n    reported from %s, line %d\n",
61178848Scokane            err,
62178848Scokane            XML_ErrorString(err),
63104349Sphk            XML_GetCurrentLineNumber(parser),
64104349Sphk            XML_GetCurrentColumnNumber(parser),
65104349Sphk            file, line);
66178848Scokane    _fail_unless(0, file, line, buffer);
67104349Sphk}
68104349Sphk
69104349Sphk#define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
70104349Sphk
71104349Sphkstatic void
72104349Sphk_expect_failure(char *text, enum XML_Error errorCode, char *errorMessage,
73104349Sphk                char *file, int lineno)
74104349Sphk{
75178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK)
76178848Scokane        /* Hackish use of _fail_unless() macro, but let's us report
77178848Scokane           the right filename and line number. */
78178848Scokane        _fail_unless(0, file, lineno, errorMessage);
79104349Sphk    if (XML_GetErrorCode(parser) != errorCode)
80104349Sphk        _xml_failure(parser, file, lineno);
81104349Sphk}
82104349Sphk
83104349Sphk#define expect_failure(text, errorCode, errorMessage) \
84104349Sphk        _expect_failure((text), (errorCode), (errorMessage), \
85104349Sphk                        __FILE__, __LINE__)
86104349Sphk
87178848Scokane/* Dummy handlers for when we need to set a handler to tickle a bug,
88178848Scokane   but it doesn't need to do anything.
89178848Scokane*/
90104349Sphk
91178848Scokanestatic void XMLCALL
92178848Scokanedummy_start_doctype_handler(void           *userData,
93178848Scokane                            const XML_Char *doctypeName,
94178848Scokane                            const XML_Char *sysid,
95178848Scokane                            const XML_Char *pubid,
96178848Scokane                            int            has_internal_subset)
97178848Scokane{}
98178848Scokane
99178848Scokanestatic void XMLCALL
100178848Scokanedummy_end_doctype_handler(void *userData)
101178848Scokane{}
102178848Scokane
103178848Scokanestatic void XMLCALL
104178848Scokanedummy_entity_decl_handler(void           *userData,
105178848Scokane                          const XML_Char *entityName,
106178848Scokane                          int            is_parameter_entity,
107178848Scokane                          const XML_Char *value,
108178848Scokane                          int            value_length,
109178848Scokane                          const XML_Char *base,
110178848Scokane                          const XML_Char *systemId,
111178848Scokane                          const XML_Char *publicId,
112178848Scokane                          const XML_Char *notationName)
113178848Scokane{}
114178848Scokane
115178848Scokanestatic void XMLCALL
116178848Scokanedummy_notation_decl_handler(void *userData,
117178848Scokane                            const XML_Char *notationName,
118178848Scokane                            const XML_Char *base,
119178848Scokane                            const XML_Char *systemId,
120178848Scokane                            const XML_Char *publicId)
121178848Scokane{}
122178848Scokane
123178848Scokanestatic void XMLCALL
124178848Scokanedummy_element_decl_handler(void *userData,
125178848Scokane                           const XML_Char *name,
126178848Scokane                           XML_Content *model)
127178848Scokane{}
128178848Scokane
129178848Scokanestatic void XMLCALL
130178848Scokanedummy_attlist_decl_handler(void           *userData,
131178848Scokane                           const XML_Char *elname,
132178848Scokane                           const XML_Char *attname,
133178848Scokane                           const XML_Char *att_type,
134178848Scokane                           const XML_Char *dflt,
135178848Scokane                           int            isrequired)
136178848Scokane{}
137178848Scokane
138178848Scokanestatic void XMLCALL
139178848Scokanedummy_comment_handler(void *userData, const XML_Char *data)
140178848Scokane{}
141178848Scokane
142178848Scokanestatic void XMLCALL
143178848Scokanedummy_pi_handler(void *userData, const XML_Char *target, const XML_Char *data)
144178848Scokane{}
145178848Scokane
146178848Scokanestatic void XMLCALL
147178848Scokanedummy_start_element(void *userData,
148178848Scokane                    const XML_Char *name, const XML_Char **atts)
149178848Scokane{}
150178848Scokane
151178848Scokane
152104349Sphk/*
153104349Sphk * Character & encoding tests.
154104349Sphk */
155104349Sphk
156104349SphkSTART_TEST(test_nul_byte)
157104349Sphk{
158104349Sphk    char text[] = "<doc>\0</doc>";
159104349Sphk
160104349Sphk    /* test that a NUL byte (in US-ASCII data) is an error */
161178848Scokane    if (XML_Parse(parser, text, sizeof(text) - 1, XML_TRUE) == XML_STATUS_OK)
162104349Sphk        fail("Parser did not report error on NUL-byte.");
163104349Sphk    if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
164104349Sphk        xml_failure(parser);
165104349Sphk}
166104349SphkEND_TEST
167104349Sphk
168104349Sphk
169104349SphkSTART_TEST(test_u0000_char)
170104349Sphk{
171104349Sphk    /* test that a NUL byte (in US-ASCII data) is an error */
172104349Sphk    expect_failure("<doc>&#0;</doc>",
173104349Sphk                   XML_ERROR_BAD_CHAR_REF,
174104349Sphk                   "Parser did not report error on NUL-byte.");
175104349Sphk}
176104349SphkEND_TEST
177104349Sphk
178104349SphkSTART_TEST(test_bom_utf8)
179104349Sphk{
180104349Sphk    /* This test is really just making sure we don't core on a UTF-8 BOM. */
181104349Sphk    char *text = "\357\273\277<e/>";
182104349Sphk
183178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
184104349Sphk        xml_failure(parser);
185104349Sphk}
186104349SphkEND_TEST
187104349Sphk
188104349SphkSTART_TEST(test_bom_utf16_be)
189104349Sphk{
190104349Sphk    char text[] = "\376\377\0<\0e\0/\0>";
191104349Sphk
192178848Scokane    if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
193104349Sphk        xml_failure(parser);
194104349Sphk}
195104349SphkEND_TEST
196104349Sphk
197104349SphkSTART_TEST(test_bom_utf16_le)
198104349Sphk{
199104349Sphk    char text[] = "\377\376<\0e\0/\0>\0";
200104349Sphk
201178848Scokane    if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
202104349Sphk        xml_failure(parser);
203104349Sphk}
204104349SphkEND_TEST
205104349Sphk
206178848Scokanestatic void XMLCALL
207104349Sphkaccumulate_characters(void *userData, const XML_Char *s, int len)
208104349Sphk{
209104349Sphk    CharData_AppendXMLChars((CharData *)userData, s, len);
210104349Sphk}
211104349Sphk
212178848Scokanestatic void XMLCALL
213104349Sphkaccumulate_attribute(void *userData, const XML_Char *name,
214104349Sphk                     const XML_Char **atts)
215104349Sphk{
216104349Sphk    CharData *storage = (CharData *)userData;
217104349Sphk    if (storage->count < 0 && atts != NULL && atts[0] != NULL) {
218104349Sphk        /* "accumulate" the value of the first attribute we see */
219104349Sphk        CharData_AppendXMLChars(storage, atts[1], -1);
220104349Sphk    }
221104349Sphk}
222104349Sphk
223104349Sphk
224104349Sphkstatic void
225178848Scokane_run_character_check(XML_Char *text, XML_Char *expected,
226178848Scokane                     const char *file, int line)
227104349Sphk{
228104349Sphk    CharData storage;
229104349Sphk
230104349Sphk    CharData_Init(&storage);
231104349Sphk    XML_SetUserData(parser, &storage);
232104349Sphk    XML_SetCharacterDataHandler(parser, accumulate_characters);
233178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
234178848Scokane        _xml_failure(parser, file, line);
235104349Sphk    CharData_CheckXMLChars(&storage, expected);
236104349Sphk}
237104349Sphk
238178848Scokane#define run_character_check(text, expected) \
239178848Scokane        _run_character_check(text, expected, __FILE__, __LINE__)
240178848Scokane
241104349Sphkstatic void
242178848Scokane_run_attribute_check(XML_Char *text, XML_Char *expected,
243178848Scokane                     const char *file, int line)
244104349Sphk{
245104349Sphk    CharData storage;
246104349Sphk
247104349Sphk    CharData_Init(&storage);
248104349Sphk    XML_SetUserData(parser, &storage);
249104349Sphk    XML_SetStartElementHandler(parser, accumulate_attribute);
250178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
251178848Scokane        _xml_failure(parser, file, line);
252104349Sphk    CharData_CheckXMLChars(&storage, expected);
253104349Sphk}
254104349Sphk
255178848Scokane#define run_attribute_check(text, expected) \
256178848Scokane        _run_attribute_check(text, expected, __FILE__, __LINE__)
257178848Scokane
258104349Sphk/* Regression test for SF bug #491986. */
259104349SphkSTART_TEST(test_danish_latin1)
260104349Sphk{
261104349Sphk    char *text =
262104349Sphk        "<?xml version='1.0' encoding='iso-8859-1'?>\n"
263178848Scokane        "<e>J\xF8rgen \xE6\xF8\xE5\xC6\xD8\xC5</e>";
264104349Sphk    run_character_check(text,
265104349Sphk             "J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
266104349Sphk}
267104349SphkEND_TEST
268104349Sphk
269104349Sphk
270104349Sphk/* Regression test for SF bug #514281. */
271104349SphkSTART_TEST(test_french_charref_hexidecimal)
272104349Sphk{
273104349Sphk    char *text =
274104349Sphk        "<?xml version='1.0' encoding='iso-8859-1'?>\n"
275104349Sphk        "<doc>&#xE9;&#xE8;&#xE0;&#xE7;&#xEA;&#xC8;</doc>";
276104349Sphk    run_character_check(text,
277104349Sphk                        "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
278104349Sphk}
279104349SphkEND_TEST
280104349Sphk
281104349SphkSTART_TEST(test_french_charref_decimal)
282104349Sphk{
283104349Sphk    char *text =
284104349Sphk        "<?xml version='1.0' encoding='iso-8859-1'?>\n"
285104349Sphk        "<doc>&#233;&#232;&#224;&#231;&#234;&#200;</doc>";
286104349Sphk    run_character_check(text,
287104349Sphk                        "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
288104349Sphk}
289104349SphkEND_TEST
290104349Sphk
291104349SphkSTART_TEST(test_french_latin1)
292104349Sphk{
293104349Sphk    char *text =
294104349Sphk        "<?xml version='1.0' encoding='iso-8859-1'?>\n"
295104349Sphk        "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
296104349Sphk    run_character_check(text,
297104349Sphk                        "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
298104349Sphk}
299104349SphkEND_TEST
300104349Sphk
301104349SphkSTART_TEST(test_french_utf8)
302104349Sphk{
303104349Sphk    char *text =
304104349Sphk        "<?xml version='1.0' encoding='utf-8'?>\n"
305104349Sphk        "<doc>\xC3\xA9</doc>";
306104349Sphk    run_character_check(text, "\xC3\xA9");
307104349Sphk}
308104349SphkEND_TEST
309104349Sphk
310104349Sphk/* Regression test for SF bug #600479.
311104349Sphk   XXX There should be a test that exercises all legal XML Unicode
312104349Sphk   characters as PCDATA and attribute value content, and XML Name
313104349Sphk   characters as part of element and attribute names.
314104349Sphk*/
315104349SphkSTART_TEST(test_utf8_false_rejection)
316104349Sphk{
317104349Sphk    char *text = "<doc>\xEF\xBA\xBF</doc>";
318104349Sphk    run_character_check(text, "\xEF\xBA\xBF");
319104349Sphk}
320104349SphkEND_TEST
321104349Sphk
322104349Sphk/* Regression test for SF bug #477667.
323104349Sphk   This test assures that any 8-bit character followed by a 7-bit
324104349Sphk   character will not be mistakenly interpreted as a valid UTF-8
325104349Sphk   sequence.
326104349Sphk*/
327104349SphkSTART_TEST(test_illegal_utf8)
328104349Sphk{
329104349Sphk    char text[100];
330104349Sphk    int i;
331104349Sphk
332104349Sphk    for (i = 128; i <= 255; ++i) {
333104349Sphk        sprintf(text, "<e>%ccd</e>", i);
334178848Scokane        if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_OK) {
335104349Sphk            sprintf(text,
336104349Sphk                    "expected token error for '%c' (ordinal %d) in UTF-8 text",
337104349Sphk                    i, i);
338104349Sphk            fail(text);
339104349Sphk        }
340104349Sphk        else if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
341104349Sphk            xml_failure(parser);
342104349Sphk        /* Reset the parser since we use the same parser repeatedly. */
343104349Sphk        XML_ParserReset(parser, NULL);
344104349Sphk    }
345104349Sphk}
346104349SphkEND_TEST
347104349Sphk
348104349SphkSTART_TEST(test_utf16)
349104349Sphk{
350104349Sphk    /* <?xml version="1.0" encoding="UTF-16"?>
351104349Sphk       <doc a='123'>some text</doc>
352104349Sphk    */
353104349Sphk    char text[] =
354104349Sphk        "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
355104349Sphk        "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
356104349Sphk        "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
357104349Sphk        "\000'\000?\000>\000\n"
358104349Sphk        "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'"
359104349Sphk        "\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/"
360104349Sphk        "\000d\000o\000c\000>";
361178848Scokane    if (XML_Parse(parser, text, sizeof(text)-1, XML_TRUE) == XML_STATUS_ERROR)
362104349Sphk        xml_failure(parser);
363104349Sphk}
364104349SphkEND_TEST
365104349Sphk
366104349SphkSTART_TEST(test_utf16_le_epilog_newline)
367104349Sphk{
368178848Scokane    unsigned int first_chunk_bytes = 17;
369104349Sphk    char text[] =
370104349Sphk        "\xFF\xFE"                      /* BOM */
371104349Sphk        "<\000e\000/\000>\000"          /* document element */
372104349Sphk        "\r\000\n\000\r\000\n\000";     /* epilog */
373104349Sphk
374104349Sphk    if (first_chunk_bytes >= sizeof(text) - 1)
375104349Sphk        fail("bad value of first_chunk_bytes");
376178848Scokane    if (  XML_Parse(parser, text, first_chunk_bytes, XML_FALSE)
377178848Scokane          == XML_STATUS_ERROR)
378104349Sphk        xml_failure(parser);
379104349Sphk    else {
380104349Sphk        enum XML_Status rc;
381104349Sphk        rc = XML_Parse(parser, text + first_chunk_bytes,
382178848Scokane                       sizeof(text) - first_chunk_bytes - 1, XML_TRUE);
383104349Sphk        if (rc == XML_STATUS_ERROR)
384104349Sphk            xml_failure(parser);
385104349Sphk    }
386104349Sphk}
387104349SphkEND_TEST
388104349Sphk
389178848Scokane/* Regression test for SF bug #481609, #774028. */
390104349SphkSTART_TEST(test_latin1_umlauts)
391104349Sphk{
392104349Sphk    char *text =
393104349Sphk        "<?xml version='1.0' encoding='iso-8859-1'?>\n"
394178848Scokane        "<e a='\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; >'\n"
395178848Scokane        "  >\xE4 \xF6 \xFC &#228; &#246; &#252; &#x00E4; &#x0F6; &#xFC; ></e>";
396104349Sphk    char *utf8 =
397104349Sphk        "\xC3\xA4 \xC3\xB6 \xC3\xBC "
398104349Sphk        "\xC3\xA4 \xC3\xB6 \xC3\xBC "
399178848Scokane        "\xC3\xA4 \xC3\xB6 \xC3\xBC >";
400104349Sphk    run_character_check(text, utf8);
401104349Sphk    XML_ParserReset(parser, NULL);
402104349Sphk    run_attribute_check(text, utf8);
403104349Sphk}
404104349SphkEND_TEST
405104349Sphk
406178848Scokane/* Regression test #1 for SF bug #653180. */
407178848ScokaneSTART_TEST(test_line_number_after_parse)
408178848Scokane{
409178848Scokane    char *text =
410178848Scokane        "<tag>\n"
411178848Scokane        "\n"
412178848Scokane        "\n</tag>";
413178848Scokane    XML_Size lineno;
414178848Scokane
415178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
416178848Scokane        xml_failure(parser);
417178848Scokane    lineno = XML_GetCurrentLineNumber(parser);
418178848Scokane    if (lineno != 4) {
419178848Scokane        char buffer[100];
420178848Scokane        sprintf(buffer,
421178848Scokane            "expected 4 lines, saw %" XML_FMT_INT_MOD "u", lineno);
422178848Scokane        fail(buffer);
423178848Scokane    }
424178848Scokane}
425178848ScokaneEND_TEST
426178848Scokane
427178848Scokane/* Regression test #2 for SF bug #653180. */
428178848ScokaneSTART_TEST(test_column_number_after_parse)
429104349Sphk{
430178848Scokane    char *text = "<tag></tag>";
431178848Scokane    XML_Size colno;
432178848Scokane
433178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_FALSE) == XML_STATUS_ERROR)
434178848Scokane        xml_failure(parser);
435178848Scokane    colno = XML_GetCurrentColumnNumber(parser);
436178848Scokane    if (colno != 11) {
437178848Scokane        char buffer[100];
438178848Scokane        sprintf(buffer,
439178848Scokane            "expected 11 columns, saw %" XML_FMT_INT_MOD "u", colno);
440178848Scokane        fail(buffer);
441178848Scokane    }
442178848Scokane}
443178848ScokaneEND_TEST
444178848Scokane
445178848Scokanestatic void XMLCALL
446178848Scokanestart_element_event_handler2(void *userData, const XML_Char *name,
447178848Scokane			     const XML_Char **attr)
448178848Scokane{
449178848Scokane    CharData *storage = (CharData *) userData;
450178848Scokane    char buffer[100];
451178848Scokane
452178848Scokane    sprintf(buffer,
453178848Scokane        "<%s> at col:%" XML_FMT_INT_MOD "u line:%"\
454178848Scokane            XML_FMT_INT_MOD "u\n", name,
455178848Scokane	    XML_GetCurrentColumnNumber(parser),
456178848Scokane	    XML_GetCurrentLineNumber(parser));
457178848Scokane    CharData_AppendString(storage, buffer);
458178848Scokane}
459178848Scokane
460178848Scokanestatic void XMLCALL
461178848Scokaneend_element_event_handler2(void *userData, const XML_Char *name)
462178848Scokane{
463178848Scokane    CharData *storage = (CharData *) userData;
464178848Scokane    char buffer[100];
465178848Scokane
466178848Scokane    sprintf(buffer,
467178848Scokane        "</%s> at col:%" XML_FMT_INT_MOD "u line:%"\
468178848Scokane            XML_FMT_INT_MOD "u\n", name,
469178848Scokane	    XML_GetCurrentColumnNumber(parser),
470178848Scokane	    XML_GetCurrentLineNumber(parser));
471178848Scokane    CharData_AppendString(storage, buffer);
472178848Scokane}
473178848Scokane
474178848Scokane/* Regression test #3 for SF bug #653180. */
475178848ScokaneSTART_TEST(test_line_and_column_numbers_inside_handlers)
476178848Scokane{
477104349Sphk    char *text =
478178848Scokane        "<a>\n"        /* Unix end-of-line */
479178848Scokane        "  <b>\r\n"    /* Windows end-of-line */
480178848Scokane        "    <c/>\r"   /* Mac OS end-of-line */
481178848Scokane        "  </b>\n"
482178848Scokane        "  <d>\n"
483178848Scokane        "    <f/>\n"
484178848Scokane        "  </d>\n"
485178848Scokane        "</a>";
486178848Scokane    char *expected =
487178848Scokane        "<a> at col:0 line:1\n"
488178848Scokane        "<b> at col:2 line:2\n"
489178848Scokane        "<c> at col:4 line:3\n"
490178848Scokane        "</c> at col:8 line:3\n"
491178848Scokane        "</b> at col:2 line:4\n"
492178848Scokane        "<d> at col:2 line:5\n"
493178848Scokane        "<f> at col:4 line:6\n"
494178848Scokane        "</f> at col:8 line:6\n"
495178848Scokane        "</d> at col:2 line:7\n"
496178848Scokane        "</a> at col:0 line:8\n";
497178848Scokane    CharData storage;
498178848Scokane
499178848Scokane    CharData_Init(&storage);
500178848Scokane    XML_SetUserData(parser, &storage);
501178848Scokane    XML_SetStartElementHandler(parser, start_element_event_handler2);
502178848Scokane    XML_SetEndElementHandler(parser, end_element_event_handler2);
503178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
504104349Sphk        xml_failure(parser);
505178848Scokane
506178848Scokane    CharData_CheckString(&storage, expected);
507178848Scokane}
508178848ScokaneEND_TEST
509178848Scokane
510178848Scokane/* Regression test #4 for SF bug #653180. */
511178848ScokaneSTART_TEST(test_line_number_after_error)
512178848Scokane{
513178848Scokane    char *text =
514178848Scokane        "<a>\n"
515178848Scokane        "  <b>\n"
516178848Scokane        "  </a>";  /* missing </b> */
517178848Scokane    XML_Size lineno;
518178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
519178848Scokane        fail("Expected a parse error");
520178848Scokane
521104349Sphk    lineno = XML_GetCurrentLineNumber(parser);
522104349Sphk    if (lineno != 3) {
523104349Sphk        char buffer[100];
524178848Scokane        sprintf(buffer, "expected 3 lines, saw %" XML_FMT_INT_MOD "u", lineno);
525104349Sphk        fail(buffer);
526104349Sphk    }
527104349Sphk}
528104349SphkEND_TEST
529178848Scokane
530178848Scokane/* Regression test #5 for SF bug #653180. */
531178848ScokaneSTART_TEST(test_column_number_after_error)
532178848Scokane{
533178848Scokane    char *text =
534178848Scokane        "<a>\n"
535178848Scokane        "  <b>\n"
536178848Scokane        "  </a>";  /* missing </b> */
537178848Scokane    XML_Size colno;
538178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_FALSE) != XML_STATUS_ERROR)
539178848Scokane        fail("Expected a parse error");
540104349Sphk
541178848Scokane    colno = XML_GetCurrentColumnNumber(parser);
542178848Scokane    if (colno != 4) {
543178848Scokane        char buffer[100];
544178848Scokane        sprintf(buffer,
545178848Scokane            "expected 4 columns, saw %" XML_FMT_INT_MOD "u", colno);
546178848Scokane        fail(buffer);
547178848Scokane    }
548178848Scokane}
549178848ScokaneEND_TEST
550178848Scokane
551104349Sphk/* Regression test for SF bug #478332. */
552104349SphkSTART_TEST(test_really_long_lines)
553104349Sphk{
554104349Sphk    /* This parses an input line longer than INIT_DATA_BUF_SIZE
555104349Sphk       characters long (defined to be 1024 in xmlparse.c).  We take a
556104349Sphk       really cheesy approach to building the input buffer, because
557104349Sphk       this avoids writing bugs in buffer-filling code.
558104349Sphk    */
559104349Sphk    char *text =
560104349Sphk        "<e>"
561104349Sphk        /* 64 chars */
562104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
563104349Sphk        /* until we have at least 1024 characters on the line: */
564104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
565104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
566104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
567104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
568104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
569104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
570104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
571104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
572104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
573104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
574104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
575104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
576104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
577104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
578104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
579104349Sphk        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
580104349Sphk        "</e>";
581178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
582104349Sphk        xml_failure(parser);
583104349Sphk}
584104349SphkEND_TEST
585104349Sphk
586104349Sphk
587104349Sphk/*
588104349Sphk * Element event tests.
589104349Sphk */
590104349Sphk
591178848Scokanestatic void XMLCALL
592104349Sphkend_element_event_handler(void *userData, const XML_Char *name)
593104349Sphk{
594104349Sphk    CharData *storage = (CharData *) userData;
595104349Sphk    CharData_AppendString(storage, "/");
596104349Sphk    CharData_AppendXMLChars(storage, name, -1);
597104349Sphk}
598104349Sphk
599104349SphkSTART_TEST(test_end_element_events)
600104349Sphk{
601104349Sphk    char *text = "<a><b><c/></b><d><f/></d></a>";
602104349Sphk    char *expected = "/c/b/f/d/a";
603104349Sphk    CharData storage;
604104349Sphk
605104349Sphk    CharData_Init(&storage);
606104349Sphk    XML_SetUserData(parser, &storage);
607104349Sphk    XML_SetEndElementHandler(parser, end_element_event_handler);
608178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
609104349Sphk        xml_failure(parser);
610104349Sphk    CharData_CheckString(&storage, expected);
611104349Sphk}
612104349SphkEND_TEST
613104349Sphk
614104349Sphk
615104349Sphk/*
616104349Sphk * Attribute tests.
617104349Sphk */
618104349Sphk
619104349Sphk/* Helpers used by the following test; this checks any "attr" and "refs"
620104349Sphk   attributes to make sure whitespace has been normalized.
621104349Sphk
622104349Sphk   Return true if whitespace has been normalized in a string, using
623104349Sphk   the rules for attribute value normalization.  The 'is_cdata' flag
624104349Sphk   is needed since CDATA attributes don't need to have multiple
625104349Sphk   whitespace characters collapsed to a single space, while other
626104349Sphk   attribute data types do.  (Section 3.3.3 of the recommendation.)
627104349Sphk*/
628104349Sphkstatic int
629104349Sphkis_whitespace_normalized(const XML_Char *s, int is_cdata)
630104349Sphk{
631104349Sphk    int blanks = 0;
632104349Sphk    int at_start = 1;
633104349Sphk    while (*s) {
634104349Sphk        if (*s == ' ')
635104349Sphk            ++blanks;
636104349Sphk        else if (*s == '\t' || *s == '\n' || *s == '\r')
637104349Sphk            return 0;
638104349Sphk        else {
639104349Sphk            if (at_start) {
640104349Sphk                at_start = 0;
641104349Sphk                if (blanks && !is_cdata)
642104349Sphk                    /* illegal leading blanks */
643104349Sphk                    return 0;
644104349Sphk            }
645104349Sphk            else if (blanks > 1 && !is_cdata)
646104349Sphk                return 0;
647104349Sphk            blanks = 0;
648104349Sphk        }
649104349Sphk        ++s;
650104349Sphk    }
651104349Sphk    if (blanks && !is_cdata)
652104349Sphk        return 0;
653104349Sphk    return 1;
654104349Sphk}
655104349Sphk
656104349Sphk/* Check the attribute whitespace checker: */
657104349Sphkstatic void
658104349Sphktesthelper_is_whitespace_normalized(void)
659104349Sphk{
660104349Sphk    assert(is_whitespace_normalized("abc", 0));
661104349Sphk    assert(is_whitespace_normalized("abc", 1));
662104349Sphk    assert(is_whitespace_normalized("abc def ghi", 0));
663104349Sphk    assert(is_whitespace_normalized("abc def ghi", 1));
664104349Sphk    assert(!is_whitespace_normalized(" abc def ghi", 0));
665104349Sphk    assert(is_whitespace_normalized(" abc def ghi", 1));
666104349Sphk    assert(!is_whitespace_normalized("abc  def ghi", 0));
667104349Sphk    assert(is_whitespace_normalized("abc  def ghi", 1));
668104349Sphk    assert(!is_whitespace_normalized("abc def ghi ", 0));
669104349Sphk    assert(is_whitespace_normalized("abc def ghi ", 1));
670104349Sphk    assert(!is_whitespace_normalized(" ", 0));
671104349Sphk    assert(is_whitespace_normalized(" ", 1));
672104349Sphk    assert(!is_whitespace_normalized("\t", 0));
673104349Sphk    assert(!is_whitespace_normalized("\t", 1));
674104349Sphk    assert(!is_whitespace_normalized("\n", 0));
675104349Sphk    assert(!is_whitespace_normalized("\n", 1));
676104349Sphk    assert(!is_whitespace_normalized("\r", 0));
677104349Sphk    assert(!is_whitespace_normalized("\r", 1));
678104349Sphk    assert(!is_whitespace_normalized("abc\t def", 1));
679104349Sphk}
680104349Sphk
681178848Scokanestatic void XMLCALL
682104349Sphkcheck_attr_contains_normalized_whitespace(void *userData,
683104349Sphk                                          const XML_Char *name,
684104349Sphk                                          const XML_Char **atts)
685104349Sphk{
686104349Sphk    int i;
687104349Sphk    for (i = 0; atts[i] != NULL; i += 2) {
688104349Sphk        const XML_Char *attrname = atts[i];
689104349Sphk        const XML_Char *value = atts[i + 1];
690104349Sphk        if (strcmp("attr", attrname) == 0
691104349Sphk            || strcmp("ents", attrname) == 0
692104349Sphk            || strcmp("refs", attrname) == 0) {
693104349Sphk            if (!is_whitespace_normalized(value, 0)) {
694104349Sphk                char buffer[256];
695104349Sphk                sprintf(buffer, "attribute value not normalized: %s='%s'",
696104349Sphk                        attrname, value);
697104349Sphk                fail(buffer);
698104349Sphk            }
699104349Sphk        }
700104349Sphk    }
701104349Sphk}
702104349Sphk
703104349SphkSTART_TEST(test_attr_whitespace_normalization)
704104349Sphk{
705104349Sphk    char *text =
706104349Sphk        "<!DOCTYPE doc [\n"
707104349Sphk        "  <!ATTLIST doc\n"
708104349Sphk        "            attr NMTOKENS #REQUIRED\n"
709104349Sphk        "            ents ENTITIES #REQUIRED\n"
710104349Sphk        "            refs IDREFS   #REQUIRED>\n"
711104349Sphk        "]>\n"
712104349Sphk        "<doc attr='    a  b c\t\td\te\t' refs=' id-1   \t  id-2\t\t'  \n"
713104349Sphk        "     ents=' ent-1   \t\r\n"
714104349Sphk        "            ent-2  ' >\n"
715104349Sphk        "  <e id='id-1'/>\n"
716104349Sphk        "  <e id='id-2'/>\n"
717104349Sphk        "</doc>";
718104349Sphk
719104349Sphk    XML_SetStartElementHandler(parser,
720104349Sphk                               check_attr_contains_normalized_whitespace);
721178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
722104349Sphk        xml_failure(parser);
723104349Sphk}
724104349SphkEND_TEST
725104349Sphk
726104349Sphk
727104349Sphk/*
728104349Sphk * XML declaration tests.
729104349Sphk */
730104349Sphk
731104349SphkSTART_TEST(test_xmldecl_misplaced)
732104349Sphk{
733104349Sphk    expect_failure("\n"
734104349Sphk                   "<?xml version='1.0'?>\n"
735104349Sphk                   "<a/>",
736104349Sphk                   XML_ERROR_MISPLACED_XML_PI,
737104349Sphk                   "failed to report misplaced XML declaration");
738104349Sphk}
739104349SphkEND_TEST
740104349Sphk
741104349Sphk/* Regression test for SF bug #584832. */
742178848Scokanestatic int XMLCALL
743104349SphkUnknownEncodingHandler(void *data,const XML_Char *encoding,XML_Encoding *info)
744104349Sphk{
745104349Sphk    if (strcmp(encoding,"unsupported-encoding") == 0) {
746104349Sphk        int i;
747104349Sphk        for (i = 0; i < 256; ++i)
748104349Sphk            info->map[i] = i;
749178848Scokane        info->data = NULL;
750178848Scokane        info->convert = NULL;
751178848Scokane        info->release = NULL;
752178848Scokane        return XML_STATUS_OK;
753104349Sphk    }
754178848Scokane    return XML_STATUS_ERROR;
755104349Sphk}
756104349Sphk
757104349SphkSTART_TEST(test_unknown_encoding_internal_entity)
758104349Sphk{
759104349Sphk    char *text =
760104349Sphk        "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
761104349Sphk        "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
762104349Sphk        "<test a='&foo;'/>";
763104349Sphk
764104349Sphk    XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL);
765178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
766104349Sphk        xml_failure(parser);
767104349Sphk}
768104349SphkEND_TEST
769104349Sphk
770178848Scokane/* Regression test for SF bug #620106. */
771178848Scokanestatic int XMLCALL
772178848Scokaneexternal_entity_loader_set_encoding(XML_Parser parser,
773178848Scokane                                    const XML_Char *context,
774178848Scokane                                    const XML_Char *base,
775178848Scokane                                    const XML_Char *systemId,
776178848Scokane                                    const XML_Char *publicId)
777178848Scokane{
778178848Scokane    /* This text says it's an unsupported encoding, but it's really
779178848Scokane       UTF-8, which we tell Expat using XML_SetEncoding().
780178848Scokane    */
781178848Scokane    char *text =
782178848Scokane        "<?xml encoding='iso-8859-3'?>"
783178848Scokane        "\xC3\xA9";
784178848Scokane    XML_Parser extparser;
785178848Scokane
786178848Scokane    extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
787178848Scokane    if (extparser == NULL)
788178848Scokane        fail("Could not create external entity parser.");
789178848Scokane    if (!XML_SetEncoding(extparser, "utf-8"))
790178848Scokane        fail("XML_SetEncoding() ignored for external entity");
791178848Scokane    if (  XML_Parse(extparser, text, strlen(text), XML_TRUE)
792178848Scokane          == XML_STATUS_ERROR) {
793178848Scokane        xml_failure(parser);
794178848Scokane        return 0;
795178848Scokane    }
796178848Scokane    return 1;
797178848Scokane}
798178848Scokane
799178848ScokaneSTART_TEST(test_ext_entity_set_encoding)
800178848Scokane{
801178848Scokane    char *text =
802178848Scokane        "<!DOCTYPE doc [\n"
803178848Scokane        "  <!ENTITY en SYSTEM 'http://xml.libexpat.org/dummy.ent'>\n"
804178848Scokane        "]>\n"
805178848Scokane        "<doc>&en;</doc>";
806178848Scokane
807178848Scokane    XML_SetExternalEntityRefHandler(parser,
808178848Scokane                                    external_entity_loader_set_encoding);
809178848Scokane    run_character_check(text, "\xC3\xA9");
810178848Scokane}
811178848ScokaneEND_TEST
812178848Scokane
813104349Sphk/* Test that no error is reported for unknown entities if we don't
814104349Sphk   read an external subset.  This was fixed in Expat 1.95.5.
815104349Sphk*/
816104349SphkSTART_TEST(test_wfc_undeclared_entity_unread_external_subset) {
817104349Sphk    char *text =
818104349Sphk        "<!DOCTYPE doc SYSTEM 'foo'>\n"
819104349Sphk        "<doc>&entity;</doc>";
820104349Sphk
821178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
822104349Sphk        xml_failure(parser);
823104349Sphk}
824104349SphkEND_TEST
825104349Sphk
826104349Sphk/* Test that an error is reported for unknown entities if we don't
827104349Sphk   have an external subset.
828104349Sphk*/
829104349SphkSTART_TEST(test_wfc_undeclared_entity_no_external_subset) {
830104349Sphk    expect_failure("<doc>&entity;</doc>",
831104349Sphk                   XML_ERROR_UNDEFINED_ENTITY,
832104349Sphk                   "Parser did not report undefined entity w/out a DTD.");
833104349Sphk}
834104349SphkEND_TEST
835104349Sphk
836104349Sphk/* Test that an error is reported for unknown entities if we don't
837104349Sphk   read an external subset, but have been declared standalone.
838104349Sphk*/
839104349SphkSTART_TEST(test_wfc_undeclared_entity_standalone) {
840104349Sphk    char *text =
841104349Sphk        "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
842104349Sphk        "<!DOCTYPE doc SYSTEM 'foo'>\n"
843104349Sphk        "<doc>&entity;</doc>";
844104349Sphk
845104349Sphk    expect_failure(text,
846104349Sphk                   XML_ERROR_UNDEFINED_ENTITY,
847104349Sphk                   "Parser did not report undefined entity (standalone).");
848104349Sphk}
849104349SphkEND_TEST
850104349Sphk
851178848Scokanestatic int XMLCALL
852104349Sphkexternal_entity_loader(XML_Parser parser,
853104349Sphk                       const XML_Char *context,
854104349Sphk                       const XML_Char *base,
855104349Sphk                       const XML_Char *systemId,
856104349Sphk                       const XML_Char *publicId)
857104349Sphk{
858104349Sphk    char *text = (char *)XML_GetUserData(parser);
859104349Sphk    XML_Parser extparser;
860104349Sphk
861104349Sphk    extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
862104349Sphk    if (extparser == NULL)
863104349Sphk        fail("Could not create external entity parser.");
864178848Scokane    if (  XML_Parse(extparser, text, strlen(text), XML_TRUE)
865178848Scokane          == XML_STATUS_ERROR) {
866104349Sphk        xml_failure(parser);
867178848Scokane        return XML_STATUS_ERROR;
868104349Sphk    }
869178848Scokane    return XML_STATUS_OK;
870104349Sphk}
871104349Sphk
872104349Sphk/* Test that an error is reported for unknown entities if we have read
873178848Scokane   an external subset, and standalone is true.
874104349Sphk*/
875178848ScokaneSTART_TEST(test_wfc_undeclared_entity_with_external_subset_standalone) {
876104349Sphk    char *text =
877178848Scokane        "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
878104349Sphk        "<!DOCTYPE doc SYSTEM 'foo'>\n"
879104349Sphk        "<doc>&entity;</doc>";
880104349Sphk    char *foo_text =
881104349Sphk        "<!ELEMENT doc (#PCDATA)*>";
882104349Sphk
883104349Sphk    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
884104349Sphk    XML_SetUserData(parser, foo_text);
885104349Sphk    XML_SetExternalEntityRefHandler(parser, external_entity_loader);
886104349Sphk    expect_failure(text,
887104349Sphk                   XML_ERROR_UNDEFINED_ENTITY,
888178848Scokane                   "Parser did not report undefined entity (external DTD).");
889104349Sphk}
890104349SphkEND_TEST
891104349Sphk
892178848Scokane/* Test that no error is reported for unknown entities if we have read
893178848Scokane   an external subset, and standalone is false.
894178848Scokane*/
895178848ScokaneSTART_TEST(test_wfc_undeclared_entity_with_external_subset) {
896178848Scokane    char *text =
897178848Scokane        "<?xml version='1.0' encoding='us-ascii'?>\n"
898178848Scokane        "<!DOCTYPE doc SYSTEM 'foo'>\n"
899178848Scokane        "<doc>&entity;</doc>";
900178848Scokane    char *foo_text =
901178848Scokane        "<!ELEMENT doc (#PCDATA)*>";
902178848Scokane
903178848Scokane    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
904178848Scokane    XML_SetUserData(parser, foo_text);
905178848Scokane    XML_SetExternalEntityRefHandler(parser, external_entity_loader);
906178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
907178848Scokane        xml_failure(parser);
908178848Scokane}
909178848ScokaneEND_TEST
910178848Scokane
911104349SphkSTART_TEST(test_wfc_no_recursive_entity_refs)
912104349Sphk{
913104349Sphk    char *text =
914104349Sphk        "<!DOCTYPE doc [\n"
915104349Sphk        "  <!ENTITY entity '&#38;entity;'>\n"
916104349Sphk        "]>\n"
917104349Sphk        "<doc>&entity;</doc>";
918104349Sphk
919104349Sphk    expect_failure(text,
920104349Sphk                   XML_ERROR_RECURSIVE_ENTITY_REF,
921104349Sphk                   "Parser did not report recursive entity reference.");
922104349Sphk}
923104349SphkEND_TEST
924104349Sphk
925178848Scokane/* Regression test for SF bug #483514. */
926178848ScokaneSTART_TEST(test_dtd_default_handling)
927178848Scokane{
928178848Scokane    char *text =
929178848Scokane        "<!DOCTYPE doc [\n"
930178848Scokane        "<!ENTITY e SYSTEM 'http://xml.libexpat.org/e'>\n"
931178848Scokane        "<!NOTATION n SYSTEM 'http://xml.libexpat.org/n'>\n"
932178848Scokane        "<!ELEMENT doc EMPTY>\n"
933178848Scokane        "<!ATTLIST doc a CDATA #IMPLIED>\n"
934178848Scokane        "<?pi in dtd?>\n"
935178848Scokane        "<!--comment in dtd-->\n"
936178848Scokane        "]><doc/>";
937104349Sphk
938178848Scokane    XML_SetDefaultHandler(parser, accumulate_characters);
939178848Scokane    XML_SetDoctypeDeclHandler(parser,
940178848Scokane                              dummy_start_doctype_handler,
941178848Scokane                              dummy_end_doctype_handler);
942178848Scokane    XML_SetEntityDeclHandler(parser, dummy_entity_decl_handler);
943178848Scokane    XML_SetNotationDeclHandler(parser, dummy_notation_decl_handler);
944178848Scokane    XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
945178848Scokane    XML_SetAttlistDeclHandler(parser, dummy_attlist_decl_handler);
946178848Scokane    XML_SetProcessingInstructionHandler(parser, dummy_pi_handler);
947178848Scokane    XML_SetCommentHandler(parser, dummy_comment_handler);
948178848Scokane    run_character_check(text, "\n\n\n\n\n\n\n<doc/>");
949178848Scokane}
950178848ScokaneEND_TEST
951178848Scokane
952178848Scokane/* See related SF bug #673791.
953178848Scokane   When namespace processing is enabled, setting the namespace URI for
954178848Scokane   a prefix is not allowed; this test ensures that it *is* allowed
955178848Scokane   when namespace processing is not enabled.
956178848Scokane   (See Namespaces in XML, section 2.)
957178848Scokane*/
958178848ScokaneSTART_TEST(test_empty_ns_without_namespaces)
959178848Scokane{
960178848Scokane    char *text =
961178848Scokane        "<doc xmlns:prefix='http://www.example.com/'>\n"
962178848Scokane        "  <e xmlns:prefix=''/>\n"
963178848Scokane        "</doc>";
964178848Scokane
965178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
966178848Scokane        xml_failure(parser);
967178848Scokane}
968178848ScokaneEND_TEST
969178848Scokane
970178848Scokane/* Regression test for SF bug #824420.
971178848Scokane   Checks that an xmlns:prefix attribute set in an attribute's default
972178848Scokane   value isn't misinterpreted.
973178848Scokane*/
974178848ScokaneSTART_TEST(test_ns_in_attribute_default_without_namespaces)
975178848Scokane{
976178848Scokane    char *text =
977178848Scokane        "<!DOCTYPE e:element [\n"
978178848Scokane        "  <!ATTLIST e:element\n"
979178848Scokane        "    xmlns:e CDATA 'http://example.com/'>\n"
980178848Scokane        "      ]>\n"
981178848Scokane        "<e:element/>";
982178848Scokane
983178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
984178848Scokane        xml_failure(parser);
985178848Scokane}
986178848ScokaneEND_TEST
987178848Scokane
988178848Scokanestatic char *long_character_data_text =
989178848Scokane    "<?xml version='1.0' encoding='iso-8859-1'?><s>"
990178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
991178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
992178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
993178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
994178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
995178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
996178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
997178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
998178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
999178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1000178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1001178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1002178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1003178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1004178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1005178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1006178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1007178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1008178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1009178848Scokane    "012345678901234567890123456789012345678901234567890123456789"
1010178848Scokane    "</s>";
1011178848Scokane
1012178848Scokanestatic XML_Bool resumable = XML_FALSE;
1013178848Scokane
1014178848Scokanestatic void
1015178848Scokaneclearing_aborting_character_handler(void *userData,
1016178848Scokane                                    const XML_Char *s, int len)
1017178848Scokane{
1018178848Scokane    XML_StopParser(parser, resumable);
1019178848Scokane    XML_SetCharacterDataHandler(parser, NULL);
1020178848Scokane}
1021178848Scokane
1022178848Scokane/* Regression test for SF bug #1515266: missing check of stopped
1023178848Scokane   parser in doContext() 'for' loop. */
1024178848ScokaneSTART_TEST(test_stop_parser_between_char_data_calls)
1025178848Scokane{
1026178848Scokane    /* The sample data must be big enough that there are two calls to
1027178848Scokane       the character data handler from within the inner "for" loop of
1028178848Scokane       the XML_TOK_DATA_CHARS case in doContent(), and the character
1029178848Scokane       handler must stop the parser and clear the character data
1030178848Scokane       handler.
1031178848Scokane    */
1032178848Scokane    char *text = long_character_data_text;
1033178848Scokane
1034178848Scokane    XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
1035178848Scokane    resumable = XML_FALSE;
1036178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_ERROR)
1037178848Scokane        xml_failure(parser);
1038178848Scokane    if (XML_GetErrorCode(parser) != XML_ERROR_ABORTED)
1039178848Scokane        xml_failure(parser);
1040178848Scokane}
1041178848ScokaneEND_TEST
1042178848Scokane
1043178848Scokane/* Regression test for SF bug #1515266: missing check of stopped
1044178848Scokane   parser in doContext() 'for' loop. */
1045178848ScokaneSTART_TEST(test_suspend_parser_between_char_data_calls)
1046178848Scokane{
1047178848Scokane    /* The sample data must be big enough that there are two calls to
1048178848Scokane       the character data handler from within the inner "for" loop of
1049178848Scokane       the XML_TOK_DATA_CHARS case in doContent(), and the character
1050178848Scokane       handler must stop the parser and clear the character data
1051178848Scokane       handler.
1052178848Scokane    */
1053178848Scokane    char *text = long_character_data_text;
1054178848Scokane
1055178848Scokane    XML_SetCharacterDataHandler(parser, clearing_aborting_character_handler);
1056178848Scokane    resumable = XML_TRUE;
1057178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) != XML_STATUS_SUSPENDED)
1058178848Scokane        xml_failure(parser);
1059178848Scokane    if (XML_GetErrorCode(parser) != XML_ERROR_NONE)
1060178848Scokane        xml_failure(parser);
1061178848Scokane}
1062178848ScokaneEND_TEST
1063178848Scokane
1064178848Scokane
1065104349Sphk/*
1066104349Sphk * Namespaces tests.
1067104349Sphk */
1068104349Sphk
1069104349Sphkstatic void
1070104349Sphknamespace_setup(void)
1071104349Sphk{
1072104349Sphk    parser = XML_ParserCreateNS(NULL, ' ');
1073104349Sphk    if (parser == NULL)
1074104349Sphk        fail("Parser not created.");
1075104349Sphk}
1076104349Sphk
1077104349Sphkstatic void
1078104349Sphknamespace_teardown(void)
1079104349Sphk{
1080104349Sphk    basic_teardown();
1081104349Sphk}
1082104349Sphk
1083104349Sphk/* Check that an element name and attribute name match the expected values.
1084104349Sphk   The expected values are passed as an array reference of string pointers
1085104349Sphk   provided as the userData argument; the first is the expected
1086104349Sphk   element name, and the second is the expected attribute name.
1087104349Sphk*/
1088178848Scokanestatic void XMLCALL
1089104349Sphktriplet_start_checker(void *userData, const XML_Char *name,
1090104349Sphk                      const XML_Char **atts)
1091104349Sphk{
1092104349Sphk    char **elemstr = (char **)userData;
1093104349Sphk    char buffer[1024];
1094104349Sphk    if (strcmp(elemstr[0], name) != 0) {
1095104349Sphk        sprintf(buffer, "unexpected start string: '%s'", name);
1096104349Sphk        fail(buffer);
1097104349Sphk    }
1098104349Sphk    if (strcmp(elemstr[1], atts[0]) != 0) {
1099104349Sphk        sprintf(buffer, "unexpected attribute string: '%s'", atts[0]);
1100104349Sphk        fail(buffer);
1101104349Sphk    }
1102104349Sphk}
1103104349Sphk
1104104349Sphk/* Check that the element name passed to the end-element handler matches
1105104349Sphk   the expected value.  The expected value is passed as the first element
1106104349Sphk   in an array of strings passed as the userData argument.
1107104349Sphk*/
1108178848Scokanestatic void XMLCALL
1109104349Sphktriplet_end_checker(void *userData, const XML_Char *name)
1110104349Sphk{
1111104349Sphk    char **elemstr = (char **)userData;
1112104349Sphk    if (strcmp(elemstr[0], name) != 0) {
1113104349Sphk        char buffer[1024];
1114104349Sphk        sprintf(buffer, "unexpected end string: '%s'", name);
1115104349Sphk        fail(buffer);
1116104349Sphk    }
1117104349Sphk}
1118104349Sphk
1119104349SphkSTART_TEST(test_return_ns_triplet)
1120104349Sphk{
1121104349Sphk    char *text =
1122104349Sphk        "<foo:e xmlns:foo='http://expat.sf.net/' bar:a='12'\n"
1123104349Sphk        "       xmlns:bar='http://expat.sf.net/'></foo:e>";
1124104349Sphk    char *elemstr[] = {
1125104349Sphk        "http://expat.sf.net/ e foo",
1126104349Sphk        "http://expat.sf.net/ a bar"
1127104349Sphk    };
1128178848Scokane    XML_SetReturnNSTriplet(parser, XML_TRUE);
1129104349Sphk    XML_SetUserData(parser, elemstr);
1130104349Sphk    XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker);
1131178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1132104349Sphk        xml_failure(parser);
1133104349Sphk}
1134104349SphkEND_TEST
1135104349Sphk
1136178848Scokanestatic void XMLCALL
1137104349Sphkoverwrite_start_checker(void *userData, const XML_Char *name,
1138104349Sphk                        const XML_Char **atts)
1139104349Sphk{
1140104349Sphk    CharData *storage = (CharData *) userData;
1141104349Sphk    CharData_AppendString(storage, "start ");
1142104349Sphk    CharData_AppendXMLChars(storage, name, -1);
1143104349Sphk    while (*atts != NULL) {
1144104349Sphk        CharData_AppendString(storage, "\nattribute ");
1145104349Sphk        CharData_AppendXMLChars(storage, *atts, -1);
1146104349Sphk        atts += 2;
1147104349Sphk    }
1148104349Sphk    CharData_AppendString(storage, "\n");
1149104349Sphk}
1150104349Sphk
1151178848Scokanestatic void XMLCALL
1152104349Sphkoverwrite_end_checker(void *userData, const XML_Char *name)
1153104349Sphk{
1154104349Sphk    CharData *storage = (CharData *) userData;
1155104349Sphk    CharData_AppendString(storage, "end ");
1156104349Sphk    CharData_AppendXMLChars(storage, name, -1);
1157104349Sphk    CharData_AppendString(storage, "\n");
1158104349Sphk}
1159104349Sphk
1160104349Sphkstatic void
1161104349Sphkrun_ns_tagname_overwrite_test(char *text, char *result)
1162104349Sphk{
1163104349Sphk    CharData storage;
1164104349Sphk    CharData_Init(&storage);
1165104349Sphk    XML_SetUserData(parser, &storage);
1166104349Sphk    XML_SetElementHandler(parser,
1167104349Sphk                          overwrite_start_checker, overwrite_end_checker);
1168178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1169104349Sphk        xml_failure(parser);
1170104349Sphk    CharData_CheckString(&storage, result);
1171104349Sphk}
1172104349Sphk
1173104349Sphk/* Regression test for SF bug #566334. */
1174104349SphkSTART_TEST(test_ns_tagname_overwrite)
1175104349Sphk{
1176104349Sphk    char *text =
1177104349Sphk        "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
1178104349Sphk        "  <n:f n:attr='foo'/>\n"
1179104349Sphk        "  <n:g n:attr2='bar'/>\n"
1180104349Sphk        "</n:e>";
1181104349Sphk    char *result =
1182104349Sphk        "start http://xml.libexpat.org/ e\n"
1183104349Sphk        "start http://xml.libexpat.org/ f\n"
1184104349Sphk        "attribute http://xml.libexpat.org/ attr\n"
1185104349Sphk        "end http://xml.libexpat.org/ f\n"
1186104349Sphk        "start http://xml.libexpat.org/ g\n"
1187104349Sphk        "attribute http://xml.libexpat.org/ attr2\n"
1188104349Sphk        "end http://xml.libexpat.org/ g\n"
1189104349Sphk        "end http://xml.libexpat.org/ e\n";
1190104349Sphk    run_ns_tagname_overwrite_test(text, result);
1191104349Sphk}
1192104349SphkEND_TEST
1193104349Sphk
1194104349Sphk/* Regression test for SF bug #566334. */
1195104349SphkSTART_TEST(test_ns_tagname_overwrite_triplet)
1196104349Sphk{
1197104349Sphk    char *text =
1198104349Sphk        "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
1199104349Sphk        "  <n:f n:attr='foo'/>\n"
1200104349Sphk        "  <n:g n:attr2='bar'/>\n"
1201104349Sphk        "</n:e>";
1202104349Sphk    char *result =
1203104349Sphk        "start http://xml.libexpat.org/ e n\n"
1204104349Sphk        "start http://xml.libexpat.org/ f n\n"
1205104349Sphk        "attribute http://xml.libexpat.org/ attr n\n"
1206104349Sphk        "end http://xml.libexpat.org/ f n\n"
1207104349Sphk        "start http://xml.libexpat.org/ g n\n"
1208104349Sphk        "attribute http://xml.libexpat.org/ attr2 n\n"
1209104349Sphk        "end http://xml.libexpat.org/ g n\n"
1210104349Sphk        "end http://xml.libexpat.org/ e n\n";
1211178848Scokane    XML_SetReturnNSTriplet(parser, XML_TRUE);
1212104349Sphk    run_ns_tagname_overwrite_test(text, result);
1213104349Sphk}
1214104349SphkEND_TEST
1215104349Sphk
1216178848Scokane
1217178848Scokane/* Regression test for SF bug #620343. */
1218178848Scokanestatic void XMLCALL
1219178848Scokanestart_element_fail(void *userData,
1220178848Scokane                   const XML_Char *name, const XML_Char **atts)
1221178848Scokane{
1222178848Scokane    /* We should never get here. */
1223178848Scokane    fail("should never reach start_element_fail()");
1224178848Scokane}
1225178848Scokane
1226178848Scokanestatic void XMLCALL
1227178848Scokanestart_ns_clearing_start_element(void *userData,
1228178848Scokane                                const XML_Char *prefix,
1229178848Scokane                                const XML_Char *uri)
1230178848Scokane{
1231178848Scokane    XML_SetStartElementHandler((XML_Parser) userData, NULL);
1232178848Scokane}
1233178848Scokane
1234178848ScokaneSTART_TEST(test_start_ns_clears_start_element)
1235178848Scokane{
1236178848Scokane    /* This needs to use separate start/end tags; using the empty tag
1237178848Scokane       syntax doesn't cause the problematic path through Expat to be
1238178848Scokane       taken.
1239178848Scokane    */
1240178848Scokane    char *text = "<e xmlns='http://xml.libexpat.org/'></e>";
1241178848Scokane
1242178848Scokane    XML_SetStartElementHandler(parser, start_element_fail);
1243178848Scokane    XML_SetStartNamespaceDeclHandler(parser, start_ns_clearing_start_element);
1244178848Scokane    XML_UseParserAsHandlerArg(parser);
1245178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1246178848Scokane        xml_failure(parser);
1247178848Scokane}
1248178848ScokaneEND_TEST
1249178848Scokane
1250178848Scokane/* Regression test for SF bug #616863. */
1251178848Scokanestatic int XMLCALL
1252178848Scokaneexternal_entity_handler(XML_Parser parser,
1253178848Scokane                        const XML_Char *context,
1254178848Scokane                        const XML_Char *base,
1255178848Scokane                        const XML_Char *systemId,
1256178848Scokane                        const XML_Char *publicId)
1257178848Scokane{
1258247513Sdelphij    intptr_t callno = 1 + (intptr_t)XML_GetUserData(parser);
1259178848Scokane    char *text;
1260178848Scokane    XML_Parser p2;
1261178848Scokane
1262178848Scokane    if (callno == 1)
1263178848Scokane        text = ("<!ELEMENT doc (e+)>\n"
1264178848Scokane                "<!ATTLIST doc xmlns CDATA #IMPLIED>\n"
1265178848Scokane                "<!ELEMENT e EMPTY>\n");
1266178848Scokane    else
1267178848Scokane        text = ("<?xml version='1.0' encoding='us-ascii'?>"
1268178848Scokane                "<e/>");
1269178848Scokane
1270178848Scokane    XML_SetUserData(parser, (void *) callno);
1271178848Scokane    p2 = XML_ExternalEntityParserCreate(parser, context, NULL);
1272178848Scokane    if (XML_Parse(p2, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR) {
1273178848Scokane        xml_failure(p2);
1274178848Scokane        return 0;
1275178848Scokane    }
1276178848Scokane    XML_ParserFree(p2);
1277178848Scokane    return 1;
1278178848Scokane}
1279178848Scokane
1280178848ScokaneSTART_TEST(test_default_ns_from_ext_subset_and_ext_ge)
1281178848Scokane{
1282178848Scokane    char *text =
1283178848Scokane        "<?xml version='1.0'?>\n"
1284178848Scokane        "<!DOCTYPE doc SYSTEM 'http://xml.libexpat.org/doc.dtd' [\n"
1285178848Scokane        "  <!ENTITY en SYSTEM 'http://xml.libexpat.org/entity.ent'>\n"
1286178848Scokane        "]>\n"
1287178848Scokane        "<doc xmlns='http://xml.libexpat.org/ns1'>\n"
1288178848Scokane        "&en;\n"
1289178848Scokane        "</doc>";
1290178848Scokane
1291178848Scokane    XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
1292178848Scokane    XML_SetExternalEntityRefHandler(parser, external_entity_handler);
1293178848Scokane    /* We actually need to set this handler to tickle this bug. */
1294178848Scokane    XML_SetStartElementHandler(parser, dummy_start_element);
1295178848Scokane    XML_SetUserData(parser, NULL);
1296178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1297178848Scokane        xml_failure(parser);
1298178848Scokane}
1299178848ScokaneEND_TEST
1300178848Scokane
1301178848Scokane/* Regression test #1 for SF bug #673791. */
1302178848ScokaneSTART_TEST(test_ns_prefix_with_empty_uri_1)
1303178848Scokane{
1304178848Scokane    char *text =
1305178848Scokane        "<doc xmlns:prefix='http://xml.libexpat.org/'>\n"
1306178848Scokane        "  <e xmlns:prefix=''/>\n"
1307178848Scokane        "</doc>";
1308178848Scokane
1309178848Scokane    expect_failure(text,
1310178848Scokane                   XML_ERROR_UNDECLARING_PREFIX,
1311178848Scokane                   "Did not report re-setting namespace"
1312178848Scokane                   " URI with prefix to ''.");
1313178848Scokane}
1314178848ScokaneEND_TEST
1315178848Scokane
1316178848Scokane/* Regression test #2 for SF bug #673791. */
1317178848ScokaneSTART_TEST(test_ns_prefix_with_empty_uri_2)
1318178848Scokane{
1319178848Scokane    char *text =
1320178848Scokane        "<?xml version='1.0'?>\n"
1321178848Scokane        "<docelem xmlns:pre=''/>";
1322178848Scokane
1323178848Scokane    expect_failure(text,
1324178848Scokane                   XML_ERROR_UNDECLARING_PREFIX,
1325178848Scokane                   "Did not report setting namespace URI with prefix to ''.");
1326178848Scokane}
1327178848ScokaneEND_TEST
1328178848Scokane
1329178848Scokane/* Regression test #3 for SF bug #673791. */
1330178848ScokaneSTART_TEST(test_ns_prefix_with_empty_uri_3)
1331178848Scokane{
1332178848Scokane    char *text =
1333178848Scokane        "<!DOCTYPE doc [\n"
1334178848Scokane        "  <!ELEMENT doc EMPTY>\n"
1335178848Scokane        "  <!ATTLIST doc\n"
1336178848Scokane        "    xmlns:prefix CDATA ''>\n"
1337178848Scokane        "]>\n"
1338178848Scokane        "<doc/>";
1339178848Scokane
1340178848Scokane    expect_failure(text,
1341178848Scokane                   XML_ERROR_UNDECLARING_PREFIX,
1342178848Scokane                   "Didn't report attr default setting NS w/ prefix to ''.");
1343178848Scokane}
1344178848ScokaneEND_TEST
1345178848Scokane
1346178848Scokane/* Regression test #4 for SF bug #673791. */
1347178848ScokaneSTART_TEST(test_ns_prefix_with_empty_uri_4)
1348178848Scokane{
1349178848Scokane    char *text =
1350178848Scokane        "<!DOCTYPE doc [\n"
1351178848Scokane        "  <!ELEMENT prefix:doc EMPTY>\n"
1352178848Scokane        "  <!ATTLIST prefix:doc\n"
1353178848Scokane        "    xmlns:prefix CDATA 'http://xml.libexpat.org/'>\n"
1354178848Scokane        "]>\n"
1355178848Scokane        "<prefix:doc/>";
1356178848Scokane    /* Packaged info expected by the end element handler;
1357178848Scokane       the weird structuring lets us re-use the triplet_end_checker()
1358178848Scokane       function also used for another test. */
1359178848Scokane    char *elemstr[] = {
1360178848Scokane        "http://xml.libexpat.org/ doc prefix"
1361178848Scokane    };
1362178848Scokane    XML_SetReturnNSTriplet(parser, XML_TRUE);
1363178848Scokane    XML_SetUserData(parser, elemstr);
1364178848Scokane    XML_SetEndElementHandler(parser, triplet_end_checker);
1365178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1366178848Scokane        xml_failure(parser);
1367178848Scokane}
1368178848ScokaneEND_TEST
1369178848Scokane
1370178848ScokaneSTART_TEST(test_ns_default_with_empty_uri)
1371178848Scokane{
1372178848Scokane    char *text =
1373178848Scokane        "<doc xmlns='http://xml.libexpat.org/'>\n"
1374178848Scokane        "  <e xmlns=''/>\n"
1375178848Scokane        "</doc>";
1376178848Scokane    if (XML_Parse(parser, text, strlen(text), XML_TRUE) == XML_STATUS_ERROR)
1377178848Scokane        xml_failure(parser);
1378178848Scokane}
1379178848ScokaneEND_TEST
1380178848Scokane
1381178848Scokane/* Regression test for SF bug #692964: two prefixes for one namespace. */
1382178848ScokaneSTART_TEST(test_ns_duplicate_attrs_diff_prefixes)
1383178848Scokane{
1384178848Scokane    char *text =
1385178848Scokane        "<doc xmlns:a='http://xml.libexpat.org/a'\n"
1386178848Scokane        "     xmlns:b='http://xml.libexpat.org/a'\n"
1387178848Scokane        "     a:a='v' b:a='v' />";
1388178848Scokane    expect_failure(text,
1389178848Scokane                   XML_ERROR_DUPLICATE_ATTRIBUTE,
1390178848Scokane                   "did not report multiple attributes with same URI+name");
1391178848Scokane}
1392178848ScokaneEND_TEST
1393178848Scokane
1394178848Scokane/* Regression test for SF bug #695401: unbound prefix. */
1395178848ScokaneSTART_TEST(test_ns_unbound_prefix_on_attribute)
1396178848Scokane{
1397178848Scokane    char *text = "<doc a:attr=''/>";
1398178848Scokane    expect_failure(text,
1399178848Scokane                   XML_ERROR_UNBOUND_PREFIX,
1400178848Scokane                   "did not report unbound prefix on attribute");
1401178848Scokane}
1402178848ScokaneEND_TEST
1403178848Scokane
1404178848Scokane/* Regression test for SF bug #695401: unbound prefix. */
1405178848ScokaneSTART_TEST(test_ns_unbound_prefix_on_element)
1406178848Scokane{
1407178848Scokane    char *text = "<a:doc/>";
1408178848Scokane    expect_failure(text,
1409178848Scokane                   XML_ERROR_UNBOUND_PREFIX,
1410178848Scokane                   "did not report unbound prefix on element");
1411178848Scokane}
1412178848ScokaneEND_TEST
1413178848Scokane
1414104349Sphkstatic Suite *
1415178848Scokanemake_suite(void)
1416104349Sphk{
1417104349Sphk    Suite *s = suite_create("basic");
1418104349Sphk    TCase *tc_basic = tcase_create("basic tests");
1419104349Sphk    TCase *tc_namespace = tcase_create("XML namespaces");
1420104349Sphk
1421104349Sphk    suite_add_tcase(s, tc_basic);
1422104349Sphk    tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
1423104349Sphk    tcase_add_test(tc_basic, test_nul_byte);
1424104349Sphk    tcase_add_test(tc_basic, test_u0000_char);
1425104349Sphk    tcase_add_test(tc_basic, test_bom_utf8);
1426104349Sphk    tcase_add_test(tc_basic, test_bom_utf16_be);
1427104349Sphk    tcase_add_test(tc_basic, test_bom_utf16_le);
1428104349Sphk    tcase_add_test(tc_basic, test_illegal_utf8);
1429104349Sphk    tcase_add_test(tc_basic, test_utf16);
1430104349Sphk    tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
1431104349Sphk    tcase_add_test(tc_basic, test_latin1_umlauts);
1432104349Sphk    /* Regression test for SF bug #491986. */
1433104349Sphk    tcase_add_test(tc_basic, test_danish_latin1);
1434104349Sphk    /* Regression test for SF bug #514281. */
1435104349Sphk    tcase_add_test(tc_basic, test_french_charref_hexidecimal);
1436104349Sphk    tcase_add_test(tc_basic, test_french_charref_decimal);
1437104349Sphk    tcase_add_test(tc_basic, test_french_latin1);
1438104349Sphk    tcase_add_test(tc_basic, test_french_utf8);
1439104349Sphk    tcase_add_test(tc_basic, test_utf8_false_rejection);
1440178848Scokane    tcase_add_test(tc_basic, test_line_number_after_parse);
1441178848Scokane    tcase_add_test(tc_basic, test_column_number_after_parse);
1442178848Scokane    tcase_add_test(tc_basic, test_line_and_column_numbers_inside_handlers);
1443178848Scokane    tcase_add_test(tc_basic, test_line_number_after_error);
1444178848Scokane    tcase_add_test(tc_basic, test_column_number_after_error);
1445104349Sphk    tcase_add_test(tc_basic, test_really_long_lines);
1446104349Sphk    tcase_add_test(tc_basic, test_end_element_events);
1447104349Sphk    tcase_add_test(tc_basic, test_attr_whitespace_normalization);
1448104349Sphk    tcase_add_test(tc_basic, test_xmldecl_misplaced);
1449104349Sphk    tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
1450104349Sphk    tcase_add_test(tc_basic,
1451104349Sphk                   test_wfc_undeclared_entity_unread_external_subset);
1452104349Sphk    tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
1453104349Sphk    tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
1454104349Sphk    tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
1455178848Scokane    tcase_add_test(tc_basic,
1456178848Scokane                   test_wfc_undeclared_entity_with_external_subset_standalone);
1457104349Sphk    tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
1458178848Scokane    tcase_add_test(tc_basic, test_ext_entity_set_encoding);
1459178848Scokane    tcase_add_test(tc_basic, test_dtd_default_handling);
1460178848Scokane    tcase_add_test(tc_basic, test_empty_ns_without_namespaces);
1461178848Scokane    tcase_add_test(tc_basic, test_ns_in_attribute_default_without_namespaces);
1462178848Scokane    tcase_add_test(tc_basic, test_stop_parser_between_char_data_calls);
1463178848Scokane    tcase_add_test(tc_basic, test_suspend_parser_between_char_data_calls);
1464104349Sphk
1465104349Sphk    suite_add_tcase(s, tc_namespace);
1466104349Sphk    tcase_add_checked_fixture(tc_namespace,
1467104349Sphk                              namespace_setup, namespace_teardown);
1468104349Sphk    tcase_add_test(tc_namespace, test_return_ns_triplet);
1469104349Sphk    tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
1470104349Sphk    tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
1471178848Scokane    tcase_add_test(tc_namespace, test_start_ns_clears_start_element);
1472178848Scokane    tcase_add_test(tc_namespace, test_default_ns_from_ext_subset_and_ext_ge);
1473178848Scokane    tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_1);
1474178848Scokane    tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_2);
1475178848Scokane    tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_3);
1476178848Scokane    tcase_add_test(tc_namespace, test_ns_prefix_with_empty_uri_4);
1477178848Scokane    tcase_add_test(tc_namespace, test_ns_default_with_empty_uri);
1478178848Scokane    tcase_add_test(tc_namespace, test_ns_duplicate_attrs_diff_prefixes);
1479178848Scokane    tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_attribute);
1480178848Scokane    tcase_add_test(tc_namespace, test_ns_unbound_prefix_on_element);
1481104349Sphk
1482104349Sphk    return s;
1483104349Sphk}
1484104349Sphk
1485104349Sphk
1486104349Sphkint
1487104349Sphkmain(int argc, char *argv[])
1488104349Sphk{
1489104349Sphk    int i, nf;
1490104349Sphk    int verbosity = CK_NORMAL;
1491178848Scokane    Suite *s = make_suite();
1492104349Sphk    SRunner *sr = srunner_create(s);
1493104349Sphk
1494104349Sphk    /* run the tests for internal helper functions */
1495104349Sphk    testhelper_is_whitespace_normalized();
1496104349Sphk
1497104349Sphk    for (i = 1; i < argc; ++i) {
1498104349Sphk        char *opt = argv[i];
1499104349Sphk        if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
1500104349Sphk            verbosity = CK_VERBOSE;
1501104349Sphk        else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
1502104349Sphk            verbosity = CK_SILENT;
1503104349Sphk        else {
1504104349Sphk            fprintf(stderr, "runtests: unknown option '%s'\n", opt);
1505104349Sphk            return 2;
1506104349Sphk        }
1507104349Sphk    }
1508178848Scokane    if (verbosity != CK_SILENT)
1509178848Scokane        printf("Expat version: %s\n", XML_ExpatVersion());
1510104349Sphk    srunner_run_all(sr, verbosity);
1511104349Sphk    nf = srunner_ntests_failed(sr);
1512104349Sphk    srunner_free(sr);
1513104349Sphk
1514104349Sphk    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
1515104349Sphk}
1516