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
28enum {
29 PROP_FLAGS = 1
30};
31
32typedef struct _GTest GTest;
33typedef struct _GTestClass GTestClass;
34
35typedef enum {
36 NO_FLAG = 0,
37 LOWEST_FLAG = 1,
38 HIGHEST_FLAG = 1 << 31
39} MyFlagsEnum;
40
41struct _GTest {
42 GObject object;
43 MyFlagsEnum flags;
44};
45
46struct _GTestClass {
47 GObjectClass parent_class;
48};
49
50static GType my_test_get_type (void);
51static 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))
55G_DEFINE_TYPE (GTest, my_test, G_TYPE_OBJECT)
56
57static void my_test_class_init (GTestClass * klass);
58static void my_test_init (GTest * test);
59static void my_test_get_property (GObject *object,
60 guint prop_id,
61 GValue *value,
62 GParamSpec *pspec);
63static void my_test_set_property (GObject *object,
64 guint prop_id,
65 const GValue *value,
66 GParamSpec *pspec);
67
68static GType
69my_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
86static void
87my_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
102static void my_test_init (GTest *test)
103{
104}
105
106static void
107my_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
125static void
126my_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
144static void
145check_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
173int
174main (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

source code of gtk/subprojects/glib/gobject/tests/flags.c