1 | /* flags.c |
2 | * Copyright (C) 2018 Arthur Demchenkov |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General |
15 | * Public License along with this library; if not, see |
16 | * <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #include <glib-object.h> |
20 | |
21 | /* Check that validation of flags works on architectures where |
22 | * #gint and #glong are different sizes, as the flags are cast |
23 | * between types a few times. |
24 | * |
25 | * See: https://gitlab.gnome.org/GNOME/glib/issues/1572 |
26 | */ |
27 | |
28 | enum { |
29 | PROP_FLAGS = 1 |
30 | }; |
31 | |
32 | typedef struct _GTest GTest; |
33 | typedef struct _GTestClass GTestClass; |
34 | |
35 | typedef enum { |
36 | NO_FLAG = 0, |
37 | LOWEST_FLAG = 1, |
38 | HIGHEST_FLAG = 1 << 31 |
39 | } MyFlagsEnum; |
40 | |
41 | struct _GTest { |
42 | GObject object; |
43 | MyFlagsEnum flags; |
44 | }; |
45 | |
46 | struct _GTestClass { |
47 | GObjectClass parent_class; |
48 | }; |
49 | |
50 | static GType my_test_get_type (void); |
51 | static GType my_test_flags_get_type (void); |
52 | |
53 | #define G_TYPE_TEST (my_test_get_type()) |
54 | #define MY_TEST(test) (G_TYPE_CHECK_INSTANCE_CAST ((test), G_TYPE_TEST, GTest)) |
55 | G_DEFINE_TYPE (GTest, my_test, G_TYPE_OBJECT) |
56 | |
57 | static void my_test_class_init (GTestClass * klass); |
58 | static void my_test_init (GTest * test); |
59 | static void my_test_get_property (GObject *object, |
60 | guint prop_id, |
61 | GValue *value, |
62 | GParamSpec *pspec); |
63 | static void my_test_set_property (GObject *object, |
64 | guint prop_id, |
65 | const GValue *value, |
66 | GParamSpec *pspec); |
67 | |
68 | static GType |
69 | my_test_flags_get_type (void) |
70 | { |
71 | static GType flags_type = 0; |
72 | |
73 | if (G_UNLIKELY(flags_type == 0)) |
74 | { |
75 | static const GFlagsValue values[] = { |
76 | { LOWEST_FLAG, "LOWEST_FLAG" , "lowest" }, |
77 | { HIGHEST_FLAG, "HIGHEST_FLAG" , "highest" }, |
78 | { 0, NULL, NULL } |
79 | }; |
80 | |
81 | flags_type = g_flags_register_static (name: g_intern_static_string (string: "GTestFlags" ), const_static_values: values); |
82 | } |
83 | return flags_type; |
84 | } |
85 | |
86 | static void |
87 | my_test_class_init (GTestClass *klass) |
88 | { |
89 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
90 | |
91 | gobject_class->get_property = my_test_get_property; |
92 | gobject_class->set_property = my_test_set_property; |
93 | |
94 | g_object_class_install_property (oclass: gobject_class, property_id: 1, |
95 | pspec: g_param_spec_flags (name: "flags" , |
96 | nick: "Flags" , |
97 | blurb: "Flags test property" , |
98 | flags_type: my_test_flags_get_type(), default_value: 0, |
99 | flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
100 | } |
101 | |
102 | static void my_test_init (GTest *test) |
103 | { |
104 | } |
105 | |
106 | static void |
107 | my_test_get_property (GObject *object, |
108 | guint prop_id, |
109 | GValue *value, |
110 | GParamSpec *pspec) |
111 | { |
112 | GTest *test = MY_TEST (object); |
113 | |
114 | switch (prop_id) |
115 | { |
116 | case PROP_FLAGS: |
117 | g_value_set_flags (value, v_flags: test->flags); |
118 | break; |
119 | default: |
120 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
121 | break; |
122 | } |
123 | } |
124 | |
125 | static void |
126 | my_test_set_property (GObject *object, |
127 | guint prop_id, |
128 | const GValue *value, |
129 | GParamSpec *pspec) |
130 | { |
131 | GTest *test = MY_TEST (object); |
132 | |
133 | switch (prop_id) |
134 | { |
135 | case PROP_FLAGS: |
136 | test->flags = g_value_get_flags (value); |
137 | break; |
138 | default: |
139 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
140 | break; |
141 | } |
142 | } |
143 | |
144 | static void |
145 | check_flags_validation (void) |
146 | { |
147 | guint test_flags[] = { |
148 | NO_FLAG, |
149 | LOWEST_FLAG, |
150 | HIGHEST_FLAG, |
151 | LOWEST_FLAG | HIGHEST_FLAG |
152 | }; |
153 | guint flag_read; |
154 | gsize i; |
155 | |
156 | for (i = 0; i < G_N_ELEMENTS (test_flags); i++) |
157 | { |
158 | guint flag_set = test_flags[i]; |
159 | GObject *test = g_object_new (G_TYPE_TEST, |
160 | first_property_name: "flags" , flag_set, |
161 | NULL); |
162 | |
163 | g_object_get (object: test, first_property_name: "flags" , &flag_read, NULL); |
164 | |
165 | /* This check will fail in case of gint -> glong conversion |
166 | * in value_flags_enum_collect_value() */ |
167 | g_assert_cmpint (flag_read, ==, flag_set); |
168 | |
169 | g_object_unref (object: test); |
170 | } |
171 | } |
172 | |
173 | int |
174 | main (int argc, char **argv) |
175 | { |
176 | g_test_init (argc: &argc, argv: &argv, NULL); |
177 | g_test_add_func (testpath: "/gobject/flags/validate" , test_func: check_flags_validation); |
178 | return g_test_run (); |
179 | } |
180 | |