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
15 #include <expat.h>
16 #include <string.h>
17 #include "unity.h"
18
19 typedef struct {
20 int depth;
21 char output[512];
22 int output_off;
23 } user_data_t;
24
insert_space(user_data_t * user_data)25 static void insert_space(user_data_t *user_data)
26 {
27 const char align_str[] = " ";
28
29 TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);
30 user_data->output[user_data->output_off++] = '\n';
31
32 for (int i = 0; i < user_data->depth; i++) {
33 for (int j = 0; j < strlen(align_str); ++j) {
34 TEST_ASSERT(sizeof(user_data->output) >= user_data->output_off);
35 user_data->output[user_data->output_off++] = align_str[j];
36 }
37 }
38 }
39
start_element(void * userData,const XML_Char * name,const XML_Char ** atts)40 static void XMLCALL start_element(void *userData, const XML_Char *name, const XML_Char **atts)
41 {
42 user_data_t *user_data = (user_data_t *) userData;
43
44 insert_space(user_data);
45
46 const int ret = snprintf(user_data->output + user_data->output_off,
47 sizeof(user_data->output) - user_data->output_off,
48 "<%s>", name);
49 TEST_ASSERT_EQUAL(strlen(name) + 2, ret); // 2 are the tag characters: "<>"
50 user_data->output_off += ret;
51 ++user_data->depth;
52 }
53
end_element(void * userData,const XML_Char * name)54 static void XMLCALL end_element(void *userData, const XML_Char *name)
55 {
56 user_data_t *user_data = (user_data_t *) userData;
57
58 --user_data->depth;
59 insert_space(user_data);
60
61 int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,
62 "</%s>", name);
63 TEST_ASSERT_EQUAL(strlen(name) + 3, ret); // 3 are the tag characters: "</>"
64 user_data->output_off += ret;
65 }
66
data_handler(void * userData,const XML_Char * s,int len)67 static void data_handler(void *userData, const XML_Char *s, int len)
68 {
69 user_data_t *user_data = (user_data_t *) userData;
70
71 insert_space(user_data);
72
73 // s is not zero-terminated
74 char tmp_str[len+1];
75 strlcpy(tmp_str, s, len+1);
76
77 int ret = snprintf(user_data->output + user_data->output_off, sizeof(user_data->output) - user_data->output_off,
78 "%s", tmp_str);
79 TEST_ASSERT_EQUAL(strlen(tmp_str), ret);
80 user_data->output_off += ret;
81 }
82
83 TEST_CASE("Expat parses XML", "[expat]")
84 {
85 const char test_in[] = "<html><title>Page title</title><body><h>header</h><ol><li>A</li>"\
86 "<li>B</li><li>C</li></ol></body></html>";
87 const char test_expected[] = "\n"\
88 "<html>\n"\
89 " <title>\n"\
90 " Page title\n"\
91 " </title>\n"\
92 " <body>\n"\
93 " <h>\n"\
94 " header\n"\
95 " </h>\n"\
96 " <ol>\n"\
97 " <li>\n"\
98 " A\n"\
99 " </li>\n"\
100 " <li>\n"\
101 " B\n"\
102 " </li>\n"\
103 " <li>\n"\
104 " C\n"\
105 " </li>\n"\
106 " </ol>\n"\
107 " </body>\n"\
108 "</html>";
109 user_data_t user_data = {
110 .depth = 0,
111 .output = { '\0' },
112 .output_off = 0
113 };
114
115 XML_Parser parser = XML_ParserCreate(NULL);
116 XML_SetUserData(parser, &user_data);
117 XML_SetElementHandler(parser, start_element, end_element);
118 XML_SetCharacterDataHandler(parser, data_handler);
119
120 TEST_ASSERT_NOT_EQUAL(XML_STATUS_ERROR, XML_Parse(parser, test_in, strlen(test_in), 1));
121 XML_ParserFree(parser);
122
123 TEST_ASSERT_EQUAL(0, user_data.depth); // all closing tags have been found
124
125 TEST_ASSERT_EQUAL(strlen(test_expected), strlen(user_data.output));
126 TEST_ASSERT_EQUAL_STRING(test_expected, user_data.output);
127 }
128