Initial commit
[platform/upstream/glib2.0.git] / glib / tests / markup-subparser.c
1 /* 
2  * Copyright © 2008 Ryan Lortie
3  * 
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.
8  * 
9  * See the included COPYING file for more information.
10  */
11
12 #include <string.h>
13 #include <stdio.h>
14 #include <glib.h>
15
16 /* keep track of GString instances to make sure nothing leaks */
17 static int strings_allocated;
18
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)
27 {
28   g_string_append_printf (user_data, "{%s}", element_name);
29
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");
33 }
34
35 static void
36 subparser_end_element (GMarkupParseContext  *context,
37                        const gchar          *element_name,
38                        gpointer              user_data,
39                        GError              **error)
40 {
41   g_string_append_printf (user_data, "{/%s}", element_name);
42 }
43
44 static void
45 subparser_error (GMarkupParseContext *context,
46                  GError              *error,
47                  gpointer             user_data)
48 {
49   g_string_free (user_data, TRUE);
50   strings_allocated--;
51 }
52
53 static GMarkupParser subparser_parser =
54 {
55   subparser_start_element,
56   subparser_end_element,
57   NULL,
58   NULL,
59   subparser_error
60 };
61
62 /* convenience functions for a parser that does not
63  * replay the starting tag into the subparser...
64  */
65 static void
66 subparser_start (GMarkupParseContext *ctx)
67 {
68   gpointer user_data;
69
70   user_data = g_string_new (NULL);
71   strings_allocated++;
72   g_markup_parse_context_push (ctx, &subparser_parser, user_data);
73 }
74
75 static char *
76 subparser_end (GMarkupParseContext  *ctx,
77                GError              **error)
78 {
79   GString *string;
80   char *result;
81
82   string = g_markup_parse_context_pop (ctx);
83   result = string->str;
84
85   g_string_free (string, FALSE);
86   strings_allocated--;
87
88   if (result == NULL || result[0] == '\0')
89     {
90       g_free (result);
91       g_set_error (error, 0, 0, "got no data");
92
93       return NULL;
94     }
95
96   return result;
97 }
98
99 /* convenience functions for a parser that -does-
100  * replay the starting tag into the subparser...
101  */
102 static gboolean
103 replay_parser_start (GMarkupParseContext  *ctx,
104                      const char           *element_name,
105                      const char          **attribute_names,
106                      const char          **attribute_values,
107                      GError              **error)
108 {
109   GError *tmp_error = NULL;
110   gpointer user_data;
111
112   user_data = g_string_new (NULL);
113   strings_allocated++;
114
115   subparser_parser.start_element (ctx, element_name,
116                                   attribute_names, attribute_values,
117                                   user_data, &tmp_error);
118
119   if (tmp_error)
120     {
121       g_propagate_error (error, tmp_error);
122       g_string_free (user_data, TRUE);
123       strings_allocated--;
124
125       return FALSE;
126     }
127
128   g_markup_parse_context_push (ctx, &subparser_parser, user_data);
129
130   return TRUE;
131 }
132
133 static char *
134 replay_parser_end (GMarkupParseContext  *ctx,
135                    GError              **error)
136 {
137   GError *tmp_error = NULL;
138   GString *string;
139   char *result;
140
141   string = g_markup_parse_context_pop (ctx);
142
143   subparser_parser.end_element (ctx, g_markup_parse_context_get_element (ctx),
144                                 string, &tmp_error);
145
146   if (tmp_error)
147     {
148       g_propagate_error (error, tmp_error);
149       g_string_free (string, TRUE);
150       strings_allocated--;
151
152       return FALSE;
153     }
154
155   result = string->str;
156
157   g_string_free (string, FALSE);
158   strings_allocated--;
159
160   if (result == NULL || result[0] == '\0')
161     {
162       g_free (result);
163       g_set_error (error, 0, 0, "got no data");
164
165       return NULL;
166     }
167
168   return result;
169 }
170
171
172 /* === start interface between subparser and calling parser === */
173 static void      subparser_start      (GMarkupParseContext  *ctx);
174 static char     *subparser_end        (GMarkupParseContext  *ctx,
175                                        GError              **error);
176 /* === end interface between subparser and calling parser === */
177
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,
183                                        GError              **error);
184 static char     *replay_parser_end    (GMarkupParseContext  *ctx,
185                                        GError              **error);
186 /* === end interface between replay parser and calling parser === */
187
188
189
190 /* now comes our parser for the test.
191  *
192  * we recognise the tags <test> and <sub>.
193  * <test> is ignored.
194  * <sub> invokes the subparser (no replay).
195  *
196  * "unknown tags" are passed to the reply subparser
197  * (so the unknown tag is fed to the subparser...)
198  */
199 static void
200 start_element (GMarkupParseContext  *context,
201                const gchar          *element_name,
202                const gchar         **attribute_names,
203                const gchar         **attribute_values,
204                gpointer              user_data,
205                GError              **error)
206 {
207   g_string_append_printf (user_data, "<%s>", element_name);
208
209   if (strcmp (element_name, "test") == 0)
210     {
211       /* do nothing */
212     }
213   else if (strcmp (element_name, "sub") == 0)
214     {
215       /* invoke subparser */
216       subparser_start (context);
217     }
218   else
219     {
220       /* unknown tag.  invoke replay subparser */
221       if (!replay_parser_start (context, element_name,
222                                 attribute_names, attribute_values,
223                                 error))
224         return;
225     }
226 }
227
228 static void
229 end_element (GMarkupParseContext  *context,
230              const gchar          *element_name,
231              gpointer              user_data,
232              GError              **error)
233 {
234   if (strcmp (element_name, "test") == 0)
235     {
236       /* do nothing */
237     }
238   else if (strcmp (element_name, "sub") == 0)
239     {
240       char *result;
241
242       if ((result = subparser_end (context, error)) == NULL)
243         return;
244
245       g_string_append_printf (user_data, "<<%s>>", result);
246       g_free (result);
247     }
248   else
249     {
250       char *result;
251
252       if ((result = replay_parser_end (context, error)) == NULL)
253         return;
254
255       g_string_append_printf (user_data, "[[%s]]", result);
256       g_free (result);
257     }
258
259   g_string_append_printf (user_data, "</%s>", element_name);
260 }
261
262 static GMarkupParser parser =
263 {
264   start_element,
265   end_element
266 };
267
268 typedef struct
269 {
270   const char *markup;
271   const char *result;
272   const char *error_message;
273 } TestCase;
274
275 void
276 test (gconstpointer user_data)
277 {
278   const TestCase *tc = user_data;
279   GMarkupParseContext *ctx;
280   GString *string;
281   gboolean result;
282   GError *error;
283
284   error = NULL;
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);
289   if (result)
290     result = g_markup_parse_context_end_parse (ctx, &error);
291   g_markup_parse_context_free (ctx);
292   g_assert (strings_allocated == 0);
293
294   if (result)
295     {
296       if (tc->error_message)
297         g_error ("expected failure (about '%s') passed!\n"
298                  "  in: %s\n  out: %s",
299                  tc->error_message, tc->markup, string->str);
300     }
301   else
302     {
303       if (!tc->error_message)
304         g_error ("unexpected failure: '%s'\n"
305                  "  in: %s\n  out: %s",
306                  error->message, tc->markup, string->str);
307
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"
312                  "  in: %s\n  out: %s",
313                  tc->error_message, error->message, tc->markup, string->str);
314     }
315
316   if (strcmp (string->str, tc->result) != 0)
317     g_error ("got the wrong result.\n"
318              "  expected: '%s'\n"
319              "  got: '%s'\n"
320              "  input: %s",
321              tc->result, string->str, tc->markup);
322
323   if (error)
324     g_error_free (error);
325
326   g_string_free (string, TRUE);
327 }
328
329 TestCase test_cases[] = /* successful runs */
330 {
331     /* in */                    /* out */
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>" }
340 };
341
342 TestCase error_cases[] = /* error cases */
343 {
344     /* in */                    /* out */                       /* error */
345   { "<foo><>",                  "<foo>",                        ">"},
346   { "",                         "",                             "empty" },
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" }
352 };
353
354 #define add_tests(func, basename, array) \
355   G_STMT_START { \
356     int __add_tests_i;                                                  \
357                                                                         \
358     for (__add_tests_i  = 0;                                            \
359          __add_tests_i < G_N_ELEMENTS (array);                          \
360          __add_tests_i++)                                               \
361       {                                                                 \
362         char *testname;                                                 \
363                                                                         \
364         testname = g_strdup_printf ("%s/%d", basename, __add_tests_i);  \
365         g_test_add_data_func (testname, &array[__add_tests_i], func);   \
366         g_free (testname);                                              \
367       }                                                                 \
368   } G_STMT_END
369
370 int
371 main (int argc, char **argv)
372 {
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 ();
377 }