diff options
author | Havoc Pennington <hp@pobox.com> | 1999-10-12 05:54:29 +0000 |
---|---|---|
committer | Havoc Pennington <hp@src.gnome.org> | 1999-10-12 05:54:29 +0000 |
commit | a1725faf5cc0d24404598bab793a953f894c9bc1 (patch) | |
tree | ad19336eae37536878809504b921d11104d1a0ed | |
parent | 595e9d4475e42116294afa1e0905c590a571b1e5 (diff) | |
download | gconf-a1725faf5cc0d24404598bab793a953f894c9bc1.tar.gz |
Was failing to init the node in the flat array of nodes if the listener
1999-10-12 Havoc Pennington <hp@pobox.com>
* gconf/gconf-listeners.c (ltable_insert): Was failing to
init
the node in the flat array of nodes if the listener location
was NULL.
(gconf_listeners_count): new function reports number
of listeners
(ltable_new): init next_cnxn to 1 instead of 0
(ltable_remove): Do a better job of cleaning up dead
tree nodes (go up looking for empty parent nodes)
(ltable_destroy): type error, was calling
listener_destroy()
on the GNodes. Oops. fixed, now use g_node_traverse() to
destroy the node contents.
(ltable_new): don't create the root node until it's needed
(ltable_insert): add root node here if needed
(ltable_remove): zero lt->tree if we
destroy it
* tests/testlisteners.c: New test program for GConfListeners,
fairly comprehensive
* tests/Makefile.am: add testlisteners, put
EFENCE at the end of
the link line
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | gconf/gconf-listeners.c | 163 | ||||
-rw-r--r-- | gconf/gconf-listeners.h | 5 | ||||
-rw-r--r-- | tests/Makefile.am | 11 | ||||
-rw-r--r-- | tests/testlisteners.c | 560 |
5 files changed, 720 insertions, 41 deletions
@@ -1,4 +1,26 @@ 1999-10-12 Havoc Pennington <hp@pobox.com> + + * gconf/gconf-listeners.c (ltable_insert): Was failing to init + the node in the flat array of nodes if the listener location + was NULL. + (gconf_listeners_count): new function reports number of listeners + (ltable_new): init next_cnxn to 1 instead of 0 + (ltable_remove): Do a better job of cleaning up dead + tree nodes (go up looking for empty parent nodes) + (ltable_destroy): type error, was calling listener_destroy() + on the GNodes. Oops. fixed, now use g_node_traverse() to + destroy the node contents. + (ltable_new): don't create the root node until it's needed + (ltable_insert): add root node here if needed + (ltable_remove): zero lt->tree if we destroy it + + * tests/testlisteners.c: New test program for GConfListeners, + fairly comprehensive + + * tests/Makefile.am: add testlisteners, put EFENCE at the end of + the link line + +1999-10-12 Havoc Pennington <hp@pobox.com> * gconf/Makefile.am: Fixes - remove some public headers from libgconf_client_SOURCES, look for GConf.idl in $(srcdir) (bug from diff --git a/gconf/gconf-listeners.c b/gconf/gconf-listeners.c index 83844250..5de75852 100644 --- a/gconf/gconf-listeners.c +++ b/gconf/gconf-listeners.c @@ -18,6 +18,12 @@ */ #include "gconf-listeners.h" +#include "gconf.h" + +/* #define DEBUG_LISTENERS 1 */ +#ifdef DEBUG_LISTENERS +#include <stdio.h> +#endif typedef struct _Listener Listener; @@ -68,7 +74,7 @@ static void ltable_notify(LTable* ltable, static guint ltable_next_cnxn(LTable* ltable); -#if 0 +#ifdef DEBUG_LISTENERS static void ltable_spew(LTable* ltable); #endif @@ -122,18 +128,28 @@ gconf_listeners_remove (GConfListeners* listeners, { LTable* lt = (LTable*)listeners; + g_return_if_fail(cnxn_id > 0); + ltable_remove(lt, cnxn_id); } void gconf_listeners_notify (GConfListeners* listeners, - const gchar* all_below, + const gchar* all_above, GConfListenersCallback callback, gpointer user_data) { LTable* lt = (LTable*)listeners; - ltable_notify(lt, all_below, callback, user_data); + ltable_notify(lt, all_above, callback, user_data); +} + +guint +gconf_listeners_count (GConfListeners* listeners) +{ + LTable* lt = (LTable*)listeners; + + return lt->active_listeners; } /* @@ -165,23 +181,20 @@ static LTable* ltable_new(void) { LTable* lt; - LTableEntry* lte; lt = g_new0(LTable, 1); lt->listeners = g_ptr_array_new(); - /* Set initial size and init error value (0) to NULL */ + /* Set initial size; note that GPtrArray's are initialized + to 0-filled */ g_ptr_array_set_size(lt->listeners, 5); - g_ptr_array_index(lt->listeners, 0) = NULL; - - lte = ltable_entry_new("/"); - - lt->tree = g_node_new(lte); - + lt->active_listeners = 0; lt->removed_cnxns = NULL; + + lt->next_cnxn = 1; /* 0 is invalid */ return lt; } @@ -214,6 +227,17 @@ ltable_insert(LTable* lt, const gchar* where, Listener* l) LTableEntry* lte; const gchar* noroot_where = where + 1; + g_return_if_fail(gconf_valid_key(where, NULL)); + + if (lt->tree == NULL) + { + lte = ltable_entry_new("/"); + + lt->tree = g_node_new(lte); + + lte = NULL; /* paranoia */ + } + /* Add to the tree */ dirnames = g_strsplit(noroot_where, "/", -1); @@ -280,10 +304,16 @@ ltable_insert(LTable* lt, const gchar* where, Listener* l) g_strfreev(dirnames); /* Add tree node to the flat table */ - g_ptr_array_set_size(lt->listeners, lt->next_cnxn); - g_ptr_array_index(lt->listeners, l->cnxn) = found; + g_ptr_array_set_size(lt->listeners, MAX(lt->next_cnxn, l->cnxn)); + g_ptr_array_index(lt->listeners, l->cnxn) = cur; lt->active_listeners += 1; + +#ifdef DEBUG_LISTENERS + printf("Added %u at %s, spewing:\n", + l->cnxn, where); + ltable_spew(lt); +#endif } static void @@ -305,6 +335,8 @@ ltable_remove(LTable* lt, guint cnxn) if (node == NULL) return; + g_assert(lt->tree != NULL); + lte = node->data; tmp = lte->listeners; @@ -342,40 +374,74 @@ ltable_remove(LTable* lt, guint cnxn) tmp = g_list_next(tmp); } - + + /* note that tmp is invalid, but should be nonzero */ g_return_if_fail(tmp != NULL); /* Remove from the tree if this node is now pointless */ - if (lte->listeners == NULL && node->children == NULL) { - ltable_entry_destroy(lte); - g_node_destroy(node); + GNode* cur = node; + while (cur != NULL) + { + GNode* parent = cur->parent; + lte = cur->data; + if (lte->listeners == NULL && cur->children == NULL) + { + if (cur == lt->tree) + lt->tree = NULL; + + ltable_entry_destroy(lte); + g_node_destroy(cur); + } + else + break; /* don't delete more parents since this node exists */ + + cur = parent; + } } lt->active_listeners -= 1; + +#ifdef DEBUG_LISTENERS + printf("Removed %u, spewing:\n", cnxn); + ltable_spew(lt); +#endif } -static void -ltable_destroy(LTable* ltable) +static gboolean +destroy_func(GNode* node, gpointer data) { - guint i; - - i = ltable->listeners->len - 1; + LTableEntry* lte = node->data; + GList* tmp; - while (i > 0) /* 0 position in array is invalid */ + tmp = lte->listeners; + while (tmp != NULL) { - if (g_ptr_array_index(ltable->listeners, i) != NULL) - { - listener_destroy(g_ptr_array_index(ltable->listeners, i)); - g_ptr_array_index(ltable->listeners, i) = NULL; - } + Listener* l = tmp->data; - --i; + listener_destroy(l); + + tmp = g_list_next(tmp); } + g_list_free(lte->listeners); + lte->listeners = NULL; - g_ptr_array_free(ltable->listeners, TRUE); + ltable_entry_destroy(lte); + + return FALSE; +} - g_node_destroy(ltable->tree); +static void +ltable_destroy(LTable* ltable) +{ + if (ltable->tree != NULL) + { + g_node_traverse(ltable->tree, G_POST_ORDER, G_TRAVERSE_ALL, -1, + destroy_func, NULL); + g_node_destroy(ltable->tree); + } + + g_ptr_array_free(ltable->listeners, TRUE); g_slist_free(ltable->removed_cnxns); @@ -392,7 +458,7 @@ notify_listener_list(GConfListeners* listeners, GList* list, const gchar* key, G { Listener* l = tmp->data; - (*callback)(listeners, l->cnxn, l->listener_data, user_data); + (*callback)(listeners, key, l->cnxn, l->listener_data, user_data); tmp = g_list_next(tmp); } @@ -410,6 +476,10 @@ ltable_notify(LTable* lt, const gchar* key, noroot_key = key + 1; g_return_if_fail(*key == '/'); + g_return_if_fail(gconf_valid_key(key, NULL)); + + if (lt->tree == NULL) + return; /* no one to notify */ /* Notify "/" listeners */ notify_listener_list((GConfListeners*)lt, @@ -470,32 +540,51 @@ ltable_entry_destroy(LTableEntry* lte) g_free(lte); } -#if 0 +#ifdef DEBUG_LISTENERS /* Debug */ gboolean spew_func(GNode* node, gpointer data) { LTableEntry* lte = node->data; GList* tmp; + gchar spaces[256]; + memset(spaces, ' ', 256); + spaces[g_node_depth(node)] = '\0'; - gconf_log(GCL_DEBUG, " Spewing node `%s'", lte->name); + + printf(" %sSpewing node `%s' (%p): ", spaces, lte->name, node); tmp = lte->listeners; while (tmp != NULL) { Listener* l = tmp->data; - - gconf_log(GCL_DEBUG, " listener %u is here", (guint)l->cnxn); + + printf(" %slistener %u is here\n", spaces, (guint)l->cnxn); tmp = g_list_next(tmp); } + if (lte->listeners == NULL) + printf("\n"); + return FALSE; } static void ltable_spew(LTable* lt) { - g_node_traverse(lt->tree, G_LEVEL_ORDER, G_TRAVERSE_ALL, -1, spew_func, NULL); + guint i; + printf("Flat table:\n"); + i = 0; + while (i < lt->listeners->len) + { + GNode* node = g_ptr_array_index(lt->listeners, i); + LTableEntry* lte = node ? node->data : NULL; + printf("%u `%s' %p\n", i, lte ? lte->name : "", node); + + ++i; + } + + g_node_traverse(lt->tree, G_PRE_ORDER, G_TRAVERSE_ALL, -1, spew_func, NULL); } #endif diff --git a/gconf/gconf-listeners.h b/gconf/gconf-listeners.h index 6eb0f046..0917a5a4 100644 --- a/gconf/gconf-listeners.h +++ b/gconf/gconf-listeners.h @@ -41,6 +41,7 @@ struct _GConfListeners { }; typedef void (*GConfListenersCallback)(GConfListeners* listeners, + const gchar* all_above_key, guint cnxn_id, gpointer listener_data, gpointer user_data); @@ -62,10 +63,12 @@ void gconf_listeners_remove (GConfListeners* listeners, guint cnxn_id); void gconf_listeners_notify (GConfListeners* listeners, - const gchar* all_below, + const gchar* all_above, GConfListenersCallback callback, gpointer user_data); +guint gconf_listeners_count (GConfListeners* listeners); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/tests/Makefile.am b/tests/Makefile.am index d27b2ebd..188f5dd8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -2,10 +2,15 @@ EFENCE= INCLUDES = -I$(top_srcdir)/gconf -I$(includedir) $(ORBIT_CFLAGS) $(GLIB_CFLAGS) \ - -DG_LOG_DOMAIN=\"testgconf\" + -DG_LOG_DOMAIN=\"GConf-Tests\" -noinst_PROGRAMS=testgconf +noinst_PROGRAMS=testgconf testlisteners testgconf_SOURCES=testgconf.c -testgconf_LDADD = $(EFENCE) $(ORBIT_LIBS) $(GLIB_LIBS) $(top_builddir)/gconf/libgconf-client.la +testgconf_LDADD = $(ORBIT_LIBS) $(GLIB_LIBS) $(top_builddir)/gconf/libgconf-client.la $(EFENCE) + +testlisteners_SOURCES=testlisteners.c + +testlisteners_LDADD = $(ORBIT_LIBS) $(GLIB_LIBS) $(top_builddir)/gconf/libgconf-client.la $(EFENCE) + diff --git a/tests/testlisteners.c b/tests/testlisteners.c new file mode 100644 index 00000000..23867922 --- /dev/null +++ b/tests/testlisteners.c @@ -0,0 +1,560 @@ +/* GConf + * Copyright (C) 1999 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <gconf-listeners.h> +#include <stdio.h> +#include <unistd.h> +#include <math.h> +#include <string.h> +#include <stdlib.h> + +static void +check(gboolean condition, const gchar* fmt, ...) +{ + va_list args; + gchar* description; + + va_start (args, fmt); + description = g_strdup_vprintf(fmt, args); + va_end (args); + + if (condition) + { + printf("."); + fflush(stdout); + } + else + { + fprintf(stderr, "\n*** FAILED: %s\n", description); + exit(1); + } + + g_free(description); +} + +static const gchar* +keys[] = { + "/testing/foo/tar", + "/testing/foo/bar", + "/testing/quad", + "/testing/blah", + "/testing/q/a/b/c/z/w/x/y/z", + "/testing/foo/baz", + "/testing/dup", + "/testing/oops/bloo", + "/testing/oops/snoo", + "/testing/dup", + "/testing/oops/kwoo", + "/testing/foo/quaz", + "/testing", + "/testing/oops", + "/testing/dup", + "/", + "/blah/blah/blah", + "/blah/blah/foo", + "/blah/blah/bar", + "/boo", + "/baz", + "/bap", + "/duplicate", + "/duplicate", + NULL +}; + +struct stuff { + guint id; + gchar* key; + guint* id_retloc; + gchar** key_retloc; +}; + +static void +test_destroy_notify(gpointer data) +{ + struct stuff* s = data; + + *s->id_retloc = s->id; + + *s->key_retloc = s->key; + + g_free(s); +} + +static void +check_add_remove(GConfListeners* listeners) +{ + guint ids[128]; + guint i; + const gchar** keyp; + guint id_retloc; + gchar* key_retloc; + + memset(ids, 0, sizeof(ids[0]) * 128); + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + struct stuff* s; + + s = g_new0(struct stuff, 1); + + s->id_retloc = &id_retloc; + s->key_retloc = &key_retloc; + + s->id = ids[i] = gconf_listeners_add(listeners, + *keyp, + s, + test_destroy_notify); + + s->key = g_strdup(*keyp); + + check(ids[i] != 0, "invalid connection ID returned for added listener"); + + ++i; + ++keyp; + } + + check(gconf_listeners_count(listeners) == i, + "number of listeners added (%u) don't now exist in the GConfListeners (%u exist)", i, gconf_listeners_count(listeners)); + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + id_retloc = 0; + key_retloc = NULL; + + gconf_listeners_remove(listeners, ids[i]); + + check(strcmp(key_retloc, *keyp) == 0, + "listener removed has different key from listener added (`%s' vs. `%s')", *keyp, key_retloc); + + g_free(key_retloc); + + check(ids[i] == id_retloc, "listener removed had different id from that added (%u vs. %u)", ids[i], id_retloc); + + ++i; + ++keyp; + } + + check(gconf_listeners_count(listeners) == 0, + "listener count isn't 0 after removing all the listeners"); +} + +static void +check_immediate_remove_after_add(GConfListeners* listeners) +{ + guint ids[128]; + guint i; + const gchar** keyp; + guint id_retloc; + gchar* key_retloc; + + memset(ids, 0, sizeof(ids[0]) * 128); + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + struct stuff* s; + + s = g_new0(struct stuff, 1); + + s->id_retloc = &id_retloc; + s->key_retloc = &key_retloc; + + s->id = ids[i] = gconf_listeners_add(listeners, + *keyp, + s, + test_destroy_notify); + + s->key = g_strdup(*keyp); + + check(ids[i] != 0, "invalid connection ID returned for added listener"); + + if (i > 0) + check(ids[i] == ids[i-1], "connection ID was not properly recycled"); + + check(gconf_listeners_count(listeners) == 1, + "didn't have 1 listener as expected"); + + id_retloc = 0; + key_retloc = NULL; + + gconf_listeners_remove(listeners, ids[i]); + + check(strcmp(key_retloc, *keyp) == 0, + "listener removed has different key from listener added (`%s' vs. `%s')", *keyp, key_retloc); + + g_free(key_retloc); + + check(ids[i] == id_retloc, "listener removed had different id from that added (%u vs. %u)", ids[i], id_retloc); + + check(gconf_listeners_count(listeners) == 0, + "didn't have 0 listeners as expected"); + + ++i; + ++keyp; + } + + check(gconf_listeners_count(listeners) == 0, + "listener count isn't 0 after removing all the listeners"); +} + +static void +check_double_add_remove(GConfListeners* listeners) +{ + guint ids[128]; + guint i; + const gchar** keyp; + guint id_retloc; + gchar* key_retloc; + + memset(ids, 0, sizeof(ids[0]) * 128); + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + struct stuff* s; + + s = g_new0(struct stuff, 1); + + s->id_retloc = &id_retloc; + s->key_retloc = &key_retloc; + + s->id = ids[i] = gconf_listeners_add(listeners, + *keyp, + s, + test_destroy_notify); + + s->key = g_strdup(*keyp); + + check(ids[i] != 0, "invalid connection ID returned for added listener"); + + ++i; + if ((i % 2) == 0) + ++keyp; + } + + check(gconf_listeners_count(listeners) == i, + "number of listeners added (%u) don't now exist in the GConfListeners (%u exist)", i, gconf_listeners_count(listeners)); + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + id_retloc = 0; + key_retloc = NULL; + + gconf_listeners_remove(listeners, ids[i]); + + check(strcmp(key_retloc, *keyp) == 0, + "listener removed has different key from listener added (`%s' vs. `%s')", *keyp, key_retloc); + + g_free(key_retloc); + + check(ids[i] == id_retloc, "listener removed had different id from that added (%u vs. %u)", ids[i], id_retloc); + + ++i; + if ((i % 2) == 0) + ++keyp; + } + + check(gconf_listeners_count(listeners) == 0, + "listener count isn't 0 after removing all the listeners"); +} + +static gboolean +should_be_notified(const gchar* changed_key, + const gchar* listener_watchpoint) +{ + return strncmp(changed_key, listener_watchpoint, strlen(listener_watchpoint)) == 0; +} + +struct notify_data { + const gchar* notify_key; + GSList* notified; +}; + +void +notify_callback(GConfListeners* listeners, + const gchar* all_above_key, + guint cnxn_id, + gpointer listener_data, + gpointer user_data) +{ + struct notify_data* nd = user_data; + struct stuff* s = listener_data; + + check(strcmp(all_above_key, nd->notify_key) == 0, "notify key `%s' is not the notify key received in callback `%s'", + nd->notify_key, all_above_key); + + check(cnxn_id == s->id, + "listener ID is wrong in callback (%u vs. %u)", + cnxn_id, s->id); + + check(should_be_notified(all_above_key, s->key), + "listener %u at `%s' shouldn't have been notified of change to `%s'", + s->id, s->key, all_above_key); + + nd->notified = g_slist_prepend(nd->notified, s); +} + +void +check_notification(GConfListeners* listeners) +{ + guint ids[128]; + guint i; + const gchar** keyp; + guint id_retloc; + gchar* key_retloc; + + memset(ids, 0, sizeof(ids[0]) * 128); + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + struct stuff* s; + + s = g_new0(struct stuff, 1); + + s->id_retloc = &id_retloc; + s->key_retloc = &key_retloc; + + s->id = ids[i] = gconf_listeners_add(listeners, + *keyp, + s, + test_destroy_notify); + + s->key = g_strdup(*keyp); + + check(ids[i] != 0, "invalid connection ID returned for added listener"); + + /* printf("%u added at `%s'\n", s->id, s->key); */ + + ++i; + ++keyp; + } + + check(gconf_listeners_count(listeners) == i, + "number of listeners added (%u) don't now exist in the GConfListeners (%u exist)", i, gconf_listeners_count(listeners)); + + keyp = keys; + + while (*keyp) + { + struct notify_data nd = { *keyp, NULL }; + GSList* tmp = NULL; + const gchar** sub_keyp; + + nd.notified = NULL; + + gconf_listeners_notify(listeners, *keyp, + notify_callback, + &nd); + + /* Check that the list that was notified matches + the list that should have been */ + sub_keyp = keys; + while (*sub_keyp) + { + struct stuff* s = NULL; + gboolean should_be = should_be_notified(*keyp, *sub_keyp); + + tmp = nd.notified; + while (tmp != NULL) + { + s = tmp->data; + + if (strcmp(s->key, *sub_keyp) == 0) + break; + + tmp = g_slist_next(tmp); + } + + if (should_be) + { + check (tmp != NULL, "listener at `%s' should have been notified of change to `%s' and was not", *sub_keyp, *keyp); + s = tmp->data; + /* remove so we can handle duplicate keys */ + nd.notified = g_slist_remove(nd.notified, tmp->data); + +#if 0 + g_assert(strcmp(s->key, *sub_keyp) == 0); + printf("%u at `%s' notified properly of `%s'\n", + s->id, *sub_keyp, *keyp); +#endif + } + else + { + check(tmp == NULL, "listener at `%s' should not have been notified of change to `%s' but it was", *sub_keyp, *keyp); +#if 0 + printf("`%s' properly not notified of `%s'\n", + *sub_keyp, *keyp); +#endif + } + + ++sub_keyp; + } + + if (nd.notified != NULL) + { + GSList* tmp = nd.notified; + while (tmp != NULL) + { + struct stuff* s = tmp->data; + fprintf(stderr, "leftover: %u at `%s' notified of `%s'\n", + s->id, s->key, *keyp); + tmp = g_slist_next(tmp); + } + } + check (nd.notified == NULL, "superfluous listeners were notified of `%s'; perhaps listeners were notified twice?", *keyp); + + ++keyp; + } + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + id_retloc = 0; + key_retloc = NULL; + + gconf_listeners_remove(listeners, ids[i]); + + check(strcmp(key_retloc, *keyp) == 0, + "listener removed has different key from listener added (`%s' vs. `%s')", *keyp, key_retloc); + + g_free(key_retloc); + + check(ids[i] == id_retloc, "listener removed had different id from that added (%u vs. %u)", ids[i], id_retloc); + + ++i; + ++keyp; + } + + check(gconf_listeners_count(listeners) == 0, + "listener count isn't 0 after removing all the listeners"); +} + +struct destroy_data { + gchar* key; + guint* destroy_count_loc; +}; + +static void +destroy_test_destroy_notify(gpointer data) +{ + struct destroy_data* d = data; + + *d->destroy_count_loc += 1; + + g_free(d->key); + + g_free(d); +} + +/* This is mostly for use with memory leak detection tools */ +void +check_destroy(void) +{ + GConfListeners* listeners; + guint ids[128]; + guint i; + const gchar** keyp; + guint destroy_count = 0; + + listeners = gconf_listeners_new(); + + memset(ids, 0, sizeof(ids[0]) * 128); + + i = 0; + keyp = keys; + + while (i < 128 && *keyp) + { + struct destroy_data* d; + + d = g_new0(struct destroy_data, 1); + + d->destroy_count_loc = &destroy_count; + + ids[i] = gconf_listeners_add(listeners, + *keyp, + d, + destroy_test_destroy_notify); + + d->key = g_strdup(*keyp); + + check(ids[i] != 0, "invalid connection ID returned for added listener"); + + ++i; + ++keyp; + } + + check(gconf_listeners_count(listeners) == i, + "number of listeners added (%u) don't now exist in the GConfListeners (%u exist)", i, gconf_listeners_count(listeners)); + + gconf_listeners_destroy(listeners); + + check(destroy_count == i, + "number of listeners added (%u) doesn't match number destroyed (%u) on GConfListeners destruction", i, destroy_count); +} + +int +main (int argc, char** argv) +{ + GConfListeners* listeners; + + listeners = gconf_listeners_new(); + + check_add_remove(listeners); + + g_assert(gconf_listeners_count(listeners) == 0); + + check_immediate_remove_after_add(listeners); + + g_assert(gconf_listeners_count(listeners) == 0); + + check_double_add_remove(listeners); + + g_assert(gconf_listeners_count(listeners) == 0); + + check_notification(listeners); + + g_assert(gconf_listeners_count(listeners) == 0); + + gconf_listeners_destroy(listeners); + + check_destroy(); + + printf("\n"); + + return 0; +} |