1 /*
2 * Copyright (C) 2015 Red Hat Inc.
3 *
4 * Author:
5 * Matthias Clasen <mclasen@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 <string.h>
22 #include <glib/gstdio.h>
23 #include <gtk/gtk.h>
24
25 #ifdef G_OS_WIN32
26 # include <io.h>
27 #endif
28
29
30 static char *
test_get_reference_file(const char * ui_file)31 test_get_reference_file (const char *ui_file)
32 {
33 GString *file = g_string_new (NULL);
34
35 if (g_str_has_suffix (ui_file, ".ui"))
36 g_string_append_len (file, ui_file, strlen (ui_file) - 3);
37 else
38 g_string_append (file, ui_file);
39
40 g_string_append (file, ".nodes");
41
42 if (!g_file_test (file->str, G_FILE_TEST_EXISTS))
43 {
44 g_string_free (file, TRUE);
45 return g_strdup (ui_file);
46 }
47
48 return g_string_free (file, FALSE);
49 }
50
51 static char *
diff_with_file(const char * file1,char * text,gssize len,GError ** error)52 diff_with_file (const char *file1,
53 char *text,
54 gssize len,
55 GError **error)
56 {
57 const char *command[] = { "diff", "-u", file1, NULL, NULL };
58 char *diff, *tmpfile;
59 int fd;
60
61 diff = NULL;
62
63 if (len < 0)
64 len = strlen (text);
65
66 /* write the text buffer to a temporary file */
67 fd = g_file_open_tmp (NULL, &tmpfile, error);
68 if (fd < 0)
69 return NULL;
70
71 if (write (fd, text, len) != (int) len)
72 {
73 close (fd);
74 g_set_error (error,
75 G_FILE_ERROR, G_FILE_ERROR_FAILED,
76 "Could not write data to temporary file '%s'", tmpfile);
77 goto done;
78 }
79 close (fd);
80 command[3] = tmpfile;
81
82 /* run diff command */
83 g_spawn_sync (NULL,
84 (char **) command,
85 NULL,
86 G_SPAWN_SEARCH_PATH,
87 NULL, NULL,
88 &diff,
89 NULL, NULL,
90 error);
91
92 done:
93 g_unlink (tmpfile);
94 g_free (tmpfile);
95
96 return diff;
97 }
98
99 static void
load_ui_file(GFile * file,gboolean generate)100 load_ui_file (GFile *file, gboolean generate)
101 {
102 GtkBuilder *builder;
103 GtkWidget *window;
104 GtkStyleContext *context;
105 char *output, *diff;
106 char *ui_file, *reference_file;
107 GError *error = NULL;
108
109 ui_file = g_file_get_path (file);
110
111 if (g_str_has_suffix (ui_file, ".rtl.ui"))
112 gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
113 else
114 gtk_widget_set_default_direction (GTK_TEXT_DIR_LTR);
115
116 builder = gtk_builder_new_from_file (ui_file);
117 window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
118
119 g_assert (window != NULL);
120
121 context = gtk_widget_get_style_context (window);
122
123 output = gtk_style_context_to_string (context, GTK_STYLE_CONTEXT_PRINT_RECURSE);
124
125 if (generate)
126 {
127 g_print ("%s", output);
128 goto out;
129 }
130
131 reference_file = test_get_reference_file (ui_file);
132
133 diff = diff_with_file (reference_file, output, -1, &error);
134 g_assert_no_error (error);
135
136 if (diff && diff[0])
137 {
138 g_test_message ("Resulting output doesn't match reference:\n%s", diff);
139 g_test_fail ();
140 }
141 g_free (reference_file);
142 g_free (diff);
143
144 out:
145 g_free (output);
146 g_free (ui_file);
147 }
148
149 static void
test_ui_file(GFile * file)150 test_ui_file (GFile *file)
151 {
152 load_ui_file (file, FALSE);
153 }
154
155 static void
add_test_for_file(GFile * file)156 add_test_for_file (GFile *file)
157 {
158 char *path;
159
160 path = g_file_get_path (file);
161
162 g_test_add_vtable (path,
163 0,
164 g_object_ref (file),
165 NULL,
166 (GTestFixtureFunc) test_ui_file,
167 (GTestFixtureFunc) g_object_unref);
168
169 g_free (path);
170 }
171
172 static int
compare_files(gconstpointer a,gconstpointer b)173 compare_files (gconstpointer a, gconstpointer b)
174 {
175 GFile *file1 = G_FILE (a);
176 GFile *file2 = G_FILE (b);
177 char *path1, *path2;
178 int result;
179
180 path1 = g_file_get_path (file1);
181 path2 = g_file_get_path (file2);
182
183 result = strcmp (path1, path2);
184
185 g_free (path1);
186 g_free (path2);
187
188 return result;
189 }
190
191 static void
add_tests_for_files_in_directory(GFile * dir)192 add_tests_for_files_in_directory (GFile *dir)
193 {
194 GFileEnumerator *enumerator;
195 GFileInfo *info;
196 GList *files;
197 GError *error = NULL;
198
199 enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
200 g_assert_no_error (error);
201 files = NULL;
202
203 while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
204 {
205 const char *filename;
206
207 filename = g_file_info_get_name (info);
208
209 if (!g_str_has_suffix (filename, ".ui") ||
210 g_str_has_suffix (filename, ".nodes"))
211 {
212 g_object_unref (info);
213 continue;
214 }
215
216 files = g_list_prepend (files, g_file_get_child (dir, filename));
217
218 g_object_unref (info);
219 }
220
221 g_assert_no_error (error);
222 g_object_unref (enumerator);
223
224 files = g_list_sort (files, compare_files);
225 g_list_foreach (files, (GFunc) add_test_for_file, NULL);
226 g_list_free_full (files, g_object_unref);
227 }
228
229 int
main(int argc,char ** argv)230 main (int argc, char **argv)
231 {
232 g_setenv ("GTK_CSS_DEBUG", "1", TRUE);
233
234 gtk_test_init (&argc, &argv);
235
236 if (argc < 2)
237 {
238 const char *basedir;
239 GFile *dir;
240
241 basedir = g_test_get_dir (G_TEST_DIST);
242 dir = g_file_new_for_path (basedir);
243 add_tests_for_files_in_directory (dir);
244
245 g_object_unref (dir);
246 }
247 else if (strcmp (argv[1], "--generate") == 0)
248 {
249 if (argc >= 3)
250 {
251 GFile *file = g_file_new_for_commandline_arg (argv[2]);
252
253 load_ui_file (file, TRUE);
254
255 g_object_unref (file);
256 }
257 }
258 else
259 {
260 guint i;
261
262 for (i = 1; i < argc; i++)
263 {
264 GFile *file = g_file_new_for_commandline_arg (argv[i]);
265
266 add_test_for_file (file);
267
268 g_object_unref (file);
269 }
270 }
271
272 return g_test_run ();
273 }
274
275