test_expat.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <expat.h>
  15. #include <string.h>
  16. #include "unity.h"
  17. typedef struct {
  18. int depth;
  19. char output[512];
  20. int output_off;
  21. } user_data_t;
  22. static void insert_space(user_data_t *user_data)
  23. {
  24. const char align_str[] = " ";
  25. TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);
  26. user_data->output[user_data->output_off++] = '\n';
  27. for (int i = 0; i < user_data->depth; i++) {
  28. for (int j = 0; j < strlen(align_str); ++j) {
  29. TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);
  30. user_data->output[user_data->output_off++] = align_str[j];
  31. }
  32. }
  33. }
  34. static void XMLCALL start_element(void *userData, const XML_Char *name, const XML_Char **atts)
  35. {
  36. user_data_t *user_data = (user_data_t *) userData;
  37. insert_space(user_data);
  38. const int ret = snprintf(user_data->output + user_data->output_off,
  39. sizeof(user_data->output) - user_data->output_off,
  40. "<%s>", name);
  41. TEST_ASSERT_EQUAL(strlen(name) + 2, ret); // 2 are the tag characters: "<>"
  42. user_data->output_off += ret;
  43. ++user_data->depth;
  44. }
  45. static void XMLCALL end_element(void *userData, const XML_Char *name)
  46. {
  47. user_data_t *user_data = (user_data_t *) userData;
  48. --user_data->depth;
  49. insert_space(user_data);
  50. int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,
  51. "</%s>", name);
  52. TEST_ASSERT_EQUAL(strlen(name) + 3, ret); // 3 are the tag characters: "</>"
  53. user_data->output_off += ret;
  54. }
  55. static void data_handler(void *userData, const XML_Char *s, int len)
  56. {
  57. user_data_t *user_data = (user_data_t *) userData;
  58. insert_space(user_data);
  59. // s is not zero-terminated
  60. char tmp_str[len+1];
  61. strlcpy(tmp_str, s, len+1);
  62. int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,
  63. "%s", tmp_str);
  64. TEST_ASSERT_EQUAL(strlen(tmp_str), ret);
  65. user_data->output_off += ret;
  66. }
  67. TEST_CASE("Expat parses XML", "[expat]")
  68. {
  69. const char test_in[] = "<html><title>Page title</title><body><h>header</h><ol><li>A</li>"\
  70. "<li>B</li><li>C</li></ol></body></html>";
  71. const char test_expected[] = "\n"\
  72. "<html>\n"\
  73. " <title>\n"\
  74. " Page title\n"\
  75. " </title>\n"\
  76. " <body>\n"\
  77. " <h>\n"\
  78. " header\n"\
  79. " </h>\n"\
  80. " <ol>\n"\
  81. " <li>\n"\
  82. " A\n"\
  83. " </li>\n"\
  84. " <li>\n"\
  85. " B\n"\
  86. " </li>\n"\
  87. " <li>\n"\
  88. " C\n"\
  89. " </li>\n"\
  90. " </ol>\n"\
  91. " </body>\n"\
  92. "</html>";
  93. user_data_t user_data = {
  94. .depth = 0,
  95. .output = { '\0' },
  96. .output_off = 0
  97. };
  98. XML_Parser parser = XML_ParserCreate(NULL);
  99. XML_SetUserData(parser, &user_data);
  100. XML_SetElementHandler(parser, start_element, end_element);
  101. XML_SetCharacterDataHandler(parser, data_handler);
  102. TEST_ASSERT_NOT_EQUAL(XML_STATUS_ERROR, XML_Parse(parser, test_in, strlen(test_in), 1));
  103. XML_ParserFree(parser);
  104. TEST_ASSERT_EQUAL(0, user_data.depth); // all closing tags have been found
  105. TEST_ASSERT_EQUAL(strlen(test_expected), strlen(user_data.output));
  106. TEST_ASSERT_EQUAL_STRING(test_expected, user_data.output);
  107. }