Branch data Line data Source code
1 : : #undef G_DISABLE_ASSERT
2 : : #undef G_LOG_DOMAIN
3 : :
4 : : #include <locale.h>
5 : : #include <string.h>
6 : : #include <stdio.h>
7 : : #include <glib.h>
8 : :
9 : : static int depth = 0;
10 : : static GString *string;
11 : :
12 : : static void
13 : 277 : indent (int extra)
14 : : {
15 : 277 : int i = 0;
16 [ + + ]: 522 : while (i < depth)
17 : : {
18 [ + - - + ]: 245 : g_string_append (string, " ");
19 : 245 : ++i;
20 : : }
21 : 277 : }
22 : :
23 : : static void
24 : 84 : start_element_handler (GMarkupParseContext *context,
25 : : const gchar *element_name,
26 : : const gchar **attribute_names,
27 : : const gchar **attribute_values,
28 : : gpointer user_data,
29 : : GError **error)
30 : : {
31 : : int i;
32 : :
33 : 84 : indent (0);
34 : 84 : g_string_append_printf (string, "ELEMENT '%s'\n", element_name);
35 : :
36 : 84 : i = 0;
37 [ + + ]: 125 : while (attribute_names[i] != NULL)
38 : : {
39 : 41 : indent (1);
40 : :
41 : 41 : g_string_append_printf (string, "%s=\"%s\"\n",
42 : 41 : attribute_names[i],
43 : 41 : attribute_values[i]);
44 : :
45 : 41 : ++i;
46 : : }
47 : :
48 : 84 : ++depth;
49 : 84 : }
50 : :
51 : : static void
52 : 56 : end_element_handler (GMarkupParseContext *context,
53 : : const gchar *element_name,
54 : : gpointer user_data,
55 : : GError **error)
56 : : {
57 : 56 : --depth;
58 : 56 : indent (0);
59 : 56 : g_string_append_printf (string, "END '%s'\n", element_name);
60 : 56 : }
61 : :
62 : : static void
63 : 89 : text_handler (GMarkupParseContext *context,
64 : : const gchar *text,
65 : : gsize text_len,
66 : : gpointer user_data,
67 : : GError **error)
68 : : {
69 : 89 : indent (0);
70 : 89 : g_string_append_printf (string, "TEXT '%.*s'\n", (int)text_len, text);
71 : 89 : }
72 : :
73 : :
74 : : static void
75 : 7 : passthrough_handler (GMarkupParseContext *context,
76 : : const gchar *passthrough_text,
77 : : gsize text_len,
78 : : gpointer user_data,
79 : : GError **error)
80 : : {
81 : 7 : indent (0);
82 : :
83 : 7 : g_string_append_printf (string, "PASS '%.*s'\n", (int)text_len, passthrough_text);
84 : 7 : }
85 : :
86 : : static void
87 : 432 : error_handler (GMarkupParseContext *context,
88 : : GError *error,
89 : : gpointer user_data)
90 : : {
91 : 432 : g_string_append_printf (string, "ERROR %s\n", error->message);
92 : 432 : }
93 : :
94 : : static const GMarkupParser parser = {
95 : : start_element_handler,
96 : : end_element_handler,
97 : : text_handler,
98 : : passthrough_handler,
99 : : error_handler
100 : : };
101 : :
102 : : static const GMarkupParser silent_parser = {
103 : : NULL,
104 : : NULL,
105 : : NULL,
106 : : NULL,
107 : : error_handler
108 : : };
109 : :
110 : : static int
111 : 511 : test_in_chunks (const gchar *contents,
112 : : gint length,
113 : : gint chunk_size,
114 : : GMarkupParseFlags flags)
115 : : {
116 : : GMarkupParseContext *context;
117 : 511 : int i = 0;
118 : :
119 : 511 : context = g_markup_parse_context_new (&silent_parser, flags, NULL, NULL);
120 : :
121 [ + + ]: 24954 : while (i < length)
122 : : {
123 : 24709 : int this_chunk = MIN (length - i, chunk_size);
124 : :
125 [ + + ]: 24709 : if (!g_markup_parse_context_parse (context,
126 : : contents + i,
127 : : this_chunk,
128 : : NULL))
129 : : {
130 : 266 : g_markup_parse_context_free (context);
131 : 266 : return 1;
132 : : }
133 : :
134 : 24443 : i += this_chunk;
135 : : }
136 : :
137 [ + + ]: 245 : if (!g_markup_parse_context_end_parse (context, NULL))
138 : : {
139 : 112 : g_markup_parse_context_free (context);
140 : 112 : return 1;
141 : : }
142 : :
143 : 133 : g_markup_parse_context_free (context);
144 : :
145 : 133 : return 0;
146 : : }
147 : :
148 : : /* Load the given @filename and parse it multiple times with different chunking
149 : : * and length handling. All results should be equal. %TRUE is returned if the
150 : : * file was parsed successfully on every attempt; %FALSE if it failed to parse
151 : : * on every attempt. The test aborts if some attempts succeed and some fail. */
152 : : static gboolean
153 : 73 : test_file (const gchar *filename,
154 : : GMarkupParseFlags flags)
155 : : {
156 : 73 : gchar *contents = NULL, *contents_unterminated = NULL;
157 : : gsize length_bytes;
158 : 73 : GError *local_error = NULL;
159 : : GMarkupParseContext *context;
160 : : gint line, col;
161 : 73 : guint n_failures = 0;
162 : 73 : guint n_tests = 0;
163 : 73 : const gsize chunk_sizes_bytes[] = { 1, 2, 5, 12, 1024 };
164 : : gsize i;
165 : 73 : GString *first_string = NULL;
166 : :
167 : 73 : g_file_get_contents (filename, &contents, &length_bytes, &local_error);
168 : 73 : g_assert_no_error (local_error);
169 : :
170 : : /* Make a copy of the contents with no trailing nul. */
171 : 73 : contents_unterminated = g_malloc (length_bytes);
172 [ + + ]: 73 : if (contents_unterminated != NULL)
173 : 72 : memcpy (contents_unterminated, contents, length_bytes);
174 : :
175 : : /* Test with nul termination. */
176 : 73 : context = g_markup_parse_context_new (&parser, flags, NULL, NULL);
177 : 73 : g_assert (g_markup_parse_context_get_user_data (context) == NULL);
178 : 73 : g_markup_parse_context_get_position (context, &line, &col);
179 : 73 : g_assert_cmpint (line, ==, 1);
180 : 73 : g_assert_cmpint (col, ==, 1);
181 : :
182 [ + + + + ]: 108 : if (!g_markup_parse_context_parse (context, contents, -1, NULL) ||
183 : 35 : !g_markup_parse_context_end_parse (context, NULL))
184 : 54 : n_failures++;
185 : 73 : n_tests++;
186 : :
187 : 73 : g_markup_parse_context_free (context);
188 : :
189 : : /* FIXME: Swap out the error string so we only return one copy of it, not
190 : : * @n_tests copies. This should be fixed properly by eliminating the global
191 : : * state in this file. */
192 : 73 : first_string = g_steal_pointer (&string);
193 : 73 : string = g_string_new ("");
194 : :
195 : : /* With the length specified explicitly and a nul terminator present (since
196 : : * g_file_get_contents() always adds one). */
197 [ + + ]: 73 : if (test_in_chunks (contents, length_bytes, length_bytes, flags) != 0)
198 : 54 : n_failures++;
199 : 73 : n_tests++;
200 : :
201 : : /* With the length specified explicitly and no nul terminator present. */
202 [ + + ]: 73 : if (test_in_chunks (contents_unterminated, length_bytes, length_bytes, flags) != 0)
203 : 54 : n_failures++;
204 : 73 : n_tests++;
205 : :
206 : : /* In various sized chunks. */
207 [ + + ]: 438 : for (i = 0; i < G_N_ELEMENTS (chunk_sizes_bytes); i++)
208 : : {
209 [ + + ]: 365 : if (test_in_chunks (contents, length_bytes, chunk_sizes_bytes[i], flags) != 0)
210 : 270 : n_failures++;
211 : 365 : n_tests++;
212 : : }
213 : :
214 : 73 : g_free (contents);
215 : 73 : g_free (contents_unterminated);
216 : :
217 : : /* FIXME: Restore the error string. */
218 : 73 : g_string_free (string, TRUE);
219 : 73 : string = g_steal_pointer (&first_string);
220 : :
221 : : /* We expect the file to either always be parsed successfully, or never be
222 : : * parsed successfully. There’s a bug in GMarkup if it sometimes parses
223 : : * successfully depending on how you chunk or terminate the input. */
224 [ + + ]: 73 : if (n_failures > 0)
225 : 54 : g_assert_cmpint (n_failures, ==, n_tests);
226 : :
227 : 73 : return (n_failures == 0);
228 : : }
229 : :
230 : : static gchar *
231 : 142 : get_expected_filename (const gchar *filename,
232 : : GMarkupParseFlags flags)
233 : : {
234 : : gchar *f, *p, *expected;
235 : :
236 : 142 : f = g_strdup (filename);
237 : 142 : p = strstr (f, ".gmarkup");
238 [ + - ]: 142 : if (p)
239 : 142 : *p = 0;
240 [ + + ]: 142 : if (flags == 0)
241 : 71 : expected = g_strconcat (f, ".expected", NULL);
242 [ + - ]: 71 : else if (flags == G_MARKUP_TREAT_CDATA_AS_TEXT)
243 : 71 : expected = g_strconcat (f, ".cdata-as-text", NULL);
244 : : else
245 : : g_assert_not_reached ();
246 : :
247 : 142 : g_free (f);
248 : :
249 : 142 : return expected;
250 : : }
251 : :
252 : : static void
253 : 71 : test_parse (gconstpointer d)
254 : : {
255 : 71 : const gchar *filename = d;
256 : : gchar *expected_file;
257 : : gchar *expected;
258 : : gboolean valid_input;
259 : 71 : GError *error = NULL;
260 : : gboolean res;
261 : :
262 : 71 : valid_input = strstr (filename, "valid") != NULL;
263 : 71 : expected_file = get_expected_filename (filename, 0);
264 : :
265 : 71 : depth = 0;
266 : 71 : string = g_string_sized_new (0);
267 : :
268 : 71 : res = test_file (filename, 0);
269 : 71 : g_assert_cmpint (res, ==, valid_input);
270 : :
271 : 71 : g_file_get_contents (expected_file, &expected, NULL, &error);
272 : 71 : g_assert_no_error (error);
273 : 71 : g_assert_cmpstr (string->str, ==, expected);
274 : 71 : g_free (expected);
275 : :
276 : 71 : g_string_free (string, TRUE);
277 : :
278 : 71 : g_free (expected_file);
279 : :
280 : 71 : expected_file = get_expected_filename (filename, G_MARKUP_TREAT_CDATA_AS_TEXT);
281 [ + + ]: 71 : if (g_file_test (expected_file, G_FILE_TEST_EXISTS))
282 : : {
283 : 2 : depth = 0;
284 : 2 : string = g_string_sized_new (0);
285 : :
286 : 2 : res = test_file (filename, G_MARKUP_TREAT_CDATA_AS_TEXT);
287 : 2 : g_assert_cmpint (res, ==, valid_input);
288 : :
289 : 2 : g_file_get_contents (expected_file, &expected, NULL, &error);
290 : 2 : g_assert_no_error (error);
291 : 2 : g_assert_cmpstr (string->str, ==, expected);
292 : 2 : g_free (expected);
293 : :
294 : 2 : g_string_free (string, TRUE);
295 : : }
296 : :
297 : 71 : g_free (expected_file);
298 : 71 : }
299 : :
300 : : int
301 : 1 : main (int argc, char *argv[])
302 : : {
303 : : GDir *dir;
304 : : GError *error;
305 : : const gchar *name;
306 : : gchar *path;
307 : :
308 : 1 : g_setenv ("LC_ALL", "C", TRUE);
309 : 1 : setlocale (LC_ALL, "");
310 : :
311 : 1 : g_test_init (&argc, &argv, NULL);
312 : :
313 : : /* allow to easily generate expected output for new test cases */
314 [ - + ]: 1 : if (argc > 1)
315 : : {
316 : 0 : gint arg = 1;
317 : 0 : GMarkupParseFlags flags = G_MARKUP_DEFAULT_FLAGS;
318 : :
319 [ # # ]: 0 : if (strcmp (argv[1], "--cdata-as-text") == 0)
320 : : {
321 : 0 : flags = G_MARKUP_TREAT_CDATA_AS_TEXT;
322 : 0 : arg = 2;
323 : : }
324 : 0 : string = g_string_sized_new (0);
325 : 0 : test_file (argv[arg], flags);
326 : 0 : g_print ("%s", string->str);
327 : 0 : return 0;
328 : : }
329 : :
330 : 1 : error = NULL;
331 : 1 : path = g_test_build_filename (G_TEST_DIST, "markups", NULL);
332 : 1 : dir = g_dir_open (path, 0, &error);
333 : 1 : g_free (path);
334 : 1 : g_assert_no_error (error);
335 [ + + ]: 145 : while ((name = g_dir_read_name (dir)) != NULL)
336 : : {
337 [ + + ]: 144 : if (!strstr (name, "gmarkup"))
338 : 73 : continue;
339 : :
340 : 71 : path = g_strdup_printf ("/markup/parse/%s", name);
341 : 71 : g_test_add_data_func_full (path, g_test_build_filename (G_TEST_DIST, "markups", name, NULL),
342 : : test_parse, g_free);
343 : 71 : g_free (path);
344 : : }
345 : 1 : g_dir_close (dir);
346 : :
347 : 1 : return g_test_run ();
348 : : }
|