1/*
2 * Copyright (C) 2020 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 void
55style_context_changed (GtkWidget *window, const char **output)
56{
57 GtkStyleContext *context;
58
59 context = gtk_widget_get_style_context (widget: window);
60
61 *output = gtk_style_context_to_string (context, flags: GTK_STYLE_CONTEXT_PRINT_RECURSE |
62 GTK_STYLE_CONTEXT_PRINT_SHOW_CHANGE);
63
64 g_main_context_wakeup (NULL);
65}
66
67static void
68load_ui_file (GFile *file, gboolean generate)
69{
70 GtkBuilder *builder;
71 GtkWidget *window;
72 char *output, *diff;
73 char *ui_file, *css_file, *reference_file;
74 GtkCssProvider *provider;
75 GError *error = NULL;
76
77 ui_file = g_file_get_path (file);
78
79 css_file = test_get_other_file (ui_file, extension: ".css");
80 g_assert_nonnull (css_file);
81
82 provider = gtk_css_provider_new ();
83 gtk_css_provider_load_from_path (css_provider: provider, path: css_file);
84 gtk_style_context_add_provider_for_display (display: gdk_display_get_default (),
85 GTK_STYLE_PROVIDER (provider),
86 GTK_STYLE_PROVIDER_PRIORITY_FORCE);
87
88 builder = gtk_builder_new_from_file (filename: ui_file);
89 window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
90 if (window == NULL)
91 window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
92
93 g_assert_nonnull (window);
94
95
96 output = NULL;
97 g_signal_connect (window, "map", G_CALLBACK (style_context_changed), &output);
98
99 gtk_widget_show (widget: window);
100
101 while (!output)
102 g_main_context_iteration (NULL, FALSE);
103
104 if (generate)
105 {
106 g_print (format: "%s", output);
107 goto out;
108 }
109
110 reference_file = test_get_other_file (ui_file, extension: ".nodes");
111
112 diff = diff_with_file (file1: reference_file, text: output, len: -1, error: &error);
113 g_assert_no_error (error);
114
115 if (diff && diff[0])
116 {
117 g_test_message (format: "Resulting output doesn't match reference:\n%s", diff);
118 g_test_fail ();
119 }
120 g_free (mem: reference_file);
121 g_free (mem: diff);
122
123out:
124 gtk_style_context_remove_provider_for_display (display: gdk_display_get_default (),
125 GTK_STYLE_PROVIDER (provider));
126 g_object_unref (object: provider);
127
128 g_free (mem: output);
129 g_free (mem: ui_file);
130 g_free (mem: css_file);
131}
132
133static void
134test_ui_file (GFile *file)
135{
136 load_ui_file (file, FALSE);
137}
138
139static void
140add_test_for_file (GFile *file)
141{
142 char *path;
143
144 path = g_file_get_path (file);
145
146 g_test_add_vtable (testpath: path,
147 data_size: 0,
148 g_object_ref (file),
149 NULL,
150 data_test: (GTestFixtureFunc) test_ui_file,
151 data_teardown: (GTestFixtureFunc) g_object_unref);
152
153 g_free (mem: path);
154}
155
156static int
157compare_files (gconstpointer a, gconstpointer b)
158{
159 GFile *file1 = G_FILE (a);
160 GFile *file2 = G_FILE (b);
161 char *path1, *path2;
162 int result;
163
164 path1 = g_file_get_path (file: file1);
165 path2 = g_file_get_path (file: file2);
166
167 result = strcmp (s1: path1, s2: path2);
168
169 g_free (mem: path1);
170 g_free (mem: path2);
171
172 return result;
173}
174
175static void
176add_tests_for_files_in_directory (GFile *dir)
177{
178 GFileEnumerator *enumerator;
179 GFileInfo *info;
180 GList *files;
181 GError *error = NULL;
182
183 enumerator = g_file_enumerate_children (file: dir, G_FILE_ATTRIBUTE_STANDARD_NAME, flags: 0, NULL, error: &error);
184 g_assert_no_error (error);
185 files = NULL;
186
187 while ((info = g_file_enumerator_next_file (enumerator, NULL, error: &error)))
188 {
189 const char *filename;
190
191 filename = g_file_info_get_name (info);
192
193 if (!g_str_has_suffix (str: filename, suffix: ".ui") ||
194 g_str_has_suffix (str: filename, suffix: ".nodes"))
195 {
196 g_object_unref (object: info);
197 continue;
198 }
199
200 files = g_list_prepend (list: files, data: g_file_get_child (file: dir, name: filename));
201
202 g_object_unref (object: info);
203 }
204
205 g_assert_no_error (error);
206 g_object_unref (object: enumerator);
207
208 files = g_list_sort (list: files, compare_func: compare_files);
209 g_list_foreach (list: files, func: (GFunc) add_test_for_file, NULL);
210 g_list_free_full (list: files, free_func: g_object_unref);
211}
212
213int
214main (int argc, char **argv)
215{
216 g_setenv (variable: "GTK_CSS_DEBUG", value: "1", TRUE);
217 g_setenv (variable: "GTK_THEME", value: "Empty", TRUE);
218 g_setenv (variable: "GSETTINGS_BACKEND", value: "memory", TRUE);
219
220 if (argc >= 3 && strcmp (s1: argv[1], s2: "--generate") == 0)
221 {
222 gtk_init ();
223
224 GFile *file = g_file_new_for_commandline_arg (arg: argv[2]);
225
226 load_ui_file (file, TRUE);
227
228 g_object_unref (object: file);
229
230 return 0;
231 }
232
233 gtk_test_init (argcp: &argc, argvp: &argv);
234
235 if (argc < 2)
236 {
237 const char *basedir;
238 GFile *dir;
239
240 basedir = g_test_get_dir (file_type: G_TEST_DIST);
241 dir = g_file_new_for_path (path: basedir);
242 add_tests_for_files_in_directory (dir);
243
244 g_object_unref (object: dir);
245 }
246 else
247 {
248 guint i;
249
250 for (i = 1; i < argc; i++)
251 {
252 GFile *file = g_file_new_for_commandline_arg (arg: argv[i]);
253
254 add_test_for_file (file);
255
256 g_object_unref (object: file);
257 }
258 }
259
260 return g_test_run ();
261}
262
263

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