2 * Copyright © 2008 Ryan Lortie
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.
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
, G_MARKUP_ERROR
, G_MARKUP_ERROR_INVALID_CONTENT
,
33 "we don't like trouble");
37 subparser_end_element (GMarkupParseContext
*context
,
38 const gchar
*element_name
,
42 g_string_append_printf (user_data
, "{/%s}", element_name
);
46 subparser_error (GMarkupParseContext
*context
,
50 g_string_free (user_data
, TRUE
);
54 static GMarkupParser subparser_parser
=
56 subparser_start_element
,
57 subparser_end_element
,
63 /* convenience functions for a parser that does not
64 * replay the starting tag into the subparser...
67 subparser_start (GMarkupParseContext
*ctx
)
71 user_data
= g_string_new (NULL
);
73 g_markup_parse_context_push (ctx
, &subparser_parser
, user_data
);
77 subparser_end (GMarkupParseContext
*ctx
,
83 string
= g_markup_parse_context_pop (ctx
);
86 g_string_free (string
, FALSE
);
89 if (result
== NULL
|| result
[0] == '\0')
92 g_set_error (error
, G_MARKUP_ERROR
, G_MARKUP_ERROR_INVALID_CONTENT
,
101 /* convenience functions for a parser that -does-
102 * replay the starting tag into the subparser...
105 replay_parser_start (GMarkupParseContext
*ctx
,
106 const char *element_name
,
107 const char **attribute_names
,
108 const char **attribute_values
,
111 GError
*tmp_error
= NULL
;
114 user_data
= g_string_new (NULL
);
117 subparser_parser
.start_element (ctx
, element_name
,
118 attribute_names
, attribute_values
,
119 user_data
, &tmp_error
);
123 g_propagate_error (error
, tmp_error
);
124 g_string_free (user_data
, TRUE
);
130 g_markup_parse_context_push (ctx
, &subparser_parser
, user_data
);
136 replay_parser_end (GMarkupParseContext
*ctx
,
139 GError
*tmp_error
= NULL
;
143 string
= g_markup_parse_context_pop (ctx
);
145 subparser_parser
.end_element (ctx
, g_markup_parse_context_get_element (ctx
),
150 g_propagate_error (error
, tmp_error
);
151 g_string_free (string
, TRUE
);
157 result
= string
->str
;
159 g_string_free (string
, FALSE
);
162 if (result
== NULL
|| result
[0] == '\0')
165 g_set_error (error
, G_MARKUP_ERROR
, G_MARKUP_ERROR_INVALID_CONTENT
,
175 /* === start interface between subparser and calling parser === */
176 static void subparser_start (GMarkupParseContext
*ctx
);
177 static char *subparser_end (GMarkupParseContext
*ctx
,
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
,
187 static char *replay_parser_end (GMarkupParseContext
*ctx
,
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>.
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...)
203 start_element (GMarkupParseContext
*context
,
204 const gchar
*element_name
,
205 const gchar
**attribute_names
,
206 const gchar
**attribute_values
,
210 g_string_append_printf (user_data
, "<%s>", element_name
);
212 if (strcmp (element_name
, "test") == 0)
216 else if (strcmp (element_name
, "sub") == 0)
218 /* invoke subparser */
219 subparser_start (context
);
223 /* unknown tag. invoke replay subparser */
224 if (!replay_parser_start (context
, element_name
,
225 attribute_names
, attribute_values
,
232 end_element (GMarkupParseContext
*context
,
233 const gchar
*element_name
,
237 if (strcmp (element_name
, "test") == 0)
241 else if (strcmp (element_name
, "sub") == 0)
245 if ((result
= subparser_end (context
, error
)) == NULL
)
248 g_string_append_printf (user_data
, "<<%s>>", result
);
255 if ((result
= replay_parser_end (context
, error
)) == NULL
)
258 g_string_append_printf (user_data
, "[[%s]]", result
);
262 g_string_append_printf (user_data
, "</%s>", element_name
);
265 static GMarkupParser parser
=
275 const char *error_message
;
279 test (gconstpointer user_data
)
281 const TestCase
*tc
= user_data
;
282 GMarkupParseContext
*ctx
;
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
);
293 result
= g_markup_parse_context_end_parse (ctx
, &error
);
294 g_markup_parse_context_free (ctx
);
295 g_assert (strings_allocated
== 0);
299 if (tc
->error_message
)
300 g_error ("expected failure (about '%s') passed!\n"
302 tc
->error_message
, tc
->markup
, string
->str
);
306 if (!tc
->error_message
)
307 g_error ("unexpected failure: '%s'\n"
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"
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"
324 tc
->result
, string
->str
, tc
->markup
);
327 g_error_free (error
);
329 g_string_free (string
, TRUE
);
332 TestCase test_cases
[] = /* successful runs */
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>", ">"},
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) \
361 for (__add_tests_i = 0; \
362 __add_tests_i < G_N_ELEMENTS (array); \
367 testname = g_strdup_printf ("%s/%d", basename, __add_tests_i); \
368 g_test_add_data_func (testname, &array[__add_tests_i], func); \
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 ();