xref: /freebsd/contrib/expat/tests/common.c (revision abd872540f24cfc7dbd1ea29b6918c7082a22108)
1 /* Commonly used functions for the Expat test suite
2                             __  __            _
3                          ___\ \/ /_ __   __ _| |_
4                         / _ \\  /| '_ \ / _` | __|
5                        |  __//  \| |_) | (_| | |_
6                         \___/_/\_\ .__/ \__,_|\__|
7                                  |_| XML parser
8 
9    Copyright (c) 2001-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
10    Copyright (c) 2003      Greg Stein <gstein@users.sourceforge.net>
11    Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
12    Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
13    Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
14    Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
15    Copyright (c) 2017      Joe Orton <jorton@redhat.com>
16    Copyright (c) 2017      José Gutiérrez de la Concha <jose@zeroc.com>
17    Copyright (c) 2018      Marco Maggi <marco.maggi-ipsu@poste.it>
18    Copyright (c) 2019      David Loffredo <loffredo@steptools.com>
19    Copyright (c) 2020      Tim Gates <tim.gates@iress.com>
20    Copyright (c) 2021      Donghee Na <donghee.na@python.org>
21    Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
22    Licensed under the MIT license:
23 
24    Permission is  hereby granted,  free of charge,  to any  person obtaining
25    a  copy  of  this  software   and  associated  documentation  files  (the
26    "Software"),  to  deal in  the  Software  without restriction,  including
27    without  limitation the  rights  to use,  copy,  modify, merge,  publish,
28    distribute, sublicense, and/or sell copies of the Software, and to permit
29    persons  to whom  the Software  is  furnished to  do so,  subject to  the
30    following conditions:
31 
32    The above copyright  notice and this permission notice  shall be included
33    in all copies or substantial portions of the Software.
34 
35    THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY  OF  ANY  KIND,
36    EXPRESS  OR IMPLIED,  INCLUDING  BUT  NOT LIMITED  TO  THE WARRANTIES  OF
37    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
38    NO EVENT SHALL THE AUTHORS OR  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
39    DAMAGES OR  OTHER LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT,  TORT OR
40    OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
41    USE OR OTHER DEALINGS IN THE SOFTWARE.
42 */
43 
44 #include <assert.h>
45 #include <stdio.h>
46 #include <string.h>
47 
48 #include "expat_config.h"
49 #include "expat.h"
50 #include "internal.h"
51 #include "chardata.h"
52 #include "minicheck.h"
53 #include "common.h"
54 
55 /* Common test data */
56 
57 const char *long_character_data_text
58     = "<?xml version='1.0' encoding='iso-8859-1'?><s>"
59       "012345678901234567890123456789012345678901234567890123456789"
60       "012345678901234567890123456789012345678901234567890123456789"
61       "012345678901234567890123456789012345678901234567890123456789"
62       "012345678901234567890123456789012345678901234567890123456789"
63       "012345678901234567890123456789012345678901234567890123456789"
64       "012345678901234567890123456789012345678901234567890123456789"
65       "012345678901234567890123456789012345678901234567890123456789"
66       "012345678901234567890123456789012345678901234567890123456789"
67       "012345678901234567890123456789012345678901234567890123456789"
68       "012345678901234567890123456789012345678901234567890123456789"
69       "012345678901234567890123456789012345678901234567890123456789"
70       "012345678901234567890123456789012345678901234567890123456789"
71       "012345678901234567890123456789012345678901234567890123456789"
72       "012345678901234567890123456789012345678901234567890123456789"
73       "012345678901234567890123456789012345678901234567890123456789"
74       "012345678901234567890123456789012345678901234567890123456789"
75       "012345678901234567890123456789012345678901234567890123456789"
76       "012345678901234567890123456789012345678901234567890123456789"
77       "012345678901234567890123456789012345678901234567890123456789"
78       "012345678901234567890123456789012345678901234567890123456789"
79       "</s>";
80 
81 const char *long_cdata_text
82     = "<s><![CDATA["
83       "012345678901234567890123456789012345678901234567890123456789"
84       "012345678901234567890123456789012345678901234567890123456789"
85       "012345678901234567890123456789012345678901234567890123456789"
86       "012345678901234567890123456789012345678901234567890123456789"
87       "012345678901234567890123456789012345678901234567890123456789"
88       "012345678901234567890123456789012345678901234567890123456789"
89       "012345678901234567890123456789012345678901234567890123456789"
90       "012345678901234567890123456789012345678901234567890123456789"
91       "012345678901234567890123456789012345678901234567890123456789"
92       "012345678901234567890123456789012345678901234567890123456789"
93       "012345678901234567890123456789012345678901234567890123456789"
94       "012345678901234567890123456789012345678901234567890123456789"
95       "012345678901234567890123456789012345678901234567890123456789"
96       "012345678901234567890123456789012345678901234567890123456789"
97       "012345678901234567890123456789012345678901234567890123456789"
98       "012345678901234567890123456789012345678901234567890123456789"
99       "012345678901234567890123456789012345678901234567890123456789"
100       "012345678901234567890123456789012345678901234567890123456789"
101       "012345678901234567890123456789012345678901234567890123456789"
102       "012345678901234567890123456789012345678901234567890123456789"
103       "]]></s>";
104 
105 /* Having an element name longer than 1024 characters exercises some
106  * of the pool allocation code in the parser that otherwise does not
107  * get executed.  The count at the end of the line is the number of
108  * characters (bytes) in the element name by that point.x
109  */
110 const char *get_buffer_test_text
111     = "<documentwitharidiculouslylongelementnametotease"  /* 0x030 */
112       "aparticularcorneroftheallocationinXML_GetBuffers"  /* 0x060 */
113       "othatwecanimprovethecoverageyetagain012345678901"  /* 0x090 */
114       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x0c0 */
115       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x0f0 */
116       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x120 */
117       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x150 */
118       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x180 */
119       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x1b0 */
120       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x1e0 */
121       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x210 */
122       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x240 */
123       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x270 */
124       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x2a0 */
125       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x2d0 */
126       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x300 */
127       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x330 */
128       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x360 */
129       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x390 */
130       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x3c0 */
131       "123456789abcdef0123456789abcdef0123456789abcdef0"  /* 0x3f0 */
132       "123456789abcdef0123456789abcdef0123456789>\n<ef0"; /* 0x420 */
133 
134 /* Test control globals */
135 
136 /* Used as the "resumable" parameter to XML_StopParser by some tests */
137 XML_Bool g_resumable = XML_FALSE;
138 
139 /* Used to control abort checks in some tests */
140 XML_Bool g_abortable = XML_FALSE;
141 
142 /* Used to control _XML_Parse_SINGLE_BYTES() chunk size */
143 int g_chunkSize = 1;
144 
145 /* Common test functions */
146 
147 void
148 tcase_add_test__ifdef_xml_dtd(TCase *tc, tcase_test_function test) {
149 #ifdef XML_DTD
150   tcase_add_test(tc, test);
151 #else
152   UNUSED_P(tc);
153   UNUSED_P(test);
154 #endif
155 }
156 
157 void
158 tcase_add_test__if_xml_ge(TCase *tc, tcase_test_function test) {
159 #if XML_GE == 1
160   tcase_add_test(tc, test);
161 #else
162   UNUSED_P(tc);
163   UNUSED_P(test);
164 #endif
165 }
166 
167 void
168 basic_teardown(void) {
169   if (g_parser != NULL) {
170     XML_ParserFree(g_parser);
171     g_parser = NULL;
172   }
173 }
174 
175 /* Generate a failure using the parser state to create an error message;
176    this should be used when the parser reports an error we weren't
177    expecting.
178 */
179 void
180 _xml_failure(XML_Parser parser, const char *file, int line) {
181   char buffer[1024];
182   enum XML_Error err = XML_GetErrorCode(parser);
183   snprintf(buffer, sizeof(buffer),
184            "    %d: %" XML_FMT_STR " (line %" XML_FMT_INT_MOD
185            "u, offset %" XML_FMT_INT_MOD "u)\n    reported from %s, line %d\n",
186            err, XML_ErrorString(err), XML_GetCurrentLineNumber(parser),
187            XML_GetCurrentColumnNumber(parser), file, line);
188   _fail(file, line, buffer);
189 }
190 
191 enum XML_Status
192 _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
193                         int isFinal) {
194   // This ensures that tests have to run pathological parse cases
195   // (e.g. when `s` is NULL) against plain XML_Parse rather than
196   // chunking _XML_Parse_SINGLE_BYTES.
197   assert((parser != NULL) && (s != NULL) && (len >= 0));
198   const int chunksize = g_chunkSize;
199   if (chunksize > 0) {
200     // parse in chunks of `chunksize` bytes as long as not exhausting
201     for (; len > chunksize; len -= chunksize, s += chunksize) {
202       enum XML_Status res = XML_Parse(parser, s, chunksize, XML_FALSE);
203       if (res != XML_STATUS_OK) {
204         return res;
205       }
206     }
207   }
208   // parse the final chunk, the size of which will be <= chunksize
209   return XML_Parse(parser, s, len, isFinal);
210 }
211 
212 void
213 _expect_failure(const char *text, enum XML_Error errorCode,
214                 const char *errorMessage, const char *file, int lineno) {
215   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
216       == XML_STATUS_OK)
217     /* Hackish use of _fail() macro, but lets us report
218        the right filename and line number. */
219     _fail(file, lineno, errorMessage);
220   if (XML_GetErrorCode(g_parser) != errorCode)
221     _xml_failure(g_parser, file, lineno);
222 }
223 
224 /* Character data support for handlers, built on top of the code in
225  * chardata.c
226  */
227 void XMLCALL
228 accumulate_characters(void *userData, const XML_Char *s, int len) {
229   CharData_AppendXMLChars((CharData *)userData, s, len);
230 }
231 
232 void XMLCALL
233 accumulate_attribute(void *userData, const XML_Char *name,
234                      const XML_Char **atts) {
235   CharData *storage = (CharData *)userData;
236   UNUSED_P(name);
237   /* Check there are attributes to deal with */
238   if (atts == NULL)
239     return;
240 
241   while (storage->count < 0 && atts[0] != NULL) {
242     /* "accumulate" the value of the first attribute we see */
243     CharData_AppendXMLChars(storage, atts[1], -1);
244     atts += 2;
245   }
246 }
247 
248 void
249 _run_character_check(const char *text, const XML_Char *expected,
250                      const char *file, int line) {
251   CharData storage;
252 
253   CharData_Init(&storage);
254   XML_SetUserData(g_parser, &storage);
255   XML_SetCharacterDataHandler(g_parser, accumulate_characters);
256   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
257       == XML_STATUS_ERROR)
258     _xml_failure(g_parser, file, line);
259   CharData_CheckXMLChars(&storage, expected);
260 }
261 
262 void
263 _run_attribute_check(const char *text, const XML_Char *expected,
264                      const char *file, int line) {
265   CharData storage;
266 
267   CharData_Init(&storage);
268   XML_SetUserData(g_parser, &storage);
269   XML_SetStartElementHandler(g_parser, accumulate_attribute);
270   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
271       == XML_STATUS_ERROR)
272     _xml_failure(g_parser, file, line);
273   CharData_CheckXMLChars(&storage, expected);
274 }
275 
276 void XMLCALL
277 ext_accumulate_characters(void *userData, const XML_Char *s, int len) {
278   ExtTest *test_data = (ExtTest *)userData;
279   accumulate_characters(test_data->storage, s, len);
280 }
281 
282 void
283 _run_ext_character_check(const char *text, ExtTest *test_data,
284                          const XML_Char *expected, const char *file, int line) {
285   CharData *const storage = (CharData *)malloc(sizeof(CharData));
286 
287   CharData_Init(storage);
288   test_data->storage = storage;
289   XML_SetUserData(g_parser, test_data);
290   XML_SetCharacterDataHandler(g_parser, ext_accumulate_characters);
291   if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
292       == XML_STATUS_ERROR)
293     _xml_failure(g_parser, file, line);
294   CharData_CheckXMLChars(storage, expected);
295 
296   free(storage);
297 }
298 
299 /* Control variable; the number of times duff_allocator() will successfully
300  * allocate */
301 #define ALLOC_ALWAYS_SUCCEED (-1)
302 #define REALLOC_ALWAYS_SUCCEED (-1)
303 
304 int g_allocation_count = ALLOC_ALWAYS_SUCCEED;
305 int g_reallocation_count = REALLOC_ALWAYS_SUCCEED;
306 
307 /* Crocked allocator for allocation failure tests */
308 void *
309 duff_allocator(size_t size) {
310   if (g_allocation_count == 0)
311     return NULL;
312   if (g_allocation_count != ALLOC_ALWAYS_SUCCEED)
313     g_allocation_count--;
314   return malloc(size);
315 }
316 
317 /* Crocked reallocator for allocation failure tests */
318 void *
319 duff_reallocator(void *ptr, size_t size) {
320   if (g_reallocation_count == 0)
321     return NULL;
322   if (g_reallocation_count != REALLOC_ALWAYS_SUCCEED)
323     g_reallocation_count--;
324   return realloc(ptr, size);
325 }
326