GVariant test: add a new vector serialisation test
[platform/upstream/glib.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, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
33                  "we don't like trouble");
34 }
35
36 static void
37 subparser_end_element (GMarkupParseContext  *context,
38                        const gchar          *element_name,
39                        gpointer              user_data,
40                        GError              **error)
41 {
42   g_string_append_printf (user_data, "{/%s}", element_name);
43 }
44
45 static void
46 subparser_error (GMarkupParseContext *context,
47                  GError              *error,
48                  gpointer             user_data)
49 {
50   g_string_free (user_data, TRUE);
51   strings_allocated--;
52 }
53
54 static GMarkupParser subparser_parser =
55 {
56   subparser_start_element,
57   subparser_end_element,
58   NULL,
59   NULL,
60   subparser_error
61 };
62
63 /* convenience functions for a parser that does not
64  * replay the starting tag into the subparser...
65  */
66 static void
67 subparser_start (GMarkupParseContext *ctx)
68 {
69   gpointer user_data;
70
71   user_data = g_string_new (NULL);
72   strings_allocated++;
73   g_markup_parse_context_push (ctx, &subparser_parser, user_data);
74 }
75
76 static char *
77 subparser_end (GMarkupParseContext  *ctx,
78                GError              **error)
79 {
80   GString *string;
81   char *result;
82
83   string = g_markup_parse_context_pop (ctx);
84   result = string->str;
85
86   g_string_free (string, FALSE);
87   strings_allocated--;
88
89   if (result == NULL || result[0] == '\0')
90     {
91       g_free (result);
92       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
93                    "got no data");
94
95       return NULL;
96     }
97
98   return result;
99 }
100
101 /* convenience functions for a parser that -does-
102  * replay the starting tag into the subparser...
103  */
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)
110 {
111   GError *tmp_error = NULL;
112   gpointer user_data;
113
114   user_data = g_string_new (NULL);
115   strings_allocated++;
116
117   subparser_parser.start_element (ctx, element_name,
118                                   attribute_names, attribute_values,
119                                   user_data, &tmp_error);
120
121   if (tmp_error)
122     {
123       g_propagate_error (error, tmp_error);
124       g_string_free (user_data, TRUE);
125       strings_allocated--;
126
127       return FALSE;
128     }
129
130   g_markup_parse_context_push (ctx, &subparser_parser, user_data);
131
132   return TRUE;
133 }
134
135 static char *
136 replay_parser_end (GMarkupParseContext  *ctx,
137                    GError              **error)
138 {
139   GError *tmp_error = NULL;
140   GString *string;
141   char *result;
142
143   string = g_markup_parse_context_pop (ctx);
144
145   subparser_parser.end_element (ctx, g_markup_parse_context_get_element (ctx),
146                                 string, &tmp_error);
147
148   if (tmp_error)
149     {
150       g_propagate_error (error, tmp_error);
151       g_string_free (string, TRUE);
152       strings_allocated--;
153
154       return NULL;
155     }
156
157   result = string->str;
158
159   g_string_free (string, FALSE);
160   strings_allocated--;
161
162   if (result == NULL || result[0] == '\0')
163     {
164       g_free (result);
165       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
166                    "got no data");
167
168       return NULL;
169     }
170
171   return result;
172 }
173
174
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 === */
180
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 === */
190
191
192
193 /* now comes our parser for the test.
194  *
195  * we recognise the tags <test> and <sub>.
196  * <test> is ignored.
197  * <sub> invokes the subparser (no replay).
198  *
199  * "unknown tags" are passed to the reply subparser
200  * (so the unknown tag is fed to the subparser...)
201  */
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)
209 {
210   g_string_append_printf (user_data, "<%s>", element_name);
211
212   if (strcmp (element_name, "test") == 0)
213     {
214       /* do nothing */
215     }
216   else if (strcmp (element_name, "sub") == 0)
217     {
218       /* invoke subparser */
219       subparser_start (context);
220     }
221   else
222     {
223       /* unknown tag.  invoke replay subparser */
224       if (!replay_parser_start (context, element_name,
225                                 attribute_names, attribute_values,
226                                 error))
227         return;
228     }
229 }
230
231 static void
232 end_element (GMarkupParseContext  *context,
233              const gchar          *element_name,
234              gpointer              user_data,
235              GError              **error)
236 {
237   if (strcmp (element_name, "test") == 0)
238     {
239       /* do nothing */
240     }
241   else if (strcmp (element_name, "sub") == 0)
242     {
243       char *result;
244
245       if ((result = subparser_end (context, error)) == NULL)
246         return;
247
248       g_string_append_printf (user_data, "<<%s>>", result);
249       g_free (result);
250     }
251   else
252     {
253       char *result;
254
255       if ((result = replay_parser_end (context, error)) == NULL)
256         return;
257
258       g_string_append_printf (user_data, "[[%s]]", result);
259       g_free (result);
260     }
261
262   g_string_append_printf (user_data, "</%s>", element_name);
263 }
264
265 static GMarkupParser parser =
266 {
267   start_element,
268   end_element
269 };
270
271 typedef struct
272 {
273   const char *markup;
274   const char *result;
275   const char *error_message;
276 } TestCase;
277
278 static void
279 test (gconstpointer user_data)
280 {
281   const TestCase *tc = user_data;
282   GMarkupParseContext *ctx;
283   GString *string;
284   gboolean result;
285   GError *error;
286
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);
296
297   if (result)
298     {
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);
303     }
304   else
305     {
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);
310
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);
317     }
318
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);
325
326   if (error)
327     g_error_free (error);
328
329   g_string_free (string, TRUE);
330 }
331
332 TestCase test_cases[] = /* successful runs */
333 {
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>" }
343 };
344
345 TestCase error_cases[] = /* error cases */
346 {
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" }
355 };
356
357 #define add_tests(func, basename, array) \
358   G_STMT_START { \
359     int __add_tests_i;                                                  \
360                                                                         \
361     for (__add_tests_i  = 0;                                            \
362          __add_tests_i < G_N_ELEMENTS (array);                          \
363          __add_tests_i++)                                               \
364       {                                                                 \
365         char *testname;                                                 \
366                                                                         \
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);                                              \
370       }                                                                 \
371   } G_STMT_END
372
373 int
374 main (int argc, char **argv)
375 {
376   g_test_init (&argc, &argv, NULL);
377   add_tests (test, "/glib/markup/subparser/success", test_cases);
378   add_tests (test, "/glib/markup/subparser/failure", error_cases);
379   return g_test_run ();
380 }