Merge branch 'g-clear-pointer-no-side-effects' into 'master'
[glib.git] / glib / tests / markup-subparser.c
blobd1ceffb007c4ad9f47ffd1bc690dc853ed682678
1 /*
2 * Copyright © 2008 Ryan Lortie
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * See the included COPYING file for more information.
12 #include <string.h>
13 #include <stdio.h>
14 #include <glib.h>
16 /* keep track of GString instances to make sure nothing leaks */
17 static int strings_allocated;
19 /* === the GMarkupParser functions === */
20 static void
21 subparser_start_element (GMarkupParseContext *context,
22 const gchar *element_name,
23 const gchar **attribute_names,
24 const gchar **attribute_values,
25 gpointer user_data,
26 GError **error)
28 g_string_append_printf (user_data, "{%s}", element_name);
30 /* we don't like trouble... */
31 if (strcmp (element_name, "trouble") == 0)
32 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
33 "we don't like trouble");
36 static void
37 subparser_end_element (GMarkupParseContext *context,
38 const gchar *element_name,
39 gpointer user_data,
40 GError **error)
42 g_string_append_printf (user_data, "{/%s}", element_name);
45 static void
46 subparser_error (GMarkupParseContext *context,
47 GError *error,
48 gpointer user_data)
50 g_string_free (user_data, TRUE);
51 strings_allocated--;
54 static GMarkupParser subparser_parser =
56 subparser_start_element,
57 subparser_end_element,
58 NULL,
59 NULL,
60 subparser_error
63 /* convenience functions for a parser that does not
64 * replay the starting tag into the subparser...
66 static void
67 subparser_start (GMarkupParseContext *ctx)
69 gpointer user_data;
71 user_data = g_string_new (NULL);
72 strings_allocated++;
73 g_markup_parse_context_push (ctx, &subparser_parser, user_data);
76 static char *
77 subparser_end (GMarkupParseContext *ctx,
78 GError **error)
80 GString *string;
81 char *result;
83 string = g_markup_parse_context_pop (ctx);
84 result = string->str;
86 g_string_free (string, FALSE);
87 strings_allocated--;
89 if (result == NULL || result[0] == '\0')
91 g_free (result);
92 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
93 "got no data");
95 return NULL;
98 return result;
101 /* convenience functions for a parser that -does-
102 * replay the starting tag into the subparser...
104 static gboolean
105 replay_parser_start (GMarkupParseContext *ctx,
106 const char *element_name,
107 const char **attribute_names,
108 const char **attribute_values,
109 GError **error)
111 GError *tmp_error = NULL;
112 gpointer user_data;
114 user_data = g_string_new (NULL);
115 strings_allocated++;
117 subparser_parser.start_element (ctx, element_name,
118 attribute_names, attribute_values,
119 user_data, &tmp_error);
121 if (tmp_error)
123 g_propagate_error (error, tmp_error);
124 g_string_free (user_data, TRUE);
125 strings_allocated--;
127 return FALSE;
130 g_markup_parse_context_push (ctx, &subparser_parser, user_data);
132 return TRUE;
135 static char *
136 replay_parser_end (GMarkupParseContext *ctx,
137 GError **error)
139 GError *tmp_error = NULL;
140 GString *string;
141 char *result;
143 string = g_markup_parse_context_pop (ctx);
145 subparser_parser.end_element (ctx, g_markup_parse_context_get_element (ctx),
146 string, &tmp_error);
148 if (tmp_error)
150 g_propagate_error (error, tmp_error);
151 g_string_free (string, TRUE);
152 strings_allocated--;
154 return NULL;
157 result = string->str;
159 g_string_free (string, FALSE);
160 strings_allocated--;
162 if (result == NULL || result[0] == '\0')
164 g_free (result);
165 g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
166 "got no data");
168 return NULL;
171 return result;
175 /* === start interface between subparser and calling parser === */
176 static void subparser_start (GMarkupParseContext *ctx);
177 static char *subparser_end (GMarkupParseContext *ctx,
178 GError **error);
179 /* === end interface between subparser and calling parser === */
181 /* === start interface between replay parser and calling parser === */
182 static gboolean replay_parser_start (GMarkupParseContext *ctx,
183 const char *element_name,
184 const char **attribute_names,
185 const char **attribute_values,
186 GError **error);
187 static char *replay_parser_end (GMarkupParseContext *ctx,
188 GError **error);
189 /* === end interface between replay parser and calling parser === */
193 /* now comes our parser for the test.
195 * we recognise the tags <test> and <sub>.
196 * <test> is ignored.
197 * <sub> invokes the subparser (no replay).
199 * "unknown tags" are passed to the reply subparser
200 * (so the unknown tag is fed to the subparser...)
202 static void
203 start_element (GMarkupParseContext *context,
204 const gchar *element_name,
205 const gchar **attribute_names,
206 const gchar **attribute_values,
207 gpointer user_data,
208 GError **error)
210 g_string_append_printf (user_data, "<%s>", element_name);
212 if (strcmp (element_name, "test") == 0)
214 /* do nothing */
216 else if (strcmp (element_name, "sub") == 0)
218 /* invoke subparser */
219 subparser_start (context);
221 else
223 /* unknown tag. invoke replay subparser */
224 if (!replay_parser_start (context, element_name,
225 attribute_names, attribute_values,
226 error))
227 return;
231 static void
232 end_element (GMarkupParseContext *context,
233 const gchar *element_name,
234 gpointer user_data,
235 GError **error)
237 if (strcmp (element_name, "test") == 0)
239 /* do nothing */
241 else if (strcmp (element_name, "sub") == 0)
243 char *result;
245 if ((result = subparser_end (context, error)) == NULL)
246 return;
248 g_string_append_printf (user_data, "<<%s>>", result);
249 g_free (result);
251 else
253 char *result;
255 if ((result = replay_parser_end (context, error)) == NULL)
256 return;
258 g_string_append_printf (user_data, "[[%s]]", result);
259 g_free (result);
262 g_string_append_printf (user_data, "</%s>", element_name);
265 static GMarkupParser parser =
267 start_element,
268 end_element
271 typedef struct
273 const char *markup;
274 const char *result;
275 const char *error_message;
276 } TestCase;
278 static void
279 test (gconstpointer user_data)
281 const TestCase *tc = user_data;
282 GMarkupParseContext *ctx;
283 GString *string;
284 gboolean result;
285 GError *error;
287 error = NULL;
288 string = g_string_new (NULL);
289 ctx = g_markup_parse_context_new (&parser, 0, string, NULL);
290 result = g_markup_parse_context_parse (ctx, tc->markup,
291 strlen (tc->markup), &error);
292 if (result)
293 result = g_markup_parse_context_end_parse (ctx, &error);
294 g_markup_parse_context_free (ctx);
295 g_assert (strings_allocated == 0);
297 if (result)
299 if (tc->error_message)
300 g_error ("expected failure (about '%s') passed!\n"
301 " in: %s\n out: %s",
302 tc->error_message, tc->markup, string->str);
304 else
306 if (!tc->error_message)
307 g_error ("unexpected failure: '%s'\n"
308 " in: %s\n out: %s",
309 error->message, tc->markup, string->str);
311 if (!strstr (error->message, tc->error_message))
312 g_error ("failed for the wrong reason.\n"
313 " expecting message about '%s'\n"
314 " got message '%s'\n"
315 " in: %s\n out: %s",
316 tc->error_message, error->message, tc->markup, string->str);
319 if (strcmp (string->str, tc->result) != 0)
320 g_error ("got the wrong result.\n"
321 " expected: '%s'\n"
322 " got: '%s'\n"
323 " input: %s",
324 tc->result, string->str, tc->markup);
326 if (error)
327 g_error_free (error);
329 g_string_free (string, TRUE);
332 TestCase test_cases[] = /* successful runs */
334 /* in */ /* out */
335 { "<test/>", "<test></test>" },
336 { "<sub><foo/></sub>", "<sub><<{foo}{/foo}>></sub>" },
337 { "<sub><foo/><bar/></sub>", "<sub><<{foo}{/foo}{bar}{/bar}>></sub>" },
338 { "<foo><bar/></foo>", "<foo>[[{foo}{bar}{/bar}{/foo}]]</foo>" },
339 { "<foo><x/><y/></foo>", "<foo>[[{foo}{x}{/x}{y}{/y}{/foo}]]</foo>" },
340 { "<foo/>", "<foo>[[{foo}{/foo}]]</foo>" },
341 { "<sub><foo/></sub><bar/>", "<sub><<{foo}{/foo}>></sub>"
342 "<bar>[[{bar}{/bar}]]</bar>" }
345 TestCase error_cases[] = /* error cases */
347 /* in */ /* out */ /* error */
348 { "<foo><>", "<foo>", ">"},
349 { "", "", "empty" },
350 { "<trouble/>", "<trouble>", "trouble" },
351 { "<sub><trouble>", "<sub>", "trouble" },
352 { "<foo><trouble>", "<foo>", "trouble" },
353 { "<sub></sub>", "<sub>", "no data" },
354 { "<sub/>", "<sub>", "no data" }
357 #define add_tests(func, basename, array) \
358 G_STMT_START { \
359 int __add_tests_i; \
361 for (__add_tests_i = 0; \
362 __add_tests_i < G_N_ELEMENTS (array); \
363 __add_tests_i++) \
365 char *testname; \
367 testname = g_strdup_printf ("%s/%d", basename, __add_tests_i); \
368 g_test_add_data_func (testname, &array[__add_tests_i], func); \
369 g_free (testname); \
371 } G_STMT_END
374 main (int argc, char **argv)
376 g_setenv ("LC_ALL", "C", TRUE);
377 g_test_init (&argc, &argv, NULL);
378 add_tests (test, "/glib/markup/subparser/success", test_cases);
379 add_tests (test, "/glib/markup/subparser/failure", error_cases);
380 return g_test_run ();