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 | |
34 | static char * |
35 | test_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 | |
55 | static char * |
56 | test_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 | |
76 | static void |
77 | append_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 | |
92 | static void |
93 | parsing_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 | |
120 | static void |
121 | parse_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 | |
183 | out: |
184 | g_free (mem: css_file); |
185 | g_free (mem: css); |
186 | } |
187 | |
188 | static void |
189 | test_css_file (GFile *file) |
190 | { |
191 | parse_css_file (file, FALSE); |
192 | } |
193 | |
194 | static void |
195 | add_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 | |
211 | static int |
212 | compare_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 | |
230 | static void |
231 | add_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 | |
269 | int |
270 | main (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 | |