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
my_test_flags_get_type(void)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 (g_intern_static_string ("GTestFlags"), values);
82 }
83 return flags_type;
84 }
85
86 static void
my_test_class_init(GTestClass * klass)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 (gobject_class, 1,
95 g_param_spec_flags ("flags",
96 "Flags",
97 "Flags test property",
98 my_test_flags_get_type(), 0,
99 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
100 }
101
my_test_init(GTest * test)102 static void my_test_init (GTest *test)
103 {
104 }
105
106 static void
my_test_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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, 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
my_test_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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
check_flags_validation(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 "flags", flag_set,
161 NULL);
162
163 g_object_get (test, "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 (test);
170 }
171 }
172
173 int
main(int argc,char ** argv)174 main (int argc, char **argv)
175 {
176 g_test_init (&argc, &argv, NULL);
177 g_test_add_func ("/gobject/flags/validate", check_flags_validation);
178 return g_test_run ();
179 }
180