]> Pileus Git - ~andy/gtk/blob - tests/css/parser/test-css-parser.c
cssparser: Make lines and positions 0-indexed
[~andy/gtk] / tests / css / parser / test-css-parser.c
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, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <glib/gstdio.h>
27 #include <gtk/gtk.h>
28
29 static char *
30 test_get_reference_file (const char *css_file)
31 {
32   GString *file = g_string_new (NULL);
33
34   if (g_str_has_suffix (css_file, ".css"))
35     g_string_append_len (file, css_file, strlen (css_file) - 4);
36   else
37     g_string_append (file, css_file);
38   
39   g_string_append (file, ".ref.css");
40
41   if (!g_file_test (file->str, G_FILE_TEST_EXISTS))
42     {
43       g_string_free (file, TRUE);
44       return g_strdup (css_file);
45     }
46
47   return g_string_free (file, FALSE);
48 }
49
50 static char *
51 test_get_errors_file (const char *css_file)
52 {
53   GString *file = g_string_new (NULL);
54
55   if (g_str_has_suffix (css_file, ".css"))
56     g_string_append_len (file, css_file, strlen (css_file) - 4);
57   else
58     g_string_append (file, css_file);
59   
60   g_string_append (file, ".errors");
61
62   if (!g_file_test (file->str, G_FILE_TEST_EXISTS))
63     {
64       g_string_free (file, TRUE);
65       return NULL;
66     }
67
68   return g_string_free (file, FALSE);
69 }
70
71 static char *
72 diff_with_file (const char  *file1,
73                 char        *text,
74                 gssize       len,
75                 GError     **error)
76 {
77   const char *command[] = { "diff", "-u", file1, NULL, NULL };
78   char *diff, *tmpfile;
79   int fd;
80
81   diff = NULL;
82
83   if (len < 0)
84     len = strlen (text);
85   
86   /* write the text buffer to a temporary file */
87   fd = g_file_open_tmp (NULL, &tmpfile, error);
88   if (fd < 0)
89     return NULL;
90
91   if (write (fd, text, len) != (int) len)
92     {
93       close (fd);
94       g_set_error (error,
95                    G_FILE_ERROR, G_FILE_ERROR_FAILED,
96                    "Could not write data to temporary file '%s'", tmpfile);
97       goto done;
98     }
99   close (fd);
100   command[3] = tmpfile;
101
102   /* run diff command */
103   g_spawn_sync (NULL, 
104                 (char **) command,
105                 NULL,
106                 G_SPAWN_SEARCH_PATH,
107                 NULL, NULL,
108                 &diff,
109                 NULL, NULL,
110                 error);
111
112 done:
113   g_unlink (tmpfile);
114   g_free (tmpfile);
115
116   return diff;
117 }
118
119 static void
120 append_error_value (GString *string,
121                     GType    enum_type,
122                     guint    value)
123 {
124   GEnumClass *enum_class;
125   GEnumValue *enum_value;
126
127   enum_class = g_type_class_ref (enum_type);
128   enum_value = g_enum_get_value (enum_class, value);
129
130   g_string_append (string, enum_value->value_name);
131
132   g_type_class_unref (enum_class);
133 }
134
135 static void
136 parsing_error_cb (GtkCssProvider *provider,
137                   const gchar     *path,
138                   guint            line,
139                   guint            position,
140                   const GError *   error,
141                   GString *        errors)
142 {
143   char *basename;
144
145   g_assert (path);
146   g_assert (line > 0);
147
148   basename = g_path_get_basename (path);
149   g_string_append_printf (errors,
150                           "%s:%u: error: ",
151                           basename, line + 1);
152   g_free (basename);
153                           
154   if (error->domain == GTK_CSS_PROVIDER_ERROR)
155       append_error_value (errors, GTK_TYPE_CSS_PROVIDER_ERROR, error->code);
156   else
157     g_string_append_printf (errors, 
158                             "%s %u\n",
159                             g_quark_to_string (error->domain),
160                             error->code);
161
162   g_string_append_c (errors, '\n');
163 }
164
165 static void
166 test_css_file (GFile *file)
167 {
168   GtkCssProvider *provider;
169   char *css, *diff;
170   char *css_file, *reference_file, *errors_file;
171   GString *errors;
172   GError *error = NULL;
173
174   css_file = g_file_get_path (file);
175   errors = g_string_new ("");
176
177   provider = gtk_css_provider_new ();
178   g_signal_connect (provider, 
179                     "parsing-error",
180                     G_CALLBACK (parsing_error_cb),
181                     errors);
182   gtk_css_provider_load_from_path (provider,
183                                    css_file,
184                                    NULL);
185
186   css = gtk_css_provider_to_string (provider);
187
188   reference_file = test_get_reference_file (css_file);
189
190   diff = diff_with_file (reference_file, css, -1, &error);
191   g_assert_no_error (error);
192
193   if (diff && diff[0])
194     {
195       g_test_message ("Resulting CSS doesn't match reference:\n%s", diff);
196       g_test_fail ();
197     }
198
199   g_free (css);
200   g_free (reference_file);
201
202   errors_file = test_get_errors_file (css_file);
203
204   if (errors_file)
205     {
206       diff = diff_with_file (errors_file, errors->str, errors->len, &error);
207       g_assert_no_error (error);
208
209       if (diff && diff[0])
210         {
211           g_test_message ("Errors don't match expected errors:\n%s", diff);
212           g_test_fail ();
213         }
214     }
215   else if (errors->str[0])
216     {
217       g_test_message ("Unexpected errors:\n%s", errors->str);
218       g_test_fail ();
219     }
220
221   g_free (errors_file);
222   g_string_free (errors, TRUE);
223
224   g_free (diff);
225   g_free (css_file);
226 }
227
228 static void
229 add_test_for_file (GFile *file)
230 {
231   g_test_add_vtable (g_file_get_path (file),
232                      0,
233                      g_object_ref (file),
234                      NULL,
235                      (GTestFixtureFunc) test_css_file,
236                      (GTestFixtureFunc) g_object_unref);
237 }
238
239 static int
240 compare_files (gconstpointer a, gconstpointer b)
241 {
242   GFile *file1 = G_FILE (a);
243   GFile *file2 = G_FILE (b);
244   char *path1, *path2;
245   int result;
246
247   path1 = g_file_get_path (file1);
248   path2 = g_file_get_path (file2);
249
250   result = strcmp (path1, path2);
251
252   g_free (path1);
253   g_free (path2);
254
255   return result;
256 }
257
258 static void
259 add_tests_for_files_in_directory (GFile *dir)
260 {
261   GFileEnumerator *enumerator;
262   GFileInfo *info;
263   GList *files;
264   GError *error = NULL;
265
266   enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
267   g_assert_no_error (error);
268   files = NULL;
269
270   while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
271     {
272       const char *filename;
273
274       filename = g_file_info_get_name (info);
275
276       if (!g_str_has_suffix (filename, ".css") ||
277           g_str_has_suffix (filename, ".out.css") ||
278           g_str_has_suffix (filename, ".ref.css"))
279         {
280           g_object_unref (info);
281           continue;
282         }
283
284       files = g_list_prepend (files, g_file_get_child (dir, filename));
285
286       g_object_unref (info);
287     }
288   
289   g_assert_no_error (error);
290   g_object_unref (enumerator);
291
292   files = g_list_sort (files, compare_files);
293   g_list_foreach (files, (GFunc) add_test_for_file, NULL);
294   g_list_free_full (files, g_object_unref);
295 }
296
297 int
298 main (int argc, char **argv)
299 {
300   gtk_test_init (&argc, &argv);
301
302   /* Add a bunch of properties so we can test that we parse them properly */
303   gtk_style_properties_register_property (NULL,
304                                           g_param_spec_boolean ("boolean-property",
305                                                                 "boolean property",
306                                                                 "test boolean properties",
307                                                                 TRUE,
308                                                                 G_PARAM_READABLE));
309   gtk_style_properties_register_property (NULL,
310                                           g_param_spec_int ("int-property",
311                                                             "int property",
312                                                             "test int properties",
313                                                             G_MININT, G_MAXINT, 0,
314                                                             G_PARAM_READABLE));
315   gtk_style_properties_register_property (NULL,
316                                           g_param_spec_uint ("uint-property",
317                                                              "uint property",
318                                                              "test uint properties",
319                                                              0, G_MAXUINT, 0,
320                                                              G_PARAM_READABLE));
321   gtk_style_properties_register_property (NULL,
322                                           g_param_spec_float ("float-property",
323                                                               "float property",
324                                                               "test float properties",
325                                                               -G_MAXFLOAT, G_MAXFLOAT, 0.0f,
326                                                               G_PARAM_READABLE));
327   gtk_style_properties_register_property (NULL,
328                                           g_param_spec_double ("double-property",
329                                                                "double property",
330                                                                "test double properties",
331                                                                -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
332                                                                G_PARAM_READABLE));
333   gtk_style_properties_register_property (NULL,
334                                           g_param_spec_string ("string-property",
335                                                                "string property",
336                                                                "test string properties",
337                                                                NULL,
338                                                                G_PARAM_READABLE));
339   gtk_style_properties_register_property (NULL,
340                                           g_param_spec_boxed ("rgba-property",
341                                                               "rgba property",
342                                                               "test rgba properties",
343                                                               GDK_TYPE_RGBA,
344                                                               G_PARAM_READABLE));
345   gtk_style_properties_register_property (NULL,
346                                           g_param_spec_boxed ("color-property",
347                                                               "color property",
348                                                               "test color properties",
349                                                               GDK_TYPE_COLOR,
350                                                               G_PARAM_READABLE));
351   gtk_style_properties_register_property (NULL,
352                                           g_param_spec_boxed ("border-property",
353                                                               "border property",
354                                                               "test border properties",
355                                                               GTK_TYPE_BORDER,
356                                                               G_PARAM_READABLE));
357   gtk_style_properties_register_property (NULL,
358                                           g_param_spec_boxed ("font-property",
359                                                               "font property",
360                                                               "test font properties",
361                                                               PANGO_TYPE_FONT_DESCRIPTION,
362                                                               G_PARAM_READABLE));
363 #if 0
364   /* not public API, use transition instead */
365   gtk_style_properties_register_property (NULL,
366                                           g_param_spec_boxed ("animation-property",
367                                                               "animation property",
368                                                               "test animation properties",
369                                                               GTK_TYPE_ANIMATION_DESCRIPTION,
370                                                               G_PARAM_READABLE));
371 #endif
372   gtk_style_properties_register_property (NULL,
373                                           g_param_spec_object ("engine-property",
374                                                                "engine property",
375                                                                "test theming engine properties",
376                                                                GTK_TYPE_THEMING_ENGINE,
377                                                                G_PARAM_READABLE));
378   gtk_style_properties_register_property (NULL,
379                                           g_param_spec_enum ("enum-property",
380                                                              "enum property",
381                                                              "test enum properties",
382                                                              GTK_TYPE_SHADOW_TYPE,
383                                                              0,
384                                                              G_PARAM_READABLE));
385   gtk_style_properties_register_property (NULL,
386                                           g_param_spec_flags ("flags-property",
387                                                               "flags property",
388                                                               "test flags properties",
389                                                               GTK_TYPE_STATE_FLAGS,
390                                                               GTK_STATE_FLAG_NORMAL,
391                                                               G_PARAM_READABLE));
392
393   if (argc < 2)
394     {
395       const char *basedir;
396       GFile *dir;
397
398       if (g_getenv ("srcdir"))
399         basedir = g_getenv ("srcdir");
400       else
401         basedir = ".";
402         
403       dir = g_file_new_for_path (basedir);
404       
405       add_tests_for_files_in_directory (dir);
406
407       g_object_unref (dir);
408     }
409   else
410     {
411       guint i;
412
413       for (i = 1; i < argc; i++)
414         {
415           GFile *file = g_file_new_for_commandline_arg (argv[i]);
416
417           add_test_for_file (file);
418
419           g_object_unref (file);
420         }
421     }
422
423   return g_test_run ();
424 }
425