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#include "testsuite/testutils.h"
25
26#ifdef G_OS_WIN32
27# include <io.h>
28#endif
29
30/* There shall be no other styles */
31#define GTK_STYLE_PROVIDER_PRIORITY_FORCE G_MAXUINT
32
33static char *
34test_get_other_file (const char *ui_file, const char *extension)
35{
36 GString *file = g_string_new (NULL);
37
38 if (g_str_has_suffix (str: ui_file, suffix: ".ui"))
39 g_string_append_len (string: file, val: ui_file, len: strlen (s: ui_file) - strlen (s: ".ui"));
40 else
41 g_string_append (string: file, val: ui_file);
42
43 g_string_append (string: file, val: extension);
44
45 if (!g_file_test (filename: file->str, test: G_FILE_TEST_EXISTS))
46 {
47 g_string_free (string: file, TRUE);
48 return NULL;
49 }
50
51 return g_string_free (string: file, FALSE);
52}
53
54static char *
55fixup_style_differences (const char *str)
56{
57 GRegex *regex;
58 char *result;
59
60 /* normalize differences that creep in from hard-to-control environmental influences */
61 regex = g_regex_new (pattern: "[.]solid-csd", compile_options: 0, match_options: 0, NULL);
62 result = g_regex_replace_literal (regex, string: str, string_len: -1, start_position: 0, replacement: ".csd", match_options: 0, NULL);
63 g_regex_unref (regex);
64
65 return result;
66}
67
68static void
69style_context_changed (GtkWidget *window, const char **output)
70{
71 GtkStyleContext *context;
72 char *str;
73
74 context = gtk_widget_get_style_context (widget: window);
75
76 str = gtk_style_context_to_string (context, flags: GTK_STYLE_CONTEXT_PRINT_RECURSE |
77 GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE);
78
79 *output = fixup_style_differences (str);
80
81 g_free (mem: str);
82
83 g_main_context_wakeup (NULL);
84}
85
86static void
87load_ui_file (GFile *file, gboolean generate)
88{
89 GtkBuilder *builder;
90 GtkWidget *window;
91 char *output;
92 char *diff;
93 char *ui_file, *css_file, *reference_file;
94 GtkCssProvider *provider;
95 GError *error = NULL;
96
97 ui_file = g_file_get_path (file);
98
99 css_file = test_get_other_file (ui_file, extension: ".css");
100 g_assert_nonnull (css_file);
101
102 provider = gtk_css_provider_new ();
103 gtk_css_provider_load_from_path (css_provider: provider, path: css_file);
104 gtk_style_context_add_provider_for_display (display: gdk_display_get_default (),
105 GTK_STYLE_PROVIDER (provider),
106 GTK_STYLE_PROVIDER_PRIORITY_FORCE);
107
108 builder = gtk_builder_new_from_file (filename: ui_file);
109 window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
110
111 g_assert_nonnull (window);
112
113 output = NULL;
114 g_signal_connect (window, "map", G_CALLBACK (style_context_changed), &output);
115
116 gtk_widget_show (widget: window);
117
118 while (!output)
119 g_main_context_iteration (NULL, FALSE);
120
121 if (generate)
122 {
123 g_print (format: "%s", output);
124 goto out;
125 }
126
127 reference_file = test_get_other_file (ui_file, extension: ".nodes");
128 g_assert_nonnull (reference_file);
129
130 diff = diff_with_file (file1: reference_file, text: output, len: -1, error: &error);
131 g_assert_no_error (error);
132
133 if (diff && diff[0])
134 {
135 g_test_message (format: "Resulting output doesn't match reference:\n%s", diff);
136 g_test_fail ();
137 }
138 g_free (mem: reference_file);
139 g_free (mem: diff);
140
141out:
142 gtk_style_context_remove_provider_for_display (display: gdk_display_get_default (),
143 GTK_STYLE_PROVIDER (provider));
144 g_object_unref (object: provider);
145
146 g_free (mem: output);
147 g_free (mem: ui_file);
148 g_free (mem: css_file);
149}
150
151static void
152test_ui_file (GFile *file)
153{
154 load_ui_file (file, FALSE);
155}
156
157static void
158add_test_for_file (GFile *file)
159{
160 char *path;
161
162 path = g_file_get_path (file);
163
164 g_test_add_vtable (testpath: path,
165 data_size: 0,
166 g_object_ref (file),
167 NULL,
168 data_test: (GTestFixtureFunc) test_ui_file,
169 data_teardown: (GTestFixtureFunc) g_object_unref);
170
171 g_free (mem: path);
172}
173
174static int
175compare_files (gconstpointer a, gconstpointer b)
176{
177 GFile *file1 = G_FILE (a);
178 GFile *file2 = G_FILE (b);
179 char *path1, *path2;
180 int result;
181
182 path1 = g_file_get_path (file: file1);
183 path2 = g_file_get_path (file: file2);
184
185 result = strcmp (s1: path1, s2: path2);
186
187 g_free (mem: path1);
188 g_free (mem: path2);
189
190 return result;
191}
192
193static void
194add_tests_for_files_in_directory (GFile *dir)
195{
196 GFileEnumerator *enumerator;
197 GFileInfo *info;
198 GList *files;
199 GError *error = NULL;
200
201 enumerator = g_file_enumerate_children (file: dir, G_FILE_ATTRIBUTE_STANDARD_NAME, flags: 0, NULL, error: &error);
202 g_assert_no_error (error);
203 files = NULL;
204
205 while ((info = g_file_enumerator_next_file (enumerator, NULL, error: &error)))
206 {
207 const char *filename;
208
209 filename = g_file_info_get_name (info);
210
211 if (!g_str_has_suffix (str: filename, suffix: ".ui") ||
212 g_str_has_suffix (str: filename, suffix: ".nodes"))
213 {
214 g_object_unref (object: info);
215 continue;
216 }
217
218 files = g_list_prepend (list: files, data: g_file_get_child (file: dir, name: filename));
219
220 g_object_unref (object: info);
221 }
222
223 g_assert_no_error (error);
224 g_object_unref (object: enumerator);
225
226 files = g_list_sort (list: files, compare_func: compare_files);
227 g_list_foreach (list: files, func: (GFunc) add_test_for_file, NULL);
228 g_list_free_full (list: files, free_func: g_object_unref);
229}
230
231int
232main (int argc, char **argv)
233{
234 g_setenv (variable: "GTK_CSS_DEBUG", value: "1", TRUE);
235 g_setenv (variable: "GTK_THEME", value: "Empty", TRUE);
236
237 if (argc >= 3 && strcmp (s1: argv[1], s2: "--generate") == 0)
238 {
239 GFile *file = g_file_new_for_commandline_arg (arg: argv[2]);
240
241 gtk_init ();
242
243 g_object_set (object: gtk_settings_get_default (), first_property_name: "gtk-font-name", "Sans", NULL);
244
245 load_ui_file (file, TRUE);
246
247 g_object_unref (object: file);
248
249 return 0;
250 }
251
252 gtk_test_init (argcp: &argc, argvp: &argv);
253 g_object_set (object: gtk_settings_get_default (), first_property_name: "gtk-font-name", "Sans", NULL);
254
255 if (argc < 2)
256 {
257 const char *basedir;
258 GFile *dir;
259
260 basedir = g_test_get_dir (file_type: G_TEST_DIST);
261 dir = g_file_new_for_path (path: basedir);
262 add_tests_for_files_in_directory (dir);
263
264 g_object_unref (object: dir);
265 }
266 else
267 {
268 guint i;
269
270 for (i = 1; i < argc; i++)
271 {
272 GFile *file = g_file_new_for_commandline_arg (arg: argv[i]);
273
274 add_test_for_file (file);
275
276 g_object_unref (object: file);
277 }
278 }
279
280 return g_test_run ();
281}
282
283

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