1 #include "config.h"
2
3 #include <glib-object.h>
4 #include <dbus/dbus.h>
5 #include <dbus/dbus-glib.h>
6 #include <dbus/dbus-glib-lowlevel.h>
7
8 #include <telepathy-glib/dbus.h>
9 #include <telepathy-glib/dbus-properties-mixin.h>
10 #include <telepathy-glib/debug.h>
11 #include <telepathy-glib/proxy.h>
12 #include <telepathy-glib/svc-generic.h>
13 #include <telepathy-glib/util.h>
14
15 #include "_gen/svc.h"
16 #include "tests/lib/util.h"
17
18 #define WITH_PROPERTIES_IFACE "com.example.WithProperties"
19
20 typedef struct _TestProperties {
21 GObject parent;
22 } TestProperties;
23 typedef struct _TestPropertiesClass {
24 GObjectClass parent;
25 TpDBusPropertiesMixinClass props;
26 } TestPropertiesClass;
27
28 GType test_properties_get_type (void);
29
30 #define TEST_TYPE_PROPERTIES \
31 (test_properties_get_type ())
32 #define TEST_PROPERTIES(obj) \
33 (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_PROPERTIES, \
34 TestProperties))
35 #define TEST_PROPERTIES_CLASS(klass) \
36 (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_PROPERTIES, \
37 TestPropertiesClass))
38 #define TEST_IS_PROPERTIES(obj) \
39 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_PROPERTIES))
40 #define TEST_IS_PROPERTIES_CLASS(klass) \
41 (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_PROPERTIES))
42 #define TEST_PROPERTIES_GET_CLASS(obj) \
43 (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_PROPERTIES, \
44 TestPropertiesClass))
45
46 G_DEFINE_TYPE_WITH_CODE (TestProperties,
47 test_properties,
48 G_TYPE_OBJECT,
49 G_IMPLEMENT_INTERFACE (TEST_TYPE_SVC_WITH_PROPERTIES, NULL);
50 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
51 tp_dbus_properties_mixin_iface_init));
52
53 static void
test_properties_init(TestProperties * self)54 test_properties_init (TestProperties *self)
55 {
56 }
57
58 static void
prop_getter(GObject * object,GQuark interface,GQuark name,GValue * value,gpointer user_data)59 prop_getter (GObject *object,
60 GQuark interface,
61 GQuark name,
62 GValue *value,
63 gpointer user_data)
64 {
65 if (tp_strdiff (user_data, "read"))
66 g_assert_cmpstr (user_data, ==, "full-access");
67
68 g_value_set_uint (value, 42);
69 }
70
71 static gboolean
prop_setter(GObject * object,GQuark interface,GQuark name,const GValue * value,gpointer user_data,GError ** error)72 prop_setter (GObject *object,
73 GQuark interface,
74 GQuark name,
75 const GValue *value,
76 gpointer user_data,
77 GError **error)
78 {
79 g_assert (G_VALUE_HOLDS_UINT (value));
80
81 if (tp_strdiff (user_data, "FULL ACCESS"))
82 g_assert_cmpstr (user_data, ==, "BLACK HOLE");
83
84 g_assert_cmpuint (g_value_get_uint (value), ==, 57);
85 return TRUE;
86 }
87
88 static void
test_properties_class_init(TestPropertiesClass * cls)89 test_properties_class_init (TestPropertiesClass *cls)
90 {
91 static TpDBusPropertiesMixinPropImpl with_properties_props[] = {
92 { "ReadOnly", "read", "READ" },
93 { "ReadWrite", "full-access", "FULL ACCESS" },
94 { "WriteOnly", "black-hole", "BLACK HOLE" },
95 { NULL }
96 };
97 static TpDBusPropertiesMixinIfaceImpl interfaces[] = {
98 { WITH_PROPERTIES_IFACE, prop_getter, prop_setter,
99 with_properties_props },
100 { NULL }
101 };
102
103 cls->props.interfaces = interfaces;
104
105 tp_dbus_properties_mixin_class_init (G_OBJECT_CLASS (cls),
106 G_STRUCT_OFFSET (TestPropertiesClass, props));
107 }
108
109 static void
test_get(TpProxy * proxy)110 test_get (TpProxy *proxy)
111 {
112 GValue *value;
113
114 g_assert (tp_cli_dbus_properties_run_get (proxy, -1,
115 WITH_PROPERTIES_IFACE, "ReadOnly", &value, NULL, NULL));
116 g_assert (G_VALUE_HOLDS_UINT (value));
117 g_assert_cmpuint (g_value_get_uint (value), ==, 42);
118
119 g_boxed_free (G_TYPE_VALUE, value);
120 }
121
122 static void
test_set(TpProxy * proxy)123 test_set (TpProxy *proxy)
124 {
125 GValue value = { 0, };
126
127 g_value_init (&value, G_TYPE_UINT);
128 g_value_set_uint (&value, 57);
129
130 g_assert (tp_cli_dbus_properties_run_set (proxy, -1,
131 WITH_PROPERTIES_IFACE, "ReadWrite", &value, NULL, NULL));
132 g_assert (tp_cli_dbus_properties_run_set (proxy, -1,
133 WITH_PROPERTIES_IFACE, "WriteOnly", &value, NULL, NULL));
134
135 g_value_unset (&value);
136 }
137
138 static void
test_get_all(TpProxy * proxy)139 test_get_all (TpProxy *proxy)
140 {
141 GHashTable *hash;
142 GValue *value;
143
144 g_assert (tp_cli_dbus_properties_run_get_all (proxy, -1,
145 WITH_PROPERTIES_IFACE, &hash, NULL, NULL));
146 g_assert (hash != NULL);
147 tp_asv_dump (hash);
148 g_assert_cmpuint (g_hash_table_size (hash), ==, 2);
149
150 value = g_hash_table_lookup (hash, "WriteOnly");
151 g_assert (value == NULL);
152
153 value = g_hash_table_lookup (hash, "ReadOnly");
154 g_assert (value != NULL);
155 g_assert (G_VALUE_HOLDS_UINT (value));
156 g_assert_cmpuint (g_value_get_uint (value), ==, 42);
157
158 value = g_hash_table_lookup (hash, "ReadWrite");
159 g_assert (value != NULL);
160 g_assert (G_VALUE_HOLDS_UINT (value));
161 g_assert_cmpuint (g_value_get_uint (value), ==, 42);
162
163 g_hash_table_unref (hash);
164 }
165
166 static void
properties_changed_cb(TpProxy * proxy,const gchar * interface_name,GHashTable * changed_properties,const gchar ** invalidated_properties,gpointer user_data,GObject * weak_object)167 properties_changed_cb (
168 TpProxy *proxy,
169 const gchar *interface_name,
170 GHashTable *changed_properties,
171 const gchar **invalidated_properties,
172 gpointer user_data,
173 GObject *weak_object)
174 {
175 GMainLoop *loop = user_data;
176 guint value;
177 gboolean valid;
178
179 g_assert_cmpuint (g_hash_table_size (changed_properties), ==, 1);
180 value = tp_asv_get_uint32 (changed_properties, "ReadOnly", &valid);
181 g_assert (valid);
182 g_assert_cmpuint (value, ==, 42);
183
184 g_assert_cmpuint (g_strv_length ((gchar **) invalidated_properties), ==, 1);
185 g_assert_cmpstr (invalidated_properties[0], ==, "ReadWrite");
186
187 g_main_loop_quit (loop);
188 }
189
190 typedef struct {
191 TestProperties *obj;
192 TpProxy *proxy;
193 } Context;
194
195 static void
test_emit_changed(Context * ctx)196 test_emit_changed (Context *ctx)
197 {
198 GMainLoop *loop = g_main_loop_new (NULL, FALSE);
199 TpProxySignalConnection *signal_conn;
200 const gchar *properties[] = { "ReadOnly", "ReadWrite", NULL };
201 GError *error = NULL;
202
203 signal_conn = tp_cli_dbus_properties_connect_to_properties_changed (
204 ctx->proxy, properties_changed_cb, loop, NULL, NULL, &error);
205 g_assert_no_error (error);
206 g_assert (signal_conn != NULL);
207
208 tp_dbus_properties_mixin_emit_properties_changed (G_OBJECT (ctx->obj),
209 WITH_PROPERTIES_IFACE, properties);
210 g_main_loop_run (loop);
211
212 tp_dbus_properties_mixin_emit_properties_changed_varargs (G_OBJECT (ctx->obj),
213 WITH_PROPERTIES_IFACE, "ReadOnly", "ReadWrite", NULL);
214 g_main_loop_run (loop);
215
216 tp_proxy_signal_connection_disconnect (signal_conn);
217 }
218
219 int
main(int argc,char ** argv)220 main (int argc, char **argv)
221 {
222 Context ctx;
223 TpDBusDaemon *dbus_daemon;
224
225 tp_tests_init (&argc, &argv);
226
227 dbus_daemon = tp_tests_dbus_daemon_dup_or_die ();
228 ctx.obj = tp_tests_object_new_static_class (TEST_TYPE_PROPERTIES, NULL);
229 tp_dbus_daemon_register_object (dbus_daemon, "/", ctx.obj);
230
231 /* Open a D-Bus connection to myself */
232 ctx.proxy = TP_PROXY (tp_tests_object_new_static_class (TP_TYPE_PROXY,
233 "dbus-daemon", dbus_daemon,
234 "bus-name", tp_dbus_daemon_get_unique_name (dbus_daemon),
235 "object-path", "/",
236 NULL));
237
238 g_assert (tp_proxy_has_interface (ctx.proxy, "org.freedesktop.DBus.Properties"));
239
240 g_test_add_data_func ("/properties/get", ctx.proxy, (GTestDataFunc) test_get);
241 g_test_add_data_func ("/properties/set", ctx.proxy, (GTestDataFunc) test_set);
242 g_test_add_data_func ("/properties/get-all", ctx.proxy, (GTestDataFunc) test_get_all);
243
244 g_test_add_data_func ("/properties/changed", &ctx, (GTestDataFunc) test_emit_changed);
245
246 tp_tests_run_with_bus ();
247
248 g_object_unref (ctx.obj);
249 g_object_unref (ctx.proxy);
250 g_object_unref (dbus_daemon);
251
252 return 0;
253 }
254