• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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