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