1/*
2 * Copyright (C) 2011 Red Hat Inc.
3 *
4 * Author:
5 * Benjamin Otte <otte@redhat.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "config.h"
22
23#undef GTK_DISABLE_DEPRECATED
24
25#include <string.h>
26#include <glib/gstdio.h>
27#include <gtk/gtk.h>
28#include "testsuite/testutils.h"
29
30#ifdef G_OS_WIN32
31# include <io.h>
32#endif
33
34static char *
35test_get_reference_file (const char *css_file)
36{
37 GString *file = g_string_new (NULL);
38
39 if (g_str_has_suffix (str: css_file, suffix: ".css"))
40 g_string_append_len (string: file, val: css_file, len: strlen (s: css_file) - 4);
41 else
42 g_string_append (string: file, val: css_file);
43
44 g_string_append (string: file, val: ".ref.css");
45
46 if (!g_file_test (filename: file->str, test: G_FILE_TEST_EXISTS))
47 {
48 g_string_free (string: file, TRUE);
49 return g_strdup (str: css_file);
50 }
51
52 return g_string_free (string: file, FALSE);
53}
54
55static char *
56test_get_errors_file (const char *css_file)
57{
58 GString *file = g_string_new (NULL);
59
60 if (g_str_has_suffix (str: css_file, suffix: ".css"))
61 g_string_append_len (string: file, val: css_file, len: strlen (s: css_file) - 4);
62 else
63 g_string_append (string: file, val: css_file);
64
65 g_string_append (string: file, val: ".errors");
66
67 if (!g_file_test (filename: file->str, test: G_FILE_TEST_EXISTS))
68 {
69 g_string_free (string: file, TRUE);
70 return NULL;
71 }
72
73 return g_string_free (string: file, FALSE);
74}
75
76static void
77append_error_value (GString *string,
78 GType enum_type,
79 guint value)
80{
81 GEnumClass *enum_class;
82 GEnumValue *enum_value;
83
84 enum_class = g_type_class_ref (type: enum_type);
85 enum_value = g_enum_get_value (enum_class, value);
86
87 g_string_append (string, val: enum_value->value_name);
88
89 g_type_class_unref (g_class: enum_class);
90}
91
92static void
93parsing_error_cb (GtkCssProvider *provider,
94 GtkCssSection *section,
95 const GError *error,
96 GString *errors)
97{
98 char *section_string;
99
100 section_string = gtk_css_section_to_string (section);
101
102 g_string_append_printf (string: errors,
103 format: "%s: error: ",
104 section_string);
105 g_free (mem: section_string);
106
107 if (error->domain == GTK_CSS_PARSER_ERROR)
108 append_error_value (string: errors, enum_type: GTK_TYPE_CSS_PARSER_ERROR, value: error->code);
109 else if (error->domain == GTK_CSS_PARSER_WARNING)
110 append_error_value (string: errors, enum_type: GTK_TYPE_CSS_PARSER_WARNING, value: error->code);
111 else
112 g_string_append_printf (string: errors,
113 format: "%s %u\n",
114 g_quark_to_string (quark: error->domain),
115 error->code);
116
117 g_string_append_c (errors, '\n');
118}
119
120static void
121parse_css_file (GFile *file, gboolean generate)
122{
123 GtkCssProvider *provider;
124 char *css, *css_file, *reference_file, *errors_file;
125 GString *errors;
126 char *diff;
127 GError *error = NULL;
128
129 css_file = g_file_get_path (file);
130 errors = g_string_new (init: "");
131
132 provider = gtk_css_provider_new ();
133 g_signal_connect (provider,
134 "parsing-error",
135 G_CALLBACK (parsing_error_cb),
136 errors);
137 gtk_css_provider_load_from_path (css_provider: provider, path: css_file);
138
139 css = gtk_css_provider_to_string (provider);
140
141 if (generate)
142 {
143 g_print (format: "%s", css);
144 goto out;
145 }
146
147 reference_file = test_get_reference_file (css_file);
148
149 diff = diff_with_file (file1: reference_file, text: css, len: -1, error: &error);
150 g_assert_no_error (error);
151
152 if (diff && diff[0])
153 {
154 g_test_message (format: "Resulting CSS doesn't match reference:\n%s", diff);
155 g_test_fail ();
156 }
157 g_free (mem: reference_file);
158 g_free (mem: diff);
159
160 errors_file = test_get_errors_file (css_file);
161
162 if (errors_file)
163 {
164 diff = diff_with_file (file1: errors_file, text: errors->str, len: errors->len, error: &error);
165 g_assert_no_error (error);
166
167 if (diff && diff[0])
168 {
169 g_test_message (format: "Errors don't match expected errors:\n%s", diff);
170 g_test_fail ();
171 }
172 g_free (mem: diff);
173 }
174 else if (errors->str[0])
175 {
176 g_test_message (format: "Unexpected errors:\n%s", errors->str);
177 g_test_fail ();
178 }
179
180 g_free (mem: errors_file);
181 g_string_free (string: errors, TRUE);
182
183out:
184 g_free (mem: css_file);
185 g_free (mem: css);
186}
187
188static void
189test_css_file (GFile *file)
190{
191 parse_css_file (file, FALSE);
192}
193
194static void
195add_test_for_file (GFile *file)
196{
197 char *path;
198
199 path = g_file_get_path (file);
200
201 g_test_add_vtable (testpath: path,
202 data_size: 0,
203 g_object_ref (file),
204 NULL,
205 data_test: (GTestFixtureFunc) test_css_file,
206 data_teardown: (GTestFixtureFunc) g_object_unref);
207
208 g_free (mem: path);
209}
210
211static int
212compare_files (gconstpointer a, gconstpointer b)
213{
214 GFile *file1 = G_FILE (a);
215 GFile *file2 = G_FILE (b);
216 char *path1, *path2;
217 int result;
218
219 path1 = g_file_get_path (file: file1);
220 path2 = g_file_get_path (file: file2);
221
222 result = strcmp (s1: path1, s2: path2);
223
224 g_free (mem: path1);
225 g_free (mem: path2);
226
227 return result;
228}
229
230static void
231add_tests_for_files_in_directory (GFile *dir)
232{
233 GFileEnumerator *enumerator;
234 GFileInfo *info;
235 GList *files;
236 GError *error = NULL;
237
238 enumerator = g_file_enumerate_children (file: dir, G_FILE_ATTRIBUTE_STANDARD_NAME, flags: 0, NULL, error: &error);
239 g_assert_no_error (error);
240 files = NULL;
241
242 while ((info = g_file_enumerator_next_file (enumerator, NULL, error: &error)))
243 {
244 const char *filename;
245
246 filename = g_file_info_get_name (info);
247
248 if (!g_str_has_suffix (str: filename, suffix: ".css") ||
249 g_str_has_suffix (str: filename, suffix: ".out.css") ||
250 g_str_has_suffix (str: filename, suffix: ".ref.css"))
251 {
252 g_object_unref (object: info);
253 continue;
254 }
255
256 files = g_list_prepend (list: files, data: g_file_get_child (file: dir, name: filename));
257
258 g_object_unref (object: info);
259 }
260
261 g_assert_no_error (error);
262 g_object_unref (object: enumerator);
263
264 files = g_list_sort (list: files, compare_func: compare_files);
265 g_list_foreach (list: files, func: (GFunc) add_test_for_file, NULL);
266 g_list_free_full (list: files, free_func: g_object_unref);
267}
268
269int
270main (int argc, char **argv)
271{
272 gtk_test_init (argcp: &argc, argvp: &argv);
273
274 if (argc < 2)
275 {
276 const char *basedir;
277 GFile *dir;
278
279 basedir = g_test_get_dir (file_type: G_TEST_DIST);
280 dir = g_file_new_for_path (path: basedir);
281 add_tests_for_files_in_directory (dir);
282
283 g_object_unref (object: dir);
284 }
285 else if (strcmp (s1: argv[1], s2: "--generate") == 0)
286 {
287 if (argc >= 3)
288 {
289 GFile *file = g_file_new_for_commandline_arg (arg: argv[2]);
290
291 parse_css_file (file, TRUE);
292
293 g_object_unref (object: file);
294 }
295 }
296 else
297 {
298 guint i;
299
300 for (i = 1; i < argc; i++)
301 {
302 GFile *file = g_file_new_for_commandline_arg (arg: argv[i]);
303
304 add_test_for_file (file);
305
306 g_object_unref (object: file);
307 }
308 }
309
310 return g_test_run ();
311}
312
313

source code of gtk/testsuite/css/parser/test-css-parser.c