home *** CD-ROM | disk | FTP | other *** search
/ Netrunner 2004 October / NETRUNNER0410.ISO / regular / ActivePerl-5.8.4.810-MSWin32-x86.msi / _f9f73a9928ac09281a1a88d5fe44674f < prev    next >
Text File  |  2004-06-01  |  28KB  |  883 lines

  1. #include <assert.h>
  2. #include <check.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6.  
  7. #include "expat.h"
  8. #include "chardata.h"
  9.  
  10.  
  11. static XML_Parser parser;
  12.  
  13.  
  14. static void
  15. basic_setup(void)
  16. {
  17.     parser = XML_ParserCreate(NULL);
  18.     if (parser == NULL)
  19.         fail("Parser not created.");
  20. }
  21.  
  22. static void
  23. basic_teardown(void)
  24. {
  25.     if (parser != NULL)
  26.         XML_ParserFree(parser);
  27. }
  28.  
  29. /* Generate a failure using the parser state to create an error message;
  30.    this should be used when the parser reports an error we weren't
  31.    expecting.
  32. */
  33. static void
  34. _xml_failure(XML_Parser parser, const char *file, int line)
  35. {
  36.     char buffer[1024];
  37.     sprintf(buffer,
  38.             "\n    %s (line %d, offset %d)\n    reported from %s, line %d",
  39.             XML_ErrorString(XML_GetErrorCode(parser)),
  40.             XML_GetCurrentLineNumber(parser),
  41.             XML_GetCurrentColumnNumber(parser),
  42.             file, line);
  43.     fail(buffer);
  44. }
  45.  
  46. #define xml_failure(parser) _xml_failure((parser), __FILE__, __LINE__)
  47.  
  48. static void
  49. _expect_failure(char *text, enum XML_Error errorCode, char *errorMessage,
  50.                 char *file, int lineno)
  51. {
  52.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_OK)
  53.         fail(errorMessage);
  54.     if (XML_GetErrorCode(parser) != errorCode)
  55.         _xml_failure(parser, file, lineno);
  56. }
  57.  
  58. #define expect_failure(text, errorCode, errorMessage) \
  59.         _expect_failure((text), (errorCode), (errorMessage), \
  60.                         __FILE__, __LINE__)
  61.  
  62.  
  63. /*
  64.  * Character & encoding tests.
  65.  */
  66.  
  67. START_TEST(test_nul_byte)
  68. {
  69.     char text[] = "<doc>\0</doc>";
  70.  
  71.     /* test that a NUL byte (in US-ASCII data) is an error */
  72.     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_OK)
  73.         fail("Parser did not report error on NUL-byte.");
  74.     if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
  75.         xml_failure(parser);
  76. }
  77. END_TEST
  78.  
  79.  
  80. START_TEST(test_u0000_char)
  81. {
  82.     /* test that a NUL byte (in US-ASCII data) is an error */
  83.     expect_failure("<doc>�</doc>",
  84.                    XML_ERROR_BAD_CHAR_REF,
  85.                    "Parser did not report error on NUL-byte.");
  86. }
  87. END_TEST
  88.  
  89. START_TEST(test_bom_utf8)
  90. {
  91.     /* This test is really just making sure we don't core on a UTF-8 BOM. */
  92.     char *text = "\357\273\277<e/>";
  93.  
  94.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  95.         xml_failure(parser);
  96. }
  97. END_TEST
  98.  
  99. START_TEST(test_bom_utf16_be)
  100. {
  101.     char text[] = "\376\377\0<\0e\0/\0>";
  102.  
  103.     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_ERROR)
  104.         xml_failure(parser);
  105. }
  106. END_TEST
  107.  
  108. START_TEST(test_bom_utf16_le)
  109. {
  110.     char text[] = "\377\376<\0e\0/\0>\0";
  111.  
  112.     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_ERROR)
  113.         xml_failure(parser);
  114. }
  115. END_TEST
  116.  
  117. static void
  118. accumulate_characters(void *userData, const XML_Char *s, int len)
  119. {
  120.     CharData_AppendXMLChars((CharData *)userData, s, len);
  121. }
  122.  
  123. static void
  124. accumulate_attribute(void *userData, const XML_Char *name,
  125.                      const XML_Char **atts)
  126. {
  127.     CharData *storage = (CharData *)userData;
  128.     if (storage->count < 0 && atts != NULL && atts[0] != NULL) {
  129.         /* "accumulate" the value of the first attribute we see */
  130.         CharData_AppendXMLChars(storage, atts[1], -1);
  131.     }
  132. }
  133.  
  134.  
  135. static void
  136. run_character_check(XML_Char *text, XML_Char *expected)
  137. {
  138.     CharData storage;
  139.  
  140.     CharData_Init(&storage);
  141.     XML_SetUserData(parser, &storage);
  142.     XML_SetCharacterDataHandler(parser, accumulate_characters);
  143.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  144.         xml_failure(parser);
  145.     CharData_CheckXMLChars(&storage, expected);
  146. }
  147.  
  148. static void
  149. run_attribute_check(XML_Char *text, XML_Char *expected)
  150. {
  151.     CharData storage;
  152.  
  153.     CharData_Init(&storage);
  154.     XML_SetUserData(parser, &storage);
  155.     XML_SetStartElementHandler(parser, accumulate_attribute);
  156.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  157.         xml_failure(parser);
  158.     CharData_CheckXMLChars(&storage, expected);
  159. }
  160.  
  161. /* Regression test for SF bug #491986. */
  162. START_TEST(test_danish_latin1)
  163. {
  164.     char *text =
  165.         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
  166.         "<e>J°rgen µ°σ╞╪┼</e>";
  167.     run_character_check(text,
  168.              "J\xC3\xB8rgen \xC3\xA6\xC3\xB8\xC3\xA5\xC3\x86\xC3\x98\xC3\x85");
  169. }
  170. END_TEST
  171.  
  172.  
  173. /* Regression test for SF bug #514281. */
  174. START_TEST(test_french_charref_hexidecimal)
  175. {
  176.     char *text =
  177.         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
  178.         "<doc>éèàçêÈ</doc>";
  179.     run_character_check(text,
  180.                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
  181. }
  182. END_TEST
  183.  
  184. START_TEST(test_french_charref_decimal)
  185. {
  186.     char *text =
  187.         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
  188.         "<doc>éèàçêÈ</doc>";
  189.     run_character_check(text,
  190.                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
  191. }
  192. END_TEST
  193.  
  194. START_TEST(test_french_latin1)
  195. {
  196.     char *text =
  197.         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
  198.         "<doc>\xE9\xE8\xE0\xE7\xEa\xC8</doc>";
  199.     run_character_check(text,
  200.                         "\xC3\xA9\xC3\xA8\xC3\xA0\xC3\xA7\xC3\xAA\xC3\x88");
  201. }
  202. END_TEST
  203.  
  204. START_TEST(test_french_utf8)
  205. {
  206.     char *text =
  207.         "<?xml version='1.0' encoding='utf-8'?>\n"
  208.         "<doc>\xC3\xA9</doc>";
  209.     run_character_check(text, "\xC3\xA9");
  210. }
  211. END_TEST
  212.  
  213. /* Regression test for SF bug #600479.
  214.    XXX There should be a test that exercises all legal XML Unicode
  215.    characters as PCDATA and attribute value content, and XML Name
  216.    characters as part of element and attribute names.
  217. */
  218. START_TEST(test_utf8_false_rejection)
  219. {
  220.     char *text = "<doc>\xEF\xBA\xBF</doc>";
  221.     run_character_check(text, "\xEF\xBA\xBF");
  222. }
  223. END_TEST
  224.  
  225. /* Regression test for SF bug #477667.
  226.    This test assures that any 8-bit character followed by a 7-bit
  227.    character will not be mistakenly interpreted as a valid UTF-8
  228.    sequence.
  229. */
  230. START_TEST(test_illegal_utf8)
  231. {
  232.     char text[100];
  233.     int i;
  234.  
  235.     for (i = 128; i <= 255; ++i) {
  236.         sprintf(text, "<e>%ccd</e>", i);
  237.         if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_OK) {
  238.             sprintf(text,
  239.                     "expected token error for '%c' (ordinal %d) in UTF-8 text",
  240.                     i, i);
  241.             fail(text);
  242.         }
  243.         else if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
  244.             xml_failure(parser);
  245.         /* Reset the parser since we use the same parser repeatedly. */
  246.         XML_ParserReset(parser, NULL);
  247.     }
  248. }
  249. END_TEST
  250.  
  251. START_TEST(test_utf16)
  252. {
  253.     /* <?xml version="1.0" encoding="UTF-16"?>
  254.        <doc a='123'>some text</doc>
  255.     */
  256.     char text[] =
  257.         "\000<\000?\000x\000m\000\154\000 \000v\000e\000r\000s\000i\000o"
  258.         "\000n\000=\000'\0001\000.\000\060\000'\000 \000e\000n\000c\000o"
  259.         "\000d\000i\000n\000g\000=\000'\000U\000T\000F\000-\0001\000\066"
  260.         "\000'\000?\000>\000\n"
  261.         "\000<\000d\000o\000c\000 \000a\000=\000'\0001\0002\0003\000'"
  262.         "\000>\000s\000o\000m\000e\000 \000t\000e\000x\000t\000<\000/"
  263.         "\000d\000o\000c\000>";
  264.     if (XML_Parse(parser, text, sizeof(text) - 1, 1) == XML_STATUS_ERROR)
  265.         xml_failure(parser);
  266. }
  267. END_TEST
  268.  
  269. START_TEST(test_utf16_le_epilog_newline)
  270. {
  271.     int first_chunk_bytes = 17;
  272.     char text[] = 
  273.         "\xFF\xFE"                      /* BOM */
  274.         "<\000e\000/\000>\000"          /* document element */
  275.         "\r\000\n\000\r\000\n\000";     /* epilog */
  276.  
  277.     if (first_chunk_bytes >= sizeof(text) - 1)
  278.         fail("bad value of first_chunk_bytes");
  279.     if (XML_Parse(parser, text, first_chunk_bytes, 0) == XML_STATUS_ERROR)
  280.         xml_failure(parser);
  281.     else {
  282.         enum XML_Status rc;
  283.         rc = XML_Parse(parser, text + first_chunk_bytes,
  284.                        sizeof(text) - first_chunk_bytes - 1, 1);
  285.         if (rc == XML_STATUS_ERROR)
  286.             xml_failure(parser);
  287.     }
  288. }
  289. END_TEST
  290.  
  291. /* Regression test for SF bug #481609. */
  292. START_TEST(test_latin1_umlauts)
  293. {
  294.     char *text =
  295.         "<?xml version='1.0' encoding='iso-8859-1'?>\n"
  296.         "<e a='Σ ÷ ⁿ ä ö ü ä ö ü'\n"
  297.         "  >Σ ÷ ⁿ ä ö ü ä ö ü</e>";
  298.     char *utf8 =
  299.         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
  300.         "\xC3\xA4 \xC3\xB6 \xC3\xBC "
  301.         "\xC3\xA4 \xC3\xB6 \xC3\xBC";
  302.     run_character_check(text, utf8);
  303.     XML_ParserReset(parser, NULL);
  304.     run_attribute_check(text, utf8);
  305. }
  306. END_TEST
  307.  
  308. /* Regression test for SF bug #422239 (maybe).
  309.    It's not clear that this reproduces enough of the context
  310.    of the reported bug.
  311. */
  312. START_TEST(test_line_count)
  313. {
  314.     char *text =
  315.         "<e>\n"
  316.         "  <e/>\n"
  317.         "</e>";
  318.     int lineno;
  319.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  320.         xml_failure(parser);
  321.     lineno = XML_GetCurrentLineNumber(parser);
  322.     if (lineno != 3) {
  323.         char buffer[100];
  324.         sprintf(buffer, "expected 3 lines, saw %d", lineno);
  325.         fail(buffer);
  326.     }
  327. }
  328. END_TEST
  329.  
  330. /* Regression test for SF bug #478332. */
  331. START_TEST(test_really_long_lines)
  332. {
  333.     /* This parses an input line longer than INIT_DATA_BUF_SIZE
  334.        characters long (defined to be 1024 in xmlparse.c).  We take a
  335.        really cheesy approach to building the input buffer, because
  336.        this avoids writing bugs in buffer-filling code.
  337.     */
  338.     char *text =
  339.         "<e>"
  340.         /* 64 chars */
  341.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  342.         /* until we have at least 1024 characters on the line: */
  343.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  344.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  345.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  346.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  347.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  348.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  349.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  350.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  351.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  352.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  353.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  354.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  355.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  356.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  357.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  358.         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-+"
  359.         "</e>";
  360.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  361.         xml_failure(parser);
  362. }
  363. END_TEST
  364.  
  365.  
  366. /*
  367.  * Element event tests.
  368.  */
  369.  
  370. static void
  371. end_element_event_handler(void *userData, const XML_Char *name)
  372. {
  373.     CharData *storage = (CharData *) userData;
  374.     CharData_AppendString(storage, "/");
  375.     CharData_AppendXMLChars(storage, name, -1);
  376. }
  377.  
  378. START_TEST(test_end_element_events)
  379. {
  380.     char *text = "<a><b><c/></b><d><f/></d></a>";
  381.     char *expected = "/c/b/f/d/a";
  382.     CharData storage;
  383.  
  384.     CharData_Init(&storage);
  385.     XML_SetUserData(parser, &storage);
  386.     XML_SetEndElementHandler(parser, end_element_event_handler);
  387.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  388.         xml_failure(parser);
  389.     CharData_CheckString(&storage, expected);
  390. }
  391. END_TEST
  392.  
  393.  
  394. /*
  395.  * Attribute tests.
  396.  */
  397.  
  398. /* Helpers used by the following test; this checks any "attr" and "refs"
  399.    attributes to make sure whitespace has been normalized.
  400.  
  401.    Return true if whitespace has been normalized in a string, using
  402.    the rules for attribute value normalization.  The 'is_cdata' flag
  403.    is needed since CDATA attributes don't need to have multiple
  404.    whitespace characters collapsed to a single space, while other
  405.    attribute data types do.  (Section 3.3.3 of the recommendation.)
  406. */
  407. static int
  408. is_whitespace_normalized(const XML_Char *s, int is_cdata)
  409. {
  410.     int blanks = 0;
  411.     int at_start = 1;
  412.     while (*s) {
  413.         if (*s == ' ')
  414.             ++blanks;
  415.         else if (*s == '\t' || *s == '\n' || *s == '\r')
  416.             return 0;
  417.         else {
  418.             if (at_start) {
  419.                 at_start = 0;
  420.                 if (blanks && !is_cdata)
  421.                     /* illegal leading blanks */
  422.                     return 0;
  423.             }
  424.             else if (blanks > 1 && !is_cdata)
  425.                 return 0;
  426.             blanks = 0;
  427.         }
  428.         ++s;
  429.     }
  430.     if (blanks && !is_cdata)
  431.         return 0;
  432.     return 1;
  433. }
  434.  
  435. /* Check the attribute whitespace checker: */
  436. static void
  437. testhelper_is_whitespace_normalized(void)
  438. {
  439.     assert(is_whitespace_normalized("abc", 0));
  440.     assert(is_whitespace_normalized("abc", 1));
  441.     assert(is_whitespace_normalized("abc def ghi", 0));
  442.     assert(is_whitespace_normalized("abc def ghi", 1));
  443.     assert(!is_whitespace_normalized(" abc def ghi", 0));
  444.     assert(is_whitespace_normalized(" abc def ghi", 1));
  445.     assert(!is_whitespace_normalized("abc  def ghi", 0));
  446.     assert(is_whitespace_normalized("abc  def ghi", 1));
  447.     assert(!is_whitespace_normalized("abc def ghi ", 0));
  448.     assert(is_whitespace_normalized("abc def ghi ", 1));
  449.     assert(!is_whitespace_normalized(" ", 0));
  450.     assert(is_whitespace_normalized(" ", 1));
  451.     assert(!is_whitespace_normalized("\t", 0));
  452.     assert(!is_whitespace_normalized("\t", 1));
  453.     assert(!is_whitespace_normalized("\n", 0));
  454.     assert(!is_whitespace_normalized("\n", 1));
  455.     assert(!is_whitespace_normalized("\r", 0));
  456.     assert(!is_whitespace_normalized("\r", 1));
  457.     assert(!is_whitespace_normalized("abc\t def", 1));
  458. }
  459.  
  460. static void
  461. check_attr_contains_normalized_whitespace(void *userData,
  462.                                           const XML_Char *name,
  463.                                           const XML_Char **atts)
  464. {
  465.     int i;
  466.     for (i = 0; atts[i] != NULL; i += 2) {
  467.         const XML_Char *attrname = atts[i];
  468.         const XML_Char *value = atts[i + 1];
  469.         if (strcmp("attr", attrname) == 0
  470.             || strcmp("ents", attrname) == 0
  471.             || strcmp("refs", attrname) == 0) {
  472.             if (!is_whitespace_normalized(value, 0)) {
  473.                 char buffer[256];
  474.                 sprintf(buffer, "attribute value not normalized: %s='%s'",
  475.                         attrname, value);
  476.                 fail(buffer);
  477.             }
  478.         }
  479.     }
  480. }
  481.  
  482. START_TEST(test_attr_whitespace_normalization)
  483. {
  484.     char *text =
  485.         "<!DOCTYPE doc [\n"
  486.         "  <!ATTLIST doc\n"
  487.         "            attr NMTOKENS #REQUIRED\n"
  488.         "            ents ENTITIES #REQUIRED\n"
  489.         "            refs IDREFS   #REQUIRED>\n"
  490.         "]>\n"
  491.         "<doc attr='    a  b c\t\td\te\t' refs=' id-1   \t  id-2\t\t'  \n"
  492.         "     ents=' ent-1   \t\r\n"
  493.         "            ent-2  ' >\n"
  494.         "  <e id='id-1'/>\n"
  495.         "  <e id='id-2'/>\n"
  496.         "</doc>";
  497.  
  498.     XML_SetStartElementHandler(parser,
  499.                                check_attr_contains_normalized_whitespace);
  500.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  501.         xml_failure(parser);
  502. }
  503. END_TEST
  504.  
  505.  
  506. /*
  507.  * XML declaration tests.
  508.  */
  509.  
  510. START_TEST(test_xmldecl_misplaced)
  511. {
  512.     expect_failure("\n"
  513.                    "<?xml version='1.0'?>\n"
  514.                    "<a/>",
  515.                    XML_ERROR_MISPLACED_XML_PI,
  516.                    "failed to report misplaced XML declaration");
  517. }
  518. END_TEST
  519.  
  520. /* Regression test for SF bug #584832. */
  521. static int
  522. UnknownEncodingHandler(void *data,const XML_Char *encoding,XML_Encoding *info)
  523. {
  524.     if (strcmp(encoding,"unsupported-encoding") == 0) {
  525.         int i;
  526.         for (i = 0; i < 256; ++i)
  527.             info->map[i] = i;
  528.         info->data=NULL;
  529.         info->convert=NULL;
  530.         info->release=NULL;
  531.         return 1;
  532.     }
  533.     return 0;
  534. }
  535.  
  536. START_TEST(test_unknown_encoding_internal_entity)
  537. {
  538.     char *text =
  539.         "<?xml version='1.0' encoding='unsupported-encoding'?>\n"
  540.         "<!DOCTYPE test [<!ENTITY foo 'bar'>]>\n"
  541.         "<test a='&foo;'/>";
  542.  
  543.     XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, NULL);
  544.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  545.         xml_failure(parser);
  546. }
  547. END_TEST
  548.  
  549. /* Test that no error is reported for unknown entities if we don't
  550.    read an external subset.  This was fixed in Expat 1.95.5.
  551. */
  552. START_TEST(test_wfc_undeclared_entity_unread_external_subset) {
  553.     char *text =
  554.         "<!DOCTYPE doc SYSTEM 'foo'>\n"
  555.         "<doc>&entity;</doc>";
  556.  
  557.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  558.         xml_failure(parser);
  559. }
  560. END_TEST
  561.  
  562. /* Test that an error is reported for unknown entities if we don't
  563.    have an external subset.
  564. */
  565. START_TEST(test_wfc_undeclared_entity_no_external_subset) {
  566.     expect_failure("<doc>&entity;</doc>",
  567.                    XML_ERROR_UNDEFINED_ENTITY,
  568.                    "Parser did not report undefined entity w/out a DTD.");
  569. }
  570. END_TEST
  571.  
  572. /* Test that an error is reported for unknown entities if we don't
  573.    read an external subset, but have been declared standalone.
  574. */
  575. START_TEST(test_wfc_undeclared_entity_standalone) {
  576.     char *text =
  577.         "<?xml version='1.0' encoding='us-ascii' standalone='yes'?>\n"
  578.         "<!DOCTYPE doc SYSTEM 'foo'>\n"
  579.         "<doc>&entity;</doc>";
  580.  
  581.     expect_failure(text,
  582.                    XML_ERROR_UNDEFINED_ENTITY,
  583.                    "Parser did not report undefined entity (standalone).");
  584. }
  585. END_TEST
  586.  
  587. static int
  588. external_entity_loader(XML_Parser parser,
  589.                        const XML_Char *context,
  590.                        const XML_Char *base,
  591.                        const XML_Char *systemId,
  592.                        const XML_Char *publicId)
  593. {
  594.     char *text = (char *)XML_GetUserData(parser);
  595.     XML_Parser extparser;
  596.  
  597.     extparser = XML_ExternalEntityParserCreate(parser, context, NULL);
  598.     if (extparser == NULL)
  599.         fail("Could not create external entity parser.");
  600.     if (XML_Parse(extparser, text, strlen(text), 1) == XML_STATUS_ERROR) {
  601.         xml_failure(parser);
  602.         return 0;
  603.     }
  604.     return 1;
  605. }
  606.  
  607. /* Test that an error is reported for unknown entities if we have read
  608.    an external subset.
  609. */
  610. START_TEST(test_wfc_undeclared_entity_with_external_subset) {
  611.     char *text =
  612.         "<?xml version='1.0' encoding='us-ascii'?>\n"
  613.         "<!DOCTYPE doc SYSTEM 'foo'>\n"
  614.         "<doc>&entity;</doc>";
  615.     char *foo_text =
  616.         "<!ELEMENT doc (#PCDATA)*>";
  617.  
  618.     XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
  619.     XML_SetUserData(parser, foo_text);
  620.     XML_SetExternalEntityRefHandler(parser, external_entity_loader);
  621.     expect_failure(text,
  622.                    XML_ERROR_UNDEFINED_ENTITY,
  623.                    "Parser did not report undefined entity with DTD.");
  624. }
  625. END_TEST
  626.  
  627. START_TEST(test_wfc_no_recursive_entity_refs)
  628. {
  629.     char *text =
  630.         "<!DOCTYPE doc [\n"
  631.         "  <!ENTITY entity '&entity;'>\n"
  632.         "]>\n"
  633.         "<doc>&entity;</doc>";
  634.  
  635.     expect_failure(text,
  636.                    XML_ERROR_RECURSIVE_ENTITY_REF,
  637.                    "Parser did not report recursive entity reference.");
  638. }
  639. END_TEST
  640.  
  641.  
  642. /*
  643.  * Namespaces tests.
  644.  */
  645.  
  646. static void
  647. namespace_setup(void)
  648. {
  649.     parser = XML_ParserCreateNS(NULL, ' ');
  650.     if (parser == NULL)
  651.         fail("Parser not created.");
  652. }
  653.  
  654. static void
  655. namespace_teardown(void)
  656. {
  657.     basic_teardown();
  658. }
  659.  
  660. /* Check that an element name and attribute name match the expected values.
  661.    The expected values are passed as an array reference of string pointers
  662.    provided as the userData argument; the first is the expected
  663.    element name, and the second is the expected attribute name.
  664. */
  665. static void
  666. triplet_start_checker(void *userData, const XML_Char *name,
  667.                       const XML_Char **atts)
  668. {
  669.     char **elemstr = (char **)userData;
  670.     char buffer[1024];
  671.     if (strcmp(elemstr[0], name) != 0) {
  672.         sprintf(buffer, "unexpected start string: '%s'", name);
  673.         fail(buffer);
  674.     }
  675.     if (strcmp(elemstr[1], atts[0]) != 0) {
  676.         sprintf(buffer, "unexpected attribute string: '%s'", atts[0]);
  677.         fail(buffer);
  678.     }
  679. }
  680.  
  681. /* Check that the element name passed to the end-element handler matches
  682.    the expected value.  The expected value is passed as the first element
  683.    in an array of strings passed as the userData argument.
  684. */
  685. static void
  686. triplet_end_checker(void *userData, const XML_Char *name)
  687. {
  688.     char **elemstr = (char **)userData;
  689.     if (strcmp(elemstr[0], name) != 0) {
  690.         char buffer[1024];
  691.         sprintf(buffer, "unexpected end string: '%s'", name);
  692.         fail(buffer);
  693.     }
  694. }
  695.  
  696. START_TEST(test_return_ns_triplet)
  697. {
  698.     char *text =
  699.         "<foo:e xmlns:foo='http://expat.sf.net/' bar:a='12'\n"
  700.         "       xmlns:bar='http://expat.sf.net/'></foo:e>";
  701.     char *elemstr[] = {
  702.         "http://expat.sf.net/ e foo",
  703.         "http://expat.sf.net/ a bar"
  704.     };
  705.     XML_SetReturnNSTriplet(parser, 1);
  706.     XML_SetUserData(parser, elemstr);
  707.     XML_SetElementHandler(parser, triplet_start_checker, triplet_end_checker);
  708.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  709.         xml_failure(parser);
  710. }
  711. END_TEST
  712.  
  713. static void
  714. overwrite_start_checker(void *userData, const XML_Char *name,
  715.                         const XML_Char **atts)
  716. {
  717.     CharData *storage = (CharData *) userData;
  718.     CharData_AppendString(storage, "start ");
  719.     CharData_AppendXMLChars(storage, name, -1);
  720.     while (*atts != NULL) {
  721.         CharData_AppendString(storage, "\nattribute ");
  722.         CharData_AppendXMLChars(storage, *atts, -1);
  723.         atts += 2;
  724.     }
  725.     CharData_AppendString(storage, "\n");
  726. }
  727.  
  728. static void
  729. overwrite_end_checker(void *userData, const XML_Char *name)
  730. {
  731.     CharData *storage = (CharData *) userData;
  732.     CharData_AppendString(storage, "end ");
  733.     CharData_AppendXMLChars(storage, name, -1);
  734.     CharData_AppendString(storage, "\n");
  735. }
  736.  
  737. static void
  738. run_ns_tagname_overwrite_test(char *text, char *result)
  739. {
  740.     CharData storage;
  741.     CharData_Init(&storage);
  742.     XML_SetUserData(parser, &storage);
  743.     XML_SetElementHandler(parser,
  744.                           overwrite_start_checker, overwrite_end_checker);
  745.     if (XML_Parse(parser, text, strlen(text), 1) == XML_STATUS_ERROR)
  746.         xml_failure(parser);
  747.     CharData_CheckString(&storage, result);
  748. }
  749.  
  750. /* Regression test for SF bug #566334. */
  751. START_TEST(test_ns_tagname_overwrite)
  752. {
  753.     char *text =
  754.         "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
  755.         "  <n:f n:attr='foo'/>\n"
  756.         "  <n:g n:attr2='bar'/>\n"
  757.         "</n:e>";
  758.     char *result =
  759.         "start http://xml.libexpat.org/ e\n"
  760.         "start http://xml.libexpat.org/ f\n"
  761.         "attribute http://xml.libexpat.org/ attr\n"
  762.         "end http://xml.libexpat.org/ f\n"
  763.         "start http://xml.libexpat.org/ g\n"
  764.         "attribute http://xml.libexpat.org/ attr2\n"
  765.         "end http://xml.libexpat.org/ g\n"
  766.         "end http://xml.libexpat.org/ e\n";
  767.     run_ns_tagname_overwrite_test(text, result);
  768. }
  769. END_TEST
  770.  
  771. /* Regression test for SF bug #566334. */
  772. START_TEST(test_ns_tagname_overwrite_triplet)
  773. {
  774.     char *text =
  775.         "<n:e xmlns:n='http://xml.libexpat.org/'>\n"
  776.         "  <n:f n:attr='foo'/>\n"
  777.         "  <n:g n:attr2='bar'/>\n"
  778.         "</n:e>";
  779.     char *result =
  780.         "start http://xml.libexpat.org/ e n\n"
  781.         "start http://xml.libexpat.org/ f n\n"
  782.         "attribute http://xml.libexpat.org/ attr n\n"
  783.         "end http://xml.libexpat.org/ f n\n"
  784.         "start http://xml.libexpat.org/ g n\n"
  785.         "attribute http://xml.libexpat.org/ attr2 n\n"
  786.         "end http://xml.libexpat.org/ g n\n"
  787.         "end http://xml.libexpat.org/ e n\n";
  788.     XML_SetReturnNSTriplet(parser, 1);
  789.     run_ns_tagname_overwrite_test(text, result);
  790. }
  791. END_TEST
  792.  
  793. static Suite *
  794. make_basic_suite(void)
  795. {
  796.     Suite *s = suite_create("basic");
  797.     TCase *tc_basic = tcase_create("basic tests");
  798.     TCase *tc_namespace = tcase_create("XML namespaces");
  799.  
  800.     suite_add_tcase(s, tc_basic);
  801.     tcase_add_checked_fixture(tc_basic, basic_setup, basic_teardown);
  802.     tcase_add_test(tc_basic, test_nul_byte);
  803.     tcase_add_test(tc_basic, test_u0000_char);
  804.     tcase_add_test(tc_basic, test_bom_utf8);
  805.     tcase_add_test(tc_basic, test_bom_utf16_be);
  806.     tcase_add_test(tc_basic, test_bom_utf16_le);
  807.     tcase_add_test(tc_basic, test_illegal_utf8);
  808.     tcase_add_test(tc_basic, test_utf16);
  809.     tcase_add_test(tc_basic, test_utf16_le_epilog_newline);
  810.     tcase_add_test(tc_basic, test_latin1_umlauts);
  811.     /* Regression test for SF bug #491986. */
  812.     tcase_add_test(tc_basic, test_danish_latin1);
  813.     /* Regression test for SF bug #514281. */
  814.     tcase_add_test(tc_basic, test_french_charref_hexidecimal);
  815.     tcase_add_test(tc_basic, test_french_charref_decimal);
  816.     tcase_add_test(tc_basic, test_french_latin1);
  817.     tcase_add_test(tc_basic, test_french_utf8);
  818.     tcase_add_test(tc_basic, test_utf8_false_rejection);
  819.     tcase_add_test(tc_basic, test_line_count);
  820.     tcase_add_test(tc_basic, test_really_long_lines);
  821.     tcase_add_test(tc_basic, test_end_element_events);
  822.     tcase_add_test(tc_basic, test_attr_whitespace_normalization);
  823.     tcase_add_test(tc_basic, test_xmldecl_misplaced);
  824.     tcase_add_test(tc_basic, test_unknown_encoding_internal_entity);
  825.     tcase_add_test(tc_basic,
  826.                    test_wfc_undeclared_entity_unread_external_subset);
  827.     tcase_add_test(tc_basic, test_wfc_undeclared_entity_no_external_subset);
  828.     tcase_add_test(tc_basic, test_wfc_undeclared_entity_standalone);
  829.     tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
  830.     tcase_add_test(tc_basic, test_wfc_no_recursive_entity_refs);
  831.  
  832.     suite_add_tcase(s, tc_namespace);
  833.     tcase_add_checked_fixture(tc_namespace,
  834.                               namespace_setup, namespace_teardown);
  835.     tcase_add_test(tc_namespace, test_return_ns_triplet);
  836.     tcase_add_test(tc_namespace, test_ns_tagname_overwrite);
  837.     tcase_add_test(tc_namespace, test_ns_tagname_overwrite_triplet);
  838.  
  839.     return s;
  840. }
  841.  
  842.  
  843. int
  844. main(int argc, char *argv[])
  845. {
  846.     int i, nf;
  847.     int forking = 0, forking_set = 0;
  848.     int verbosity = CK_NORMAL;
  849.     Suite *s = make_basic_suite();
  850.     SRunner *sr = srunner_create(s);
  851.  
  852.     /* run the tests for internal helper functions */
  853.     testhelper_is_whitespace_normalized();
  854.  
  855.     for (i = 1; i < argc; ++i) {
  856.         char *opt = argv[i];
  857.         if (strcmp(opt, "-v") == 0 || strcmp(opt, "--verbose") == 0)
  858.             verbosity = CK_VERBOSE;
  859.         else if (strcmp(opt, "-q") == 0 || strcmp(opt, "--quiet") == 0)
  860.             verbosity = CK_SILENT;
  861.         else if (strcmp(opt, "-f") == 0 || strcmp(opt, "--fork") == 0) {
  862.             forking = 1;
  863.             forking_set = 1;
  864.         }
  865.         else if (strcmp(opt, "-n") == 0 || strcmp(opt, "--no-fork") == 0) {
  866.             forking = 0;
  867.             forking_set = 1;
  868.         }
  869.         else {
  870.             fprintf(stderr, "runtests: unknown option '%s'\n", opt);
  871.             return 2;
  872.         }
  873.     }
  874.     if (forking_set)
  875.         srunner_set_fork_status(sr, forking ? CK_FORK : CK_NOFORK);
  876.     srunner_run_all(sr, verbosity);
  877.     nf = srunner_ntests_failed(sr);
  878.     srunner_free(sr);
  879.     suite_free(s);
  880.  
  881.     return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  882. }
  883.