1/*
2 * Copyright © 2007 Ryan Lortie
3 *
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.
8 *
9 * See the included COPYING file for more information.
10 */
11
12#include <stdlib.h>
13#include <string.h>
14#include <glib.h>
15
16static void
17start (GMarkupParseContext *context,
18 const char *element_name,
19 const char **attribute_names,
20 const char **attribute_values,
21 gpointer user_data,
22 GError **error)
23{
24 GString *string = user_data;
25 gboolean result;
26
27#define collect(...) \
28 g_markup_collect_attributes (element_name, attribute_names, \
29 attribute_values, error, __VA_ARGS__, \
30 G_MARKUP_COLLECT_INVALID)
31#define BOOL G_MARKUP_COLLECT_BOOLEAN
32#define OPTBOOL G_MARKUP_COLLECT_BOOLEAN | G_MARKUP_COLLECT_OPTIONAL
33#define TRI G_MARKUP_COLLECT_TRISTATE
34#define STR G_MARKUP_COLLECT_STRING
35#define STRDUP G_MARKUP_COLLECT_STRDUP
36#define OPTSTR G_MARKUP_COLLECT_STRING | G_MARKUP_COLLECT_OPTIONAL
37#define OPTDUP G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL
38#define n(x) ((x)?(x):"(null)")
39
40 if (strcmp (s1: element_name, s2: "bool") == 0)
41 {
42 gboolean mb = 2, ob = 2, tri = 2;
43
44 result = collect (BOOL, "mb", &mb,
45 OPTBOOL, "ob", &ob,
46 TRI, "tri", &tri);
47
48 g_assert (result ||
49 (mb == FALSE && ob == FALSE && tri != TRUE && tri != FALSE));
50
51 if (tri != FALSE && tri != TRUE)
52 tri = -1;
53
54 g_string_append_printf (string, format: "<bool(%d) %d %d %d>",
55 result, mb, ob, tri);
56 }
57
58 else if (strcmp (s1: element_name, s2: "str") == 0)
59 {
60 const char *cm, *co;
61 char *am, *ao;
62
63 result = collect (STR, "cm", &cm,
64 STRDUP, "am", &am,
65 OPTDUP, "ao", &ao,
66 OPTSTR, "co", &co);
67
68 g_assert (result ||
69 (cm == NULL && am == NULL && ao == NULL && co == NULL));
70
71 g_string_append_printf (string, format: "<str(%d) %s %s %s %s>",
72 result, n (cm), n (am), n (ao), n (co));
73
74 g_free (mem: am);
75 g_free (mem: ao);
76 }
77}
78
79static GMarkupParser parser = { start, NULL, NULL, NULL, NULL };
80
81struct test
82{
83 const char *document;
84 const char *result;
85 GMarkupError error_code;
86 const char *error_info;
87};
88
89static struct test tests[] =
90{
91 { "<bool mb='y'>", "<bool(1) 1 0 -1>",
92 G_MARKUP_ERROR_PARSE, "'bool'" },
93
94 { "<bool mb='false'/>", "<bool(1) 0 0 -1>", 0, NULL },
95 { "<bool mb='true'/>", "<bool(1) 1 0 -1>", 0, NULL },
96 { "<bool mb='t' ob='f' tri='1'/>", "<bool(1) 1 0 1>", 0, NULL },
97 { "<bool mb='y' ob='n' tri='0'/>", "<bool(1) 1 0 0>", 0, NULL },
98
99 { "<bool mb='y' my:attr='q'><my:tag/></bool>", "<bool(1) 1 0 -1>", 0, NULL },
100 { "<bool mb='y' my:attr='q'><my:tag>some <b>text</b> is in here</my:tag></bool>",
101 "<bool(1) 1 0 -1>", 0, NULL },
102
103 { "<bool ob='y'/>", "<bool(0) 0 0 -1>",
104 G_MARKUP_ERROR_MISSING_ATTRIBUTE, "'mb'" },
105
106 { "<bool mb='y' mb='y'/>", "<bool(0) 0 0 -1>",
107 G_MARKUP_ERROR_INVALID_CONTENT, "'mb'" },
108
109 { "<bool mb='y' tri='y' tri='n'/>", "<bool(0) 0 0 -1>",
110 G_MARKUP_ERROR_INVALID_CONTENT, "'tri'" },
111
112 { "<str cm='x' am='y'/>", "<str(1) x y (null) (null)>", 0, NULL },
113
114 { "<str am='x' co='y'/>", "<str(0) (null) (null) (null) (null)>",
115 G_MARKUP_ERROR_MISSING_ATTRIBUTE, "'cm'" },
116
117 { "<str am='x'/>", "<str(0) (null) (null) (null) (null)>",
118 G_MARKUP_ERROR_MISSING_ATTRIBUTE, "'cm'" },
119
120 { "<str am='x' cm='x' am='y'/>", "<str(0) (null) (null) (null) (null)>",
121 G_MARKUP_ERROR_INVALID_CONTENT, "'am'" },
122
123 { "<str am='x' qm='y' cm='x'/>", "<str(0) (null) (null) (null) (null)>",
124 G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "'qm'" },
125
126 { "<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)>",
127 G_MARKUP_ERROR_INVALID_CONTENT, "'am'" },
128
129 { "<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)>",
130 G_MARKUP_ERROR_INVALID_CONTENT, "'am'" },
131
132 { "<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'/>",
133 "<str(0) (null) (null) (null) (null)>",
134 G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, "'a'" },
135
136 { "<bool mb='ja'/>", "<bool(0) 0 0 -1>",
137 G_MARKUP_ERROR_INVALID_CONTENT, "'mb'" },
138
139 { "<bool mb='nein'/>", "<bool(0) 0 0 -1>",
140 G_MARKUP_ERROR_INVALID_CONTENT, "'mb'" }
141};
142
143static void
144test_collect (gconstpointer d)
145{
146 const struct test *test = d;
147
148 GMarkupParseContext *ctx;
149 GError *error = NULL;
150 GString *string;
151 gboolean result;
152
153 string = g_string_new (init: "");
154 ctx = g_markup_parse_context_new (parser: &parser, flags: G_MARKUP_IGNORE_QUALIFIED, user_data: string, NULL);
155 result = g_markup_parse_context_parse (context: ctx,
156 text: test->document,
157 text_len: -1, error: &error);
158 if (result)
159 result = g_markup_parse_context_end_parse (context: ctx, error: &error);
160
161 if (result)
162 {
163 g_assert_no_error (error);
164 g_assert_cmpint (test->error_code, ==, 0);
165 g_assert_cmpstr (test->result, ==, string->str);
166 }
167 else
168 {
169 g_assert_error (error, G_MARKUP_ERROR, (gint) test->error_code);
170 }
171
172 g_markup_parse_context_free (context: ctx);
173 g_string_free (string, TRUE);
174 g_clear_error (err: &error);
175}
176
177#define XML "<element a='1' b='2' c='3'/>"
178
179static void
180start_element (GMarkupParseContext *context,
181 const gchar *element_name,
182 const gchar **attribute_names,
183 const gchar **attribute_values,
184 gpointer user_data,
185 GError **error)
186{
187 /* Omitting "c" attribute intentionally to trigger crash. */
188 g_markup_collect_attributes (element_name,
189 attribute_names,
190 attribute_values,
191 error,
192 first_type: G_MARKUP_COLLECT_STRING, first_attr: "a", NULL,
193 G_MARKUP_COLLECT_STRING, "b", NULL,
194 G_MARKUP_COLLECT_INVALID);
195}
196
197static GMarkupParser cleanup_parser = {
198 start_element, NULL, NULL, NULL, NULL
199};
200
201static void
202test_cleanup (void)
203{
204 GMarkupParseContext *context;
205
206 if (!g_test_undefined ())
207 return;
208
209 context = g_markup_parse_context_new (parser: &cleanup_parser, flags: 0, NULL, NULL);
210 g_markup_parse_context_parse (context, XML, text_len: -1, NULL);
211
212 g_test_expect_message (G_LOG_DOMAIN, log_level: G_LOG_LEVEL_CRITICAL,
213 pattern: "g_markup_parse_context_end_parse: assertion 'context->state != STATE_ERROR' failed");
214 g_markup_parse_context_end_parse (context, NULL);
215 g_test_assert_expected_messages ();
216
217 g_markup_parse_context_free (context);
218}
219
220int
221main (int argc, char **argv)
222{
223 gsize i;
224 gchar *path;
225
226 g_test_init (argc: &argc, argv: &argv, NULL);
227
228 for (i = 0; i < G_N_ELEMENTS (tests); i++)
229 {
230 path = g_strdup_printf (format: "/markup/collect/%" G_GSIZE_FORMAT, i);
231 g_test_add_data_func (testpath: path, test_data: &tests[i], test_func: test_collect);
232 g_free (mem: path);
233 }
234
235 g_test_add_func (testpath: "/markup/collect/cleanup", test_func: test_cleanup);
236
237 return g_test_run ();
238}
239

source code of gtk/subprojects/glib/glib/tests/markup-collect.c