]> Pileus Git - ~andy/gtk/blob - gtk/tests/stylecontext.c
More !srcdir fixes for the stylecontext test
[~andy/gtk] / gtk / tests / stylecontext.c
1 #include <gtk/gtk.h>
2
3 static void
4 test_parse_empty (void)
5 {
6   GtkCssProvider *provider;
7   GError *error;
8   gboolean res;
9
10   provider = gtk_css_provider_new ();
11   error = NULL;
12   res = gtk_css_provider_load_from_data (provider, "", -1, &error);
13
14   g_assert (res);
15   g_assert_no_error (error);
16   g_clear_error (&error);
17
18   g_object_unref (provider);
19 }
20
21 static void
22 test_parse_at (void)
23 {
24   GtkCssProvider *provider;
25   GError *error;
26   gboolean res;
27   gint i;
28   const gchar *valid[] = {
29     "@import \"" SRCDIR "/test.css\";",
30     "@import '" SRCDIR "/test.css';",
31     "@import url(\"" SRCDIR "/test.css\");",
32     "@import url('" SRCDIR "/test.css');",
33     "@import\nurl (\t\"" SRCDIR "/test.css\" ) ;",
34     "@define-color bg_color #f9a039;",
35     "@define-color color @bg_color;",
36     "@define-color color rgb(100, 99, 88);",
37     "@define-color color rgba(50%, 50%, 50%, 0.5);",
38     "@define-color color lighter(#f9a039);",
39     "@define-color color darker ( @blue ) ;",
40     "@define-color color shade(@blue, 1.3);",
41     "@define-color color alpha(@blue, 1.3);",
42     "@define-color color mix(@blue, @red, 0.2);",
43     "@define-color color red;",
44     "@define-color color mix(shade (#121212, 0.5), mix (rgb(10%,20%,100%), @blue,0.5), 0.2);",
45     "@define-color blue @blue;",
46     "@define-color blue123_a-b #123;",
47     NULL
48   };
49
50   const gchar *invalid[] = {
51     "@import " SRCDIR "/test.css ;",
52     "@import url ( \"" SRCDIR "/test.css\" xyz );",
53     "@import url(\");",
54     "@import url(');",
55     "@import url(\"abc');",
56     "@ import ;",
57     "@define_color blue  red;",
58     "@define-color blue #12234;",
59     "@define-color blue #12g234;",
60     "@define-color blue @@;",
61     "@define-color blue 5!#%4@DG$##x;",
62     "@define-color color mix(@red, @blue, @green);",
63     "@define-color color mix(@blue, 0.2, @red);",
64     "@define-color color mix(0.2, @blue, @red);",
65     "@define-color color mix(@blue, @red);",
66     "@define-color color mix(@blue);",
67     "@define-color color mix();",
68     "@define-color color rgba(50%, 50%, 50%);",
69     "@define-color color rgb(50%, a);",
70     "@define-color 1col rgb(50%, a);",
71     "@three-dee { some other crap };",
72     NULL
73   };
74
75   error = NULL;
76   for (i = 0; valid[i]; i++)
77     {
78       provider = gtk_css_provider_new ();
79       res = gtk_css_provider_load_from_data (provider, valid[i], -1, &error);
80       if (error)
81         g_print ("parsing '%s': got unexpected error: %s\n", valid[i], error->message);
82       g_assert_no_error (error);
83       g_assert (res);
84
85       g_object_unref (provider);
86    }
87
88   for (i = 0; invalid[i]; i++)
89     {
90       provider = gtk_css_provider_new ();
91       res = gtk_css_provider_load_from_data (provider, invalid[i], -1, &error);
92       g_assert_error (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_FAILED);
93       g_assert (!res);
94       g_object_unref (provider);
95       g_clear_error (&error);
96    }
97 }
98
99 static void
100 test_parse_selectors (void)
101 {
102   GtkCssProvider *provider;
103   GError *error;
104   gboolean res;
105   gint i;
106   const gchar *valid[] = {
107     "* {}",
108     "E {}",
109     "E F {}",
110     "E > F {}",
111     "E#id {}",
112     "#id {}",
113     "tab:first-child {}",
114     "tab:last-child {}",
115     "tab:nth-child(first) {}",
116     "tab:nth-child(last) {}",
117     "tab:nth-child(even) {}",
118     "tab:nth-child(odd) {}",
119     "tab:sorted {}",
120     ".some-class {}",
121     ".some-class.another-class {}",
122     ".some-class .another-class {}",
123     "E * {}",
124     "E .class {}",
125     "E > .foo {}",
126     "E > #id {}",
127     "E:active {}",
128     "E:prelight {}",
129     "E:hover {}",
130     "E:selected {}",
131     "E:insensitive {}",
132     "E:inconsistent {}",
133     "E:focused {}",
134     "E:active:prelight {}",
135     "* > .notebook tab:first-child .label:focused {}",
136     "E, F {}",
137     "E, F /* comment here */ {}",
138     "E,/* comment here */ F {}",
139     "E1.e1_2 #T3_4 {}",
140     NULL
141   };
142
143   const gchar *invalid[] = {
144     /* nth-child and similar pseudo classes can only
145      * be used with regions, not with types
146      */
147     "E:first-child {}",
148     "E:last-child {}",
149     "E:nth-child(first) {}",
150     "E:nth-child(last) {}",
151     "E:nth-child(even) {}",
152     "E:nth-child(odd) {}",
153     "E:sorted {}",
154     /* widget state pseudo-classes can only be used for
155      * the last element
156      */
157     "E:focused tab {}",
158      NULL
159   };
160
161   error = NULL;
162   for (i = 0; valid[i]; i++)
163     {
164       provider = gtk_css_provider_new ();
165       res = gtk_css_provider_load_from_data (provider, valid[i], -1, &error);
166       g_assert_no_error (error);
167       g_assert (res);
168
169       g_object_unref (provider);
170    }
171
172   for (i = 0; invalid[i]; i++)
173     {
174       provider = gtk_css_provider_new ();
175       res = gtk_css_provider_load_from_data (provider, invalid[i], -1, &error);
176       g_assert_error (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_FAILED);
177       g_assert (!res);
178       g_object_unref (provider);
179       g_clear_error (&error);
180    }
181 }
182
183 static void
184 test_parse_declarations (void)
185 {
186   GtkCssProvider *provider;
187   GError *error;
188   gboolean res;
189   gint i;
190   const gchar *valid[] = {
191     "* {}",
192     "* { font: Sans 15 }",
193     "* { font: Sans 15; }",
194     "* { font: bold }",
195     "* { color: red }",
196     "* { /* just a comment */ }",
197     "* { /* multi\nline\ncomment */ }",
198     "* { font: /* comment here */ Sans 15 }",
199     "* { color: red; background-color: shade (@bg_color, 0.5) }",
200     "* { margin: 5 }",
201     "* { margin: 5 10 }",
202     "* { margin: 5 10 3 }",
203     "* { margin: 5 10 3 5 }",
204     "* { padding: 5 }",
205     "* { padding: 5 10 }",
206     "* { border-width: 5; border-radius: 10 }",
207     "* { border-color: #ff00ff }",
208     "* { engine: clearlooks }",
209     "* { background-image: -gtk-gradient (linear,               \n"
210     "                                    left top, right top,   \n"
211     "                                    from (#fff), to (#000)) }",
212     "* { background-image: -gtk-gradient (linear,               \n"
213     "                                    0.0 0.5, 0.5 1.0,      \n"
214     "                                    from (#fff),           \n"
215     "                                    color-stop (0.5, #f00),\n"
216     "                                    to (#000))              }",
217     "* { background-image: -gtk-gradient (radial,               \n"
218     "                                     center center, 0.2,   \n"
219     "                                     center center, 0.8,   \n"
220     "                                     color-stop (0.0,#fff),\n"
221     "                                     color-stop (1.0,#000))}\n",
222     "* { border-image: url (\"" SRCDIR "/test.png\") 3 4 3 4 stretch       }",
223     "* { border-image: url (\"" SRCDIR "/test.png\") 3 4 3 4 repeat stretch}",
224     "* { transition: 150ms ease-in-out                          }",
225     "* { transition: 1s linear loop                             }",
226     NULL
227   };
228
229   const gchar *invalid[] = {
230     "* { color }",
231     "* { color:green; color }",
232     "* { color:red; color; color:green }",
233     "* { color:green; color: }",
234     "* { color:red; color:; color:green }",
235     "* { color:green; color{;color:maroon} }",
236     "* { color:red; color{;color:maroon}; color:green }",
237     "* { content: 'Hello",
238     NULL
239   };
240
241   error = NULL;
242   for (i = 0; valid[i]; i++)
243     {
244       provider = gtk_css_provider_new ();
245       res = gtk_css_provider_load_from_data (provider, valid[i], -1, &error);
246       g_assert_no_error (error);
247       g_assert (res);
248
249       g_object_unref (provider);
250    }
251
252   for (i = 0; invalid[i]; i++)
253     {
254       provider = gtk_css_provider_new ();
255       res = gtk_css_provider_load_from_data (provider, invalid[i], -1, &error);
256       g_assert_error (error, GTK_CSS_PROVIDER_ERROR, GTK_CSS_PROVIDER_ERROR_FAILED);
257       g_assert (!res);
258       g_object_unref (provider);
259       g_clear_error (&error);
260    }
261 }
262
263 static void
264 test_path (void)
265 {
266   GtkWidgetPath *path;
267   GtkWidgetPath *path2;
268   gint pos;
269   GtkRegionFlags flags;
270
271   path = gtk_widget_path_new ();
272   g_assert_cmpint (gtk_widget_path_length (path), ==, 0);
273
274   pos = gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
275   g_assert_cmpint (pos, ==, 0);
276   g_assert_cmpint (gtk_widget_path_length (path), ==, 1);
277   g_assert (gtk_widget_path_iter_get_widget_type (path, 0) == GTK_TYPE_WINDOW);
278   g_assert (gtk_widget_path_is_type (path, GTK_TYPE_WIDGET));
279   g_assert (gtk_widget_path_iter_get_name (path, 0) == NULL);
280
281   pos = gtk_widget_path_append_type (path, GTK_TYPE_WIDGET);
282   g_assert_cmpint (pos, ==, 1);
283   g_assert_cmpint (gtk_widget_path_length (path), ==, 2);
284   gtk_widget_path_iter_set_widget_type (path, pos, GTK_TYPE_BUTTON);
285   g_assert (gtk_widget_path_is_type (path, GTK_TYPE_BUTTON));
286   g_assert (gtk_widget_path_has_parent (path, GTK_TYPE_WIDGET));
287   g_assert (gtk_widget_path_has_parent (path, GTK_TYPE_WINDOW));
288   g_assert (!gtk_widget_path_has_parent (path, GTK_TYPE_DIALOG));
289   g_assert (gtk_widget_path_iter_get_name (path, 1) == NULL);
290
291   gtk_widget_path_iter_set_name (path, 1, "name");
292   g_assert (gtk_widget_path_iter_has_name (path, 1, "name"));
293
294   gtk_widget_path_iter_add_class (path, 1, "class1");
295   gtk_widget_path_iter_add_class (path, 1, "class2");
296   g_assert (gtk_widget_path_iter_has_class (path, 1, "class1"));
297   g_assert (gtk_widget_path_iter_has_class (path, 1, "class2"));
298   g_assert (!gtk_widget_path_iter_has_class (path, 1, "class3"));
299
300   path2 = gtk_widget_path_copy (path);
301   g_assert (gtk_widget_path_iter_has_class (path2, 1, "class1"));
302   g_assert (gtk_widget_path_iter_has_class (path2, 1, "class2"));
303   g_assert (!gtk_widget_path_iter_has_class (path2, 1, "class3"));
304   gtk_widget_path_free (path2);
305
306   gtk_widget_path_iter_remove_class (path, 1, "class2");
307   g_assert (gtk_widget_path_iter_has_class (path, 1, "class1"));
308   g_assert (!gtk_widget_path_iter_has_class (path, 1, "class2"));
309   gtk_widget_path_iter_clear_classes (path, 1);
310   g_assert (!gtk_widget_path_iter_has_class (path, 1, "class1"));
311
312   gtk_widget_path_iter_add_region (path, 1, "tab", 0);
313   gtk_widget_path_iter_add_region (path, 1, "title", GTK_REGION_EVEN | GTK_REGION_FIRST);
314
315   g_assert (gtk_widget_path_iter_has_region (path, 1, "tab", &flags) &&
316             flags == 0);
317   g_assert (gtk_widget_path_iter_has_region (path, 1, "title", &flags) &&
318             flags == (GTK_REGION_EVEN | GTK_REGION_FIRST));
319   g_assert (!gtk_widget_path_iter_has_region (path, 1, "extension", NULL));
320
321   path2 = gtk_widget_path_copy (path);
322   g_assert (gtk_widget_path_iter_has_region (path2, 1, "tab", &flags) &&
323             flags == 0);
324   g_assert (gtk_widget_path_iter_has_region (path2, 1, "title", &flags) &&
325             flags == (GTK_REGION_EVEN | GTK_REGION_FIRST));
326   g_assert (!gtk_widget_path_iter_has_region (path2, 1, "extension", NULL));
327   gtk_widget_path_free (path2);
328
329   gtk_widget_path_free (path);
330 }
331
332 static void
333 test_match (void)
334 {
335   GtkStyleContext *context;
336   GtkWidgetPath *path;
337   GtkCssProvider *provider;
338   GError *error;
339   const gchar *data;
340   GdkRGBA *color;
341   GdkRGBA expected;
342
343   error = NULL;
344   provider = gtk_css_provider_new ();
345
346   gdk_rgba_parse (&expected, "#fff");
347
348   context = gtk_style_context_new ();
349
350   path = gtk_widget_path_new ();
351   gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
352   gtk_widget_path_append_type (path, GTK_TYPE_BOX);
353   gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
354   gtk_widget_path_iter_set_name (path, 0, "mywindow");
355   gtk_widget_path_iter_add_class (path, 2, "button");
356   gtk_style_context_set_path (context, path);
357   gtk_widget_path_free (path);
358
359   gtk_style_context_add_provider (context,
360                                   GTK_STYLE_PROVIDER (provider),
361                                   GTK_STYLE_PROVIDER_PRIORITY_USER);
362
363   data = "* { color: #fff }";
364   gtk_css_provider_load_from_data (provider, data, -1, &error);
365   g_assert_no_error (error);
366   gtk_style_context_invalidate (context);
367   gtk_style_context_get (context, 0, "color", &color, NULL);
368   g_assert (gdk_rgba_equal (color, &expected));
369   gdk_rgba_free (color);
370
371   data = "* { color: #f00 }\n"
372          "GtkButton { color: #fff }";
373   gtk_css_provider_load_from_data (provider, data, -1, &error);
374   g_assert_no_error (error);
375   gtk_style_context_invalidate (context);
376   gtk_style_context_get (context, 0, "color", &color, NULL);
377   g_assert (gdk_rgba_equal (color, &expected));
378   gdk_rgba_free (color);
379
380   data = "* { color: #f00 }\n"
381          "GtkButton { color: #fff }\n"
382          "GtkWindow > GtkButton { color: #000 }";
383   gtk_css_provider_load_from_data (provider, data, -1, &error);
384   g_assert_no_error (error);
385   gtk_style_context_invalidate (context);
386   gtk_style_context_get (context, 0, "color", &color, NULL);
387   g_assert (gdk_rgba_equal (color, &expected));
388   gdk_rgba_free (color);
389
390   data = "* { color: #f00 }\n"
391          ".button { color: #fff }";
392   gtk_css_provider_load_from_data (provider, data, -1, &error);
393   g_assert_no_error (error);
394   gtk_style_context_invalidate (context);
395   gtk_style_context_get (context, 0, "color", &color, NULL);
396   g_assert (gdk_rgba_equal (color, &expected));
397   gdk_rgba_free (color);
398
399   data = "* { color: #f00 }\n"
400          "GtkButton { color: #000 }\n"
401          ".button { color: #fff }";
402   gtk_css_provider_load_from_data (provider, data, -1, &error);
403   g_assert_no_error (error);
404   gtk_style_context_invalidate (context);
405   gtk_style_context_get (context, 0, "color", &color, NULL);
406   g_assert (gdk_rgba_equal (color, &expected));
407   gdk_rgba_free (color);
408
409   data = "* { color: #f00 }\n"
410          "GtkButton { color: #000 }\n"
411          "GtkWindow GtkButton { color: #fff }";
412   gtk_css_provider_load_from_data (provider, data, -1, &error);
413   g_assert_no_error (error);
414   gtk_style_context_invalidate (context);
415   gtk_style_context_get (context, 0, "color", &color, NULL);
416   g_assert (gdk_rgba_equal (color, &expected));
417   gdk_rgba_free (color);
418
419   data = "* { color: #f00 }\n"
420          ".button { color: #000 }\n"
421          "GtkWindow .button { color: #fff }";
422   gtk_css_provider_load_from_data (provider, data, -1, &error);
423   g_assert_no_error (error);
424   gtk_style_context_invalidate (context);
425   gtk_style_context_get (context, 0, "color", &color, NULL);
426   g_assert (gdk_rgba_equal (color, &expected));
427   gdk_rgba_free (color);
428
429   data = "* { color: #f00 }\n"
430          "* .button { color: #000 }\n"
431          "#mywindow .button { color: #fff }";
432   gtk_css_provider_load_from_data (provider, data, -1, &error);
433   g_assert_no_error (error);
434   gtk_style_context_invalidate (context);
435   gtk_style_context_get (context, 0, "color", &color, NULL);
436   g_assert (gdk_rgba_equal (color, &expected));
437   gdk_rgba_free (color);
438
439   data = "* { color: #f00 }\n"
440          "GtkWindow .button { color: #000 }\n"
441          "GtkWindow#mywindow .button { color: #fff }";
442   gtk_css_provider_load_from_data (provider, data, -1, &error);
443   g_assert_no_error (error);
444   gtk_style_context_invalidate (context);
445   gtk_style_context_get (context, 0, "color", &color, NULL);
446   g_assert (gdk_rgba_equal (color, &expected));
447   gdk_rgba_free (color);
448
449   data = "* { color: #f00 }\n"
450          "GtkWindow .button { color: #fff }\n"
451          "GObject .button { color: #000 }";
452   gtk_css_provider_load_from_data (provider, data, -1, &error);
453   g_assert_no_error (error);
454   gtk_style_context_invalidate (context);
455   gtk_style_context_get (context, 0, "color", &color, NULL);
456   g_assert (gdk_rgba_equal (color, &expected));
457   gdk_rgba_free (color);
458
459   g_object_unref (provider);
460   g_object_unref (context);
461 }
462
463 static void
464 test_style_property (void)
465 {
466   GtkStyleContext *context;
467   GtkWidgetPath *path;
468   GtkCssProvider *provider;
469   GError *error;
470   const gchar *data;
471   gint x;
472   GdkRGBA *color;
473   GdkRGBA expected;
474
475   error = NULL;
476   provider = gtk_css_provider_new ();
477
478   context = gtk_style_context_new ();
479
480   path = gtk_widget_path_new ();
481   gtk_widget_path_append_type (path, GTK_TYPE_WINDOW);
482   gtk_widget_path_append_type (path, GTK_TYPE_BOX);
483   gtk_widget_path_append_type (path, GTK_TYPE_BUTTON);
484   gtk_style_context_set_path (context, path);
485   gtk_widget_path_free (path);
486   gtk_style_context_set_state (context, GTK_STATE_FLAG_PRELIGHT);
487
488   /* Since we set the prelight state on the context, we expect
489    * only the third selector to match, even though the second one
490    * has higher specificity, and the fourth one comes later.
491    *
492    * In particular, we want to verify that widget style properties and
493    * CSS properties follow the same matching rules, ie we expect
494    * color to be #003 and child-displacement-x to be 3.
495    */
496   data = "GtkButton:insensitive { color: #001; -GtkButton-child-displacement-x: 1 }\n"
497          "GtkBox GtkButton:selected { color: #002; -GtkButton-child-displacement-x: 2 }\n"
498          "GtkButton:prelight { color: #003; -GtkButton-child-displacement-x: 3 }\n"
499          "GtkButton:focused { color: #004; -GtkButton-child-displacement-x: 4 }\n";
500   gtk_css_provider_load_from_data (provider, data, -1, &error);
501   g_assert_no_error (error);
502   gtk_style_context_add_provider (context,
503                                   GTK_STYLE_PROVIDER (provider),
504                                   GTK_STYLE_PROVIDER_PRIORITY_USER);
505
506   gtk_style_context_invalidate (context);
507
508   gtk_style_context_get (context, GTK_STATE_FLAG_PRELIGHT, "color", &color, NULL);
509   gdk_rgba_parse (&expected, "#003");
510   g_assert (gdk_rgba_equal (color, &expected));
511   gdk_rgba_free (color);
512
513   gtk_style_context_get_style (context, "child-displacement-x", &x, NULL);
514
515   g_assert_cmpint (x, ==, 3);
516
517   g_object_unref (provider);
518   g_object_unref (context);
519 }
520
521 int
522 main (int argc, char *argv[])
523 {
524   gtk_init (NULL, NULL);
525   g_test_init (&argc, &argv, NULL);
526
527   g_test_add_func ("/style/parse/empty", test_parse_empty);
528   g_test_add_func ("/style/parse/at", test_parse_at);
529   g_test_add_func ("/style/parse/selectors", test_parse_selectors);
530   g_test_add_func ("/style/parse/declarations", test_parse_declarations);
531   g_test_add_func ("/style/path", test_path);
532   g_test_add_func ("/style/match", test_match);
533   g_test_add_func ("/style/style-property", test_style_property);
534
535   return g_test_run ();
536 }