1 /*
2 * extension-set.c
3 * This file is part of libpeas
4 *
5 * Copyright (C) 2010 - Garrett Regier
6 *
7 * libpeas is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * libpeas is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <libpeas/peas.h>
31
32 #include "testing/testing.h"
33
34 typedef struct _TestFixture TestFixture;
35
36 struct _TestFixture {
37 PeasEngine *engine;
38 };
39
40 /* Have dependencies before the plugin that requires them */
41 static const gchar *loadable_plugins[] = {
42 "loadable", "has-dep", "self-dep"
43 };
44
45 static void
extension_added_cb(PeasExtensionSet * extension_set,PeasPluginInfo * info,PeasExtension * extension,gint * active)46 extension_added_cb (PeasExtensionSet *extension_set,
47 PeasPluginInfo *info,
48 PeasExtension *extension,
49 gint *active)
50 {
51 ++(*active);
52 }
53
54 static void
extension_removed_cb(PeasExtensionSet * extension_set,PeasPluginInfo * info,PeasExtension * extension,gint * active)55 extension_removed_cb (PeasExtensionSet *extension_set,
56 PeasPluginInfo *info,
57 PeasExtension *extension,
58 gint *active)
59 {
60 --(*active);
61 }
62
63 static PeasExtensionSet *
testing_extension_set_new(PeasEngine * engine,gint * active)64 testing_extension_set_new (PeasEngine *engine,
65 gint *active)
66 {
67 gint i;
68 PeasPluginInfo *info;
69 PeasExtensionSet *extension_set;
70
71 extension_set = peas_extension_set_new (engine,
72 PEAS_TYPE_ACTIVATABLE,
73 "object", NULL,
74 NULL);
75
76 if (active == NULL)
77 {
78 active = g_new (gint, 1);
79 g_object_set_data_full (G_OBJECT (extension_set),
80 "testing-extension-set-active", active,
81 g_free);
82 }
83
84 *active = 0;
85
86 g_signal_connect (extension_set,
87 "extension-added",
88 G_CALLBACK (extension_added_cb),
89 active);
90 g_signal_connect (extension_set,
91 "extension-removed",
92 G_CALLBACK (extension_removed_cb),
93 active);
94
95 peas_extension_set_foreach (extension_set,
96 (PeasExtensionSetForeachFunc) extension_added_cb,
97 active);
98
99 for (i = 0; i < G_N_ELEMENTS (loadable_plugins); ++i)
100 {
101 g_assert_cmpint (*active, ==, i);
102
103 info = peas_engine_get_plugin_info (engine, loadable_plugins[i]);
104 g_assert (peas_engine_load_plugin (engine, info));
105 }
106
107 /* Load a plugin that does not provide a PeasActivatable */
108 info = peas_engine_get_plugin_info (engine, "extension-c");
109 g_assert (peas_engine_load_plugin (engine, info));
110
111 g_assert_cmpint (*active, ==, G_N_ELEMENTS (loadable_plugins));
112
113 return extension_set;
114 }
115
116 static void
test_setup(TestFixture * fixture,gconstpointer data)117 test_setup (TestFixture *fixture,
118 gconstpointer data)
119 {
120 fixture->engine = testing_engine_new ();
121 }
122
123 static void
test_teardown(TestFixture * fixture,gconstpointer data)124 test_teardown (TestFixture *fixture,
125 gconstpointer data)
126 {
127 testing_engine_free (fixture->engine);
128 }
129
130 static void
test_runner(TestFixture * fixture,gconstpointer data)131 test_runner (TestFixture *fixture,
132 gconstpointer data)
133 {
134 ((void (*) (PeasEngine *engine)) data) (fixture->engine);
135 }
136
137 static void
test_extension_set_create_valid(PeasEngine * engine)138 test_extension_set_create_valid (PeasEngine *engine)
139 {
140 PeasExtensionSet *extension_set;
141
142 extension_set = peas_extension_set_new (engine,
143 PEAS_TYPE_ACTIVATABLE,
144 "object", NULL,
145 NULL);
146
147 g_object_unref (extension_set);
148 }
149
150 static void
valid_extension_added_cb(PeasExtensionSet * extension_set,PeasPluginInfo * info,PeasExtension * extension,GObject ** obj_ptr)151 valid_extension_added_cb (PeasExtensionSet *extension_set,
152 PeasPluginInfo *info,
153 PeasExtension *extension,
154 GObject **obj_ptr)
155 {
156 g_object_get (PEAS_ACTIVATABLE (extension), "object", obj_ptr, NULL);
157 }
158
159 static void
test_extension_set_create_valid_with_properties(PeasEngine * engine)160 test_extension_set_create_valid_with_properties (PeasEngine *engine)
161 {
162 PeasPluginInfo *info;
163 PeasExtensionSet *extension_set;
164 GValue prop_value = G_VALUE_INIT;
165 GObject *obj, *obj_cmp;
166 const gchar *prop_names[1] = { "object" };
167
168 obj = g_object_new (G_TYPE_OBJECT, NULL);
169 g_value_init (&prop_value, G_TYPE_OBJECT);
170 g_value_set_object (&prop_value, obj);
171
172 extension_set = peas_extension_set_new_with_properties (engine,
173 PEAS_TYPE_ACTIVATABLE,
174 G_N_ELEMENTS (prop_names),
175 prop_names,
176 &prop_value);
177 g_signal_connect (extension_set,
178 "extension-added",
179 G_CALLBACK (valid_extension_added_cb),
180 &obj_cmp);
181 info = peas_engine_get_plugin_info (engine, "builtin");
182
183 g_assert (peas_engine_load_plugin (engine, info));
184 g_assert (obj == obj_cmp);
185
186 g_assert (PEAS_IS_EXTENSION_SET (extension_set));
187 g_object_unref (extension_set);
188 g_value_unset (&prop_value);
189 }
190
191
192 static void
test_extension_set_create_invalid(PeasEngine * engine)193 test_extension_set_create_invalid (PeasEngine *engine)
194 {
195 PeasExtensionSet *extension_set;
196
197 testing_util_push_log_hook ("*assertion*G_TYPE_IS_INTERFACE*failed");
198 testing_util_push_log_hook ("*type 'PeasActivatable' has no property named 'invalid-property'");
199
200 /* Invalid GType */
201 extension_set = peas_extension_set_new (engine, G_TYPE_INVALID, NULL);
202 g_assert (!PEAS_IS_EXTENSION_SET (extension_set));
203
204
205 /* GObject but not a GInterface */
206 extension_set = peas_extension_set_new (engine, G_TYPE_OBJECT, NULL);
207 g_assert (!PEAS_IS_EXTENSION_SET (extension_set));
208
209
210 /* Interface does not have an 'invalid-property' property */
211 extension_set = peas_extension_set_new (engine,
212 PEAS_TYPE_ACTIVATABLE,
213 "invalid-property", "does-not-exist",
214 NULL);
215 g_assert (!PEAS_IS_EXTENSION_SET (extension_set));
216 }
217
218 static void
test_extension_set_create_invalid_with_properties(PeasEngine * engine)219 test_extension_set_create_invalid_with_properties (PeasEngine *engine)
220 {
221 PeasExtensionSet *extension_set;
222 GValue prop_values[2] = { G_VALUE_INIT };
223 const gchar *prop_names[2] = { "object", NULL };
224 const gchar *prop_names_not_exist[1] = { "aleb" };
225 guint n_elements;
226
227 testing_util_push_log_hook ("*property name*should not be NULL.");
228 testing_util_push_log_hook ("*assertion*G_TYPE_IS_INTERFACE*failed");
229 testing_util_push_log_hook ("*should be an initialized GValue.");
230 testing_util_push_log_hook ("*has no property named 'aleb'*");
231
232 g_value_init (&prop_values[0], G_TYPE_POINTER);
233 g_value_set_pointer (&prop_values[0], NULL);
234
235 /* Interface has a NULL property name*/
236 n_elements = G_N_ELEMENTS (prop_values);
237 extension_set = peas_extension_set_new_with_properties (engine,
238 PEAS_TYPE_ACTIVATABLE,
239 n_elements,
240 prop_names,
241 prop_values);
242 g_assert (!PEAS_IS_EXTENSION_SET (extension_set));
243 g_value_unset (&prop_values[0]);
244
245 /* Invalid GType */
246 extension_set = peas_extension_set_new_with_properties (engine,
247 G_TYPE_INVALID,
248 0, NULL, NULL);
249 g_assert (!PEAS_IS_EXTENSION_SET (extension_set));
250
251 /* Uninitialized GValue */
252 n_elements = 1;
253 extension_set = peas_extension_set_new_with_properties (engine,
254 PEAS_TYPE_ACTIVATABLE,
255 n_elements,
256 prop_names,
257 prop_values);
258 g_assert (!PEAS_IS_EXTENSION_SET (extension_set));
259
260 /* Uninitialized GValue*/
261 g_value_init (&prop_values[0], G_TYPE_POINTER);
262 g_value_set_pointer (&prop_values[0], NULL);
263 n_elements = G_N_ELEMENTS (prop_names_not_exist);
264 extension_set = peas_extension_set_new_with_properties (engine,
265 PEAS_TYPE_ACTIVATABLE,
266 n_elements,
267 prop_names_not_exist,
268 prop_values);
269 g_assert (!PEAS_IS_EXTENSION_SET (extension_set));
270 g_value_unset (&prop_values[0]);
271 }
272
273
274 static void
test_extension_set_extension_added(PeasEngine * engine)275 test_extension_set_extension_added (PeasEngine *engine)
276 {
277 gint active;
278 PeasExtensionSet *extension_set;
279
280 /* This will check that an extension is added
281 * as plugins are loaded and cause active to
282 * be synced with the number of added extensions
283 */
284 extension_set = testing_extension_set_new (engine, &active);
285
286 g_object_unref (extension_set);
287
288 /* Verify that freeing the extension
289 * set causes the extensions to be removed
290 */
291 g_assert_cmpint (active, ==, 0);
292 }
293
294 static void
test_extension_set_extension_removed(PeasEngine * engine)295 test_extension_set_extension_removed (PeasEngine *engine)
296 {
297 gint i, active;
298 PeasPluginInfo *info;
299 PeasExtensionSet *extension_set;
300
301 extension_set = testing_extension_set_new (engine, &active);
302
303 /* Unload the plugin that does not provide a PeasActivatable */
304 info = peas_engine_get_plugin_info (engine, "extension-c");
305 g_assert (peas_engine_unload_plugin (engine, info));
306
307 /* To keep deps in order */
308 for (i = G_N_ELEMENTS (loadable_plugins); i > 0; --i)
309 {
310 g_assert_cmpint (active, ==, i);
311
312 info = peas_engine_get_plugin_info (engine, loadable_plugins[i - 1]);
313
314 g_assert (peas_engine_unload_plugin (engine, info));
315 }
316
317 g_assert_cmpint (active, ==, 0);
318
319 g_object_unref (extension_set);
320 }
321
322 static void
test_extension_set_get_extension(PeasEngine * engine)323 test_extension_set_get_extension (PeasEngine *engine)
324 {
325 PeasPluginInfo *info;
326 PeasExtension *extension;
327 PeasExtensionSet *extension_set;
328
329 extension_set = testing_extension_set_new (engine, NULL);
330 info = peas_engine_get_plugin_info (engine, loadable_plugins[0]);
331
332 extension = peas_extension_set_get_extension (extension_set, info);
333 g_assert (PEAS_IS_ACTIVATABLE (extension));
334
335 g_object_add_weak_pointer (G_OBJECT (extension),
336 (gpointer) &extension);
337 g_assert (peas_engine_unload_plugin (engine, info));
338
339 g_assert (extension == NULL);
340 g_assert (peas_extension_set_get_extension (extension_set, info) == NULL);
341
342 g_object_unref (extension_set);
343 }
344
345 static void
test_extension_set_call_valid(PeasEngine * engine)346 test_extension_set_call_valid (PeasEngine *engine)
347 {
348 PeasExtensionSet *extension_set;
349
350 extension_set = testing_extension_set_new (engine, NULL);
351
352 g_assert (peas_extension_set_call (extension_set, "activate", NULL));
353
354 g_object_unref (extension_set);
355 }
356
357 static void
test_extension_set_call_invalid(PeasEngine * engine)358 test_extension_set_call_invalid (PeasEngine *engine)
359 {
360 PeasExtensionSet *extension_set;
361
362 testing_util_push_log_hook ("Method 'PeasActivatable.invalid' was not found");
363
364 extension_set = testing_extension_set_new (engine, NULL);
365
366 g_assert (!peas_extension_set_call (extension_set, "invalid", NULL));
367
368 g_object_unref (extension_set);
369 }
370
371 static void
test_extension_set_foreach(PeasEngine * engine)372 test_extension_set_foreach (PeasEngine *engine)
373 {
374 gint count = 0;
375 PeasExtensionSet *extension_set;
376
377 extension_set = testing_extension_set_new (engine, NULL);
378
379 peas_extension_set_foreach (extension_set,
380 (PeasExtensionSetForeachFunc) extension_added_cb,
381 &count);
382
383 g_assert_cmpint (count, ==, G_N_ELEMENTS (loadable_plugins));
384
385 g_object_unref (extension_set);
386 }
387
388 static void
ordering_cb(PeasExtensionSet * set,PeasPluginInfo * info,PeasExtension * extension,GList ** order)389 ordering_cb (PeasExtensionSet *set,
390 PeasPluginInfo *info,
391 PeasExtension *extension,
392 GList **order)
393 {
394 const gchar *order_module_name = (const gchar *) (*order)->data;
395
396 g_assert_cmpstr (order_module_name, ==,
397 peas_plugin_info_get_module_name (info));
398 *order = g_list_delete_link (*order, *order);
399 }
400
401 static void
test_extension_set_ordering(PeasEngine * engine)402 test_extension_set_ordering (PeasEngine *engine)
403 {
404 guint i;
405 GList *foreach_order = NULL;
406 GList *dispose_order = NULL;
407 PeasExtensionSet *extension_set;
408
409 for (i = 0; i < G_N_ELEMENTS (loadable_plugins); ++i)
410 {
411 /* Use descriptive names to make an assert more informative */
412 foreach_order = g_list_append (foreach_order,
413 (gpointer) loadable_plugins[i]);
414 dispose_order = g_list_prepend (dispose_order,
415 (gpointer) loadable_plugins[i]);
416 }
417
418 extension_set = testing_extension_set_new (engine, NULL);
419
420 peas_extension_set_foreach (extension_set,
421 (PeasExtensionSetForeachFunc) ordering_cb,
422 &foreach_order);
423 g_assert (foreach_order == NULL);
424
425
426 g_signal_connect (extension_set,
427 "extension-removed",
428 G_CALLBACK (ordering_cb),
429 &dispose_order);
430 g_object_unref (extension_set);
431 g_assert (dispose_order == NULL);
432 }
433
434 int
main(int argc,char ** argv)435 main (int argc,
436 char **argv)
437 {
438 testing_init (&argc, &argv);
439
440 #define TEST(path, ftest) \
441 g_test_add ("/extension-set/" path, TestFixture, \
442 (gpointer) test_extension_set_##ftest, \
443 test_setup, test_runner, test_teardown)
444
445 TEST ("create-valid", create_valid);
446 TEST ("create-invalid", create_invalid);
447 TEST ("create-valid-with-properties", create_valid_with_properties);
448 TEST ("create-invalid-with-properties", create_invalid_with_properties);
449
450 TEST ("extension-added", extension_added);
451 TEST ("extension-removed", extension_removed);
452
453 TEST ("get-extension", get_extension);
454
455 TEST ("call-valid", call_valid);
456 TEST ("call-invalid", call_invalid);
457
458 TEST ("foreach", foreach);
459
460 TEST ("ordering", ordering);
461
462 #undef TEST
463
464 return testing_run_tests ();
465 }
466