1 /*
2 * Copyright © 2007 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 <glib.h>
14
15 static void
start(GMarkupParseContext * context,const char * element_name,const char ** attribute_names,const char ** attribute_values,gpointer user_data,GError ** error)16 start (GMarkupParseContext *context,
17 const char *element_name,
18 const char **attribute_names,
19 const char **attribute_values,
20 gpointer user_data,
21 GError **error)
22 {
23 GString *string = user_data;
24 gboolean result;
25
26 #define collect(...) \
27 g_markup_collect_attributes (element_name, attribute_names, \
28 attribute_values, error, __VA_ARGS__, \
29 G_MARKUP_COLLECT_INVALID)
30 #define BOOL G_MARKUP_COLLECT_BOOLEAN
31 #define OPTBOOL G_MARKUP_COLLECT_BOOLEAN | G_MARKUP_COLLECT_OPTIONAL
32 #define TRI G_MARKUP_COLLECT_TRISTATE
33 #define STR G_MARKUP_COLLECT_STRING
34 #define STRDUP G_MARKUP_COLLECT_STRDUP
35 #define OPTSTR G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL
36 #define OPTDUP G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL
37 #define n(x) ((x)?(x):"(null)")
38
39 if (strcmp (element_name, "bool") == 0)
40 {
41 gboolean mb = 2, ob = 2, tri = 2;
42
43 result = collect (BOOL, "mb", &mb,
44 OPTBOOL, "ob", &ob,
45 TRI, "tri", &tri);
46
47 g_assert (result ||
48 (mb == FALSE && ob == FALSE && tri != TRUE && tri != FALSE));
49
50 if (tri != FALSE && tri != TRUE)
51 tri = -1;
52
53 g_string_append_printf (string, "<bool(%d) %d %d %d>",
54 result, mb, ob, tri);
55 }
56
57 else if (strcmp (element_name, "str") == 0)
58 {
59 const char *cm, *co;
60 char *am, *ao;
61
62 result = collect (STR, "cm", &cm,
63 STRDUP, "am", &am,
64 OPTDUP, "ao", &ao,
65 OPTSTR, "co", &co);
66
67 g_assert (result ||
68 (cm == NULL && am == NULL && ao == NULL && co == NULL));
69
70 g_string_append_printf (string, "<str(%d) %s %s %s %s>",
71 result, n (cm), n (am), n (ao), n (co));
72
73 g_free (am);
74 g_free (ao);
75 }
76 }
77
78 static GMarkupParser parser = { start };
79
80 struct test
81 {
82 const char *document;
83 const char *result;
84 GMarkupError error_code;
85 const char *error_info;
86 };
87
88 static struct test tests[] =
89 {
90 { "<bool mb='y'>", "<bool(1) 1 0 -1>",
91 G_MARKUP_ERROR_PARSE, "'bool'" },
92
93 { "<bool mb='false'/>", "<bool(1) 0 0 -1>" },
94 { "<bool mb='true'/>", "<bool(1) 1 0 -1>" },
95 { "<bool mb='t' ob='f' tri='1'/>", "<bool(1) 1 0 1>" },
96 { "<bool mb='y' ob='n' tri='0'/>", "<bool(1) 1 0 0>" },
97
98 { "<bool ob='y'/>", "<bool(0) 0 0 -1>",
99 G_MARKUP_ERROR_MISSING_ATTRIBUTE, "'mb'" },
100
101 { "<bool mb='y' mb='y'/>", "<bool(0) 0 0 -1>",
102 G_MARKUP_ERROR_INVALID_CONTENT, "'mb'" },
103
104 { "<bool mb='y' tri='y' tri='n'/>", "<bool(0) 0 0 -1>",
105 G_MARKUP_ERROR_INVALID_CONTENT, "'tri'" },
106
107 { "<str cm='x' am='y'/>", "<str(1) x y (null) (null)>" },
108
109 { "<str am='x' co='y'/>", "<str(0) (null) (null) (null) (null)>",
110 G_MARKUP_ERROR_MISSING_ATTRIBUTE, "'cm'" },
111
112 { "<str am='x'/>", "<str(0) (null) (null) (null) (null)>",
113 G_MARKUP_ERROR_MISSING_ATTRIBUTE, "'cm'" },
114
115 { "<str am='x' cm='x' am='y'/>", "<str(0) (null) (null) (null) (null)>",
116 G_MARKUP_ERROR_INVALID_CONTENT, "'am'" },
117
118 { "<str am='x' qm='y' cm='x'/>", "<str(0) (null) (null) (null) (null)>",
119 G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "'qm'" },
120
121 { "<str am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' cm='x'/>", "<str(0) (null) (null) (null) (null)>",
122 G_MARKUP_ERROR_INVALID_CONTENT, "'am'" },
123
124 { "<str cm='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x' am='x'/>", "<str(0) (null) (null) (null) (null)>",
125 G_MARKUP_ERROR_INVALID_CONTENT, "'am'" },
126
127 { "<str a='x' b='x' c='x' d='x' e='x' f='x' g='x' h='x' i='x' j='x' k='x' l='x' m='x' n='x' o='x' p='x' q='x' r='x' s='x' t='x' u='x' v='x' w='x' x='x' y='x' z='x' aa='x' bb='x' cc='x' dd='x' ee='x' ff='x' gg='x' hh='x' ii='x' jj='x' kk='x' ll='x' mm='x' nn='x' oo='x' pp='x' qq='x' rr='x' ss='x' tt='x' uu='x' vv='x' ww='x' xx='x' yy='x' zz='x' am='x' cm='x'/>",
128 "<str(0) (null) (null) (null) (null)>",
129 G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "'a'" },
130
131 { "<bool mb='ja'/>", "<bool(0) 0 0 -1>",
132 G_MARKUP_ERROR_INVALID_CONTENT, "'mb'" },
133
134 { "<bool mb='nein'/>", "<bool(0) 0 0 -1>",
135 G_MARKUP_ERROR_INVALID_CONTENT, "'mb'" }
136 };
137
138 int
main(int argc,char ** argv)139 main (int argc, char **argv)
140 {
141 gboolean verbose = FALSE;
142 int i;
143
144 if (argc > 1)
145 {
146 if (argc != 2 || strcmp (argv[1], "-v") != 0)
147 {
148 g_print ("error: call with no arguments or '-v' for verbose\n");
149 return 1;
150 }
151
152 verbose = TRUE;
153 }
154
155 for (i = 0; i < G_N_ELEMENTS (tests); i++)
156 {
157 GMarkupParseContext *ctx;
158 GError *error = NULL;
159 GString *string;
160 gboolean result;
161
162 string = g_string_new ("");
163 ctx = g_markup_parse_context_new (&parser, 0, string, NULL);
164 result = g_markup_parse_context_parse (ctx,
165 tests[i].document,
166 -1, &error);
167 if (result)
168 result = g_markup_parse_context_end_parse (ctx, &error);
169
170 if (verbose)
171 g_print ("%d: %s:\n (error %d, \"%s\")\n %s\n\n",
172 i, tests[i].document,
173 error ? error->code : 0,
174 error ? error->message : "(no error)",
175 string->str);
176
177 if (result)
178 {
179 if (error != NULL)
180 g_error ("parser successful but error is set: "
181 "%s(%d) '%s'", g_quark_to_string (error->domain),
182 error->code, error->message);
183
184 if (tests[i].error_code != 0)
185 g_error ("parser succeeded on test %d ('%s') but "
186 "we expected a failure with code %d\n", i,
187 tests[i].document, tests[i].error_code);
188 }
189 else
190 {
191 if (error->domain != G_MARKUP_ERROR)
192 g_error ("error occured on test %d ('%s') but is not in "
193 "the GMarkupError domain, but rather '%s'", i,
194 tests[i].document, g_quark_to_string (error->domain));
195
196 if (error->code != tests[i].error_code)
197 g_error ("failure expected with test %d ('%s') but it "
198 "has error code %d (we expected code %d)", i,
199 tests[i].document, error->code, tests[i].error_code);
200
201 if (strstr (error->message, tests[i].error_info) == NULL)
202 g_error ("failure message on test %d ('%s') fails "
203 "to mention '%s' in the error message", i,
204 tests[i].document, tests[i].error_info);
205 }
206
207 if (strcmp (tests[i].result, string->str) != 0)
208 g_error ("result on test %d ('%s') expected to be '%s' "
209 "but came out as '%s'", i, tests[i].document,
210 tests[i].result, string->str);
211
212 g_markup_parse_context_free (ctx);
213 g_string_free (string, TRUE);
214 g_clear_error (&error);
215 }
216
217 if (verbose)
218 g_print ("\n*** all tests passed ***\n\n");
219
220 return 0;
221 }
222