2 * Copyright © 2008 Ryan Lortie
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * See the included COPYING file for more information.
16 /* keep track of GString instances to make sure nothing leaks */
17 static int strings_allocated;
19 /* === the GMarkupParser functions === */
21 subparser_start_element (GMarkupParseContext *context,
22 const gchar *element_name,
23 const gchar **attribute_names,
24 const gchar **attribute_values,
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, 0, 0, "we don't like trouble");
36 subparser_end_element (GMarkupParseContext *context,
37 const gchar *element_name,
41 g_string_append_printf (user_data, "{/%s}", element_name);
45 subparser_error (GMarkupParseContext *context,
49 g_string_free (user_data, TRUE);
53 static GMarkupParser subparser_parser =
55 subparser_start_element,
56 subparser_end_element,
62 /* convenience functions for a parser that does not
63 * replay the starting tag into the subparser...
66 subparser_start (GMarkupParseContext *ctx)
70 user_data = g_string_new (NULL);
72 g_markup_parse_context_push (ctx, &subparser_parser, user_data);
76 subparser_end (GMarkupParseContext *ctx,
82 string = g_markup_parse_context_pop (ctx);
85 g_string_free (string, FALSE);
88 if (result == NULL || result[0] == '\0')
91 g_set_error (error, 0, 0, "got no data");
99 /* convenience functions for a parser that -does-
100 * replay the starting tag into the subparser...
103 replay_parser_start (GMarkupParseContext *ctx,
104 const char *element_name,
105 const char **attribute_names,
106 const char **attribute_values,
109 GError *tmp_error = NULL;
112 user_data = g_string_new (NULL);
115 subparser_parser.start_element (ctx, element_name,
116 attribute_names, attribute_values,
117 user_data, &tmp_error);
121 g_propagate_error (error, tmp_error);
122 g_string_free (user_data, TRUE);
128 g_markup_parse_context_push (ctx, &subparser_parser, user_data);
134 replay_parser_end (GMarkupParseContext *ctx,
137 GError *tmp_error = NULL;
141 string = g_markup_parse_context_pop (ctx);
143 subparser_parser.end_element (ctx, g_markup_parse_context_get_element (ctx),
148 g_propagate_error (error, tmp_error);
149 g_string_free (string, TRUE);
155 result = string->str;
157 g_string_free (string, FALSE);
160 if (result == NULL || result[0] == '\0')
163 g_set_error (error, 0, 0, "got no data");
172 /* === start interface between subparser and calling parser === */
173 static void subparser_start (GMarkupParseContext *ctx);
174 static char *subparser_end (GMarkupParseContext *ctx,
176 /* === end interface between subparser and calling parser === */
178 /* === start interface between replay parser and calling parser === */
179 static gboolean replay_parser_start (GMarkupParseContext *ctx,
180 const char *element_name,
181 const char **attribute_names,
182 const char **attribute_values,
184 static char *replay_parser_end (GMarkupParseContext *ctx,
186 /* === end interface between replay parser and calling parser === */
190 /* now comes our parser for the test.
192 * we recognise the tags <test> and <sub>.
194 * <sub> invokes the subparser (no replay).
196 * "unknown tags" are passed to the reply subparser
197 * (so the unknown tag is fed to the subparser...)
200 start_element (GMarkupParseContext *context,
201 const gchar *element_name,
202 const gchar **attribute_names,
203 const gchar **attribute_values,
207 g_string_append_printf (user_data, "<%s>", element_name);
209 if (strcmp (element_name, "test") == 0)
213 else if (strcmp (element_name, "sub") == 0)
215 /* invoke subparser */
216 subparser_start (context);
220 /* unknown tag. invoke replay subparser */
221 if (!replay_parser_start (context, element_name,
222 attribute_names, attribute_values,
229 end_element (GMarkupParseContext *context,
230 const gchar *element_name,
234 if (strcmp (element_name, "test") == 0)
238 else if (strcmp (element_name, "sub") == 0)
242 if ((result = subparser_end (context, error)) == NULL)
245 g_string_append_printf (user_data, "<<%s>>", result);
252 if ((result = replay_parser_end (context, error)) == NULL)
255 g_string_append_printf (user_data, "[[%s]]", result);
259 g_string_append_printf (user_data, "</%s>", element_name);
262 static GMarkupParser parser =
272 const char *error_message;
276 test (gconstpointer user_data)
278 const TestCase *tc = user_data;
279 GMarkupParseContext *ctx;
285 string = g_string_new (NULL);
286 ctx = g_markup_parse_context_new (&parser, 0, string, NULL);
287 result = g_markup_parse_context_parse (ctx, tc->markup,
288 strlen (tc->markup), &error);
290 result = g_markup_parse_context_end_parse (ctx, &error);
291 g_markup_parse_context_free (ctx);
292 g_assert (strings_allocated == 0);
296 if (tc->error_message)
297 g_error ("expected failure (about '%s') passed!\n"
299 tc->error_message, tc->markup, string->str);
303 if (!tc->error_message)
304 g_error ("unexpected failure: '%s'\n"
306 error->message, tc->markup, string->str);
308 if (!strstr (error->message, tc->error_message))
309 g_error ("failed for the wrong reason.\n"
310 " expecting message about '%s'\n"
311 " got message '%s'\n"
313 tc->error_message, error->message, tc->markup, string->str);
316 if (strcmp (string->str, tc->result) != 0)
317 g_error ("got the wrong result.\n"
321 tc->result, string->str, tc->markup);
324 g_error_free (error);
326 g_string_free (string, TRUE);
329 TestCase test_cases[] = /* successful runs */
332 { "<test/>", "<test></test>" },
333 { "<sub><foo/></sub>", "<sub><<{foo}{/foo}>></sub>" },
334 { "<sub><foo/><bar/></sub>", "<sub><<{foo}{/foo}{bar}{/bar}>></sub>" },
335 { "<foo><bar/></foo>", "<foo>[[{foo}{bar}{/bar}{/foo}]]</foo>" },
336 { "<foo><x/><y/></foo>", "<foo>[[{foo}{x}{/x}{y}{/y}{/foo}]]</foo>" },
337 { "<foo/>", "<foo>[[{foo}{/foo}]]</foo>" },
338 { "<sub><foo/></sub><bar/>", "<sub><<{foo}{/foo}>></sub>"
339 "<bar>[[{bar}{/bar}]]</bar>" }
342 TestCase error_cases[] = /* error cases */
344 /* in */ /* out */ /* error */
345 { "<foo><>", "<foo>", ">"},
347 { "<trouble/>", "<trouble>", "trouble" },
348 { "<sub><trouble>", "<sub>", "trouble" },
349 { "<foo><trouble>", "<foo>", "trouble" },
350 { "<sub></sub>", "<sub>", "no data" },
351 { "<sub/>", "<sub>", "no data" }
354 #define add_tests(func, basename, array) \
358 for (__add_tests_i = 0; \
359 __add_tests_i < G_N_ELEMENTS (array); \
364 testname = g_strdup_printf ("%s/%d", basename, __add_tests_i); \
365 g_test_add_data_func (testname, &array[__add_tests_i], func); \
371 main (int argc, char **argv)
373 g_test_init (&argc, &argv, NULL);
374 add_tests (test, "/glib/markup/subparser/success", test_cases);
375 add_tests (test, "/glib/markup/subparser/failure", error_cases);
376 return g_test_run ();