Update to birb 0.4 and use the testing helpers in libpurple

Thu, 12 Jun 2025 23:48:22 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Thu, 12 Jun 2025 23:48:22 -0500
changeset 43265
7960b5f85729
parent 43260
d5b9da0df929
child 43266
19b9321a0177

Update to birb 0.4 and use the testing helpers in libpurple

Testing Done:
Called in the turtles.

Reviewed at https://reviews.imfreedom.org/r/4014/

libpurple/tests/test_attachments.c file | annotate | diff | comparison | revisions
libpurple/tests/test_badges.c file | annotate | diff | comparison | revisions
libpurple/tests/test_command_manager.c file | annotate | diff | comparison | revisions
libpurple/tests/test_conversation_manager.c file | annotate | diff | comparison | revisions
libpurple/tests/test_conversation_members.c file | annotate | diff | comparison | revisions
libpurple/tests/test_credential_manager.c file | annotate | diff | comparison | revisions
libpurple/tests/test_history_manager.c file | annotate | diff | comparison | revisions
libpurple/tests/test_messages.c file | annotate | diff | comparison | revisions
libpurple/tests/test_notification_manager.c file | annotate | diff | comparison | revisions
libpurple/tests/test_person.c file | annotate | diff | comparison | revisions
libpurple/tests/test_presence_manager.c file | annotate | diff | comparison | revisions
meson.build file | annotate | diff | comparison | revisions
subprojects/birb.wrap file | annotate | diff | comparison | revisions
--- a/libpurple/tests/test_attachments.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_attachments.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,36 +18,9 @@
 
 #include <glib.h>
 
-#include <purple.h>
-
-/******************************************************************************
- * Callbacks
- *****************************************************************************/
-static void
-test_purple_attachments_items_changed(GListModel *model,
-                                      G_GNUC_UNUSED guint position,
-                                      G_GNUC_UNUSED guint removed,
-                                      G_GNUC_UNUSED guint added,
-                                      gpointer data)
-{
-	guint *counter = data;
+#include <birb.h>
 
-	g_assert_true(PURPLE_IS_ATTACHMENTS(model));
-
-	*counter = *counter + 1;
-}
-
-static void
-test_purple_attachments_notify(GObject *self,
-                               G_GNUC_UNUSED GParamSpec *pspec,
-                               gpointer data)
-{
-	guint *counter = data;
-
-	g_assert_true(PURPLE_IS_ATTACHMENTS(self));
-
-	*counter = *counter + 1;
-}
+#include <purple.h>
 
 /******************************************************************************
  * Tests
@@ -83,12 +56,10 @@
 	guint n_items_counter = 0;
 
 	attachments = purple_attachments_new();
-	g_signal_connect(attachments, "items-changed",
-	                 G_CALLBACK(test_purple_attachments_items_changed),
-	                 &items_changed_counter);
-	g_signal_connect(attachments, "notify::n-items",
-	                 G_CALLBACK(test_purple_attachments_notify),
-	                 &n_items_counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(attachments),
+	                                    &items_changed_counter);
+	birb_count_property_changed(G_OBJECT(attachments), "n-items",
+	                            &n_items_counter);
 
 	attachment = purple_attachment_new("1337", "text/plain");
 
@@ -121,12 +92,10 @@
 	guint n_items_counter = 0;
 
 	attachments = purple_attachments_new();
-	g_signal_connect(attachments, "items-changed",
-	                 G_CALLBACK(test_purple_attachments_items_changed),
-	                 &items_changed_counter);
-	g_signal_connect(attachments, "notify::n-items",
-	                 G_CALLBACK(test_purple_attachments_notify),
-	                 &n_items_counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(attachments),
+	                                    &items_changed_counter);
+	birb_count_property_changed(G_OBJECT(attachments), "n-items",
+	                            &n_items_counter);
 
 	attachment = purple_attachment_new("1337", "text/plain");
 
--- a/libpurple/tests/test_badges.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_badges.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,23 +18,9 @@
 
 #include <glib.h>
 
-#include <purple.h>
+#include <birb.h>
 
-/******************************************************************************
- * Callbacks
- *****************************************************************************/
-static void
-test_purple_badges_items_changed(GListModel *model,
-                                 G_GNUC_UNUSED guint position,
-                                 G_GNUC_UNUSED guint removed,
-                                 G_GNUC_UNUSED guint added, gpointer data)
-{
-	guint *counter = data;
-
-	g_assert_true(PURPLE_IS_BADGES(model));
-
-	*counter = *counter + 1;
-}
+#include <purple.h>
 
 /******************************************************************************
  * Tests
@@ -82,8 +68,7 @@
 	 */
 
 	badges = purple_badges_new();
-	g_signal_connect(badges, "items-changed",
-	                 G_CALLBACK(test_purple_badges_items_changed), &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(badges), &counter);
 
 	high = purple_badge_new("high", 1000, "icon-name", "+");
 	medium = purple_badge_new("medium", 0, "icon-name", "=");
@@ -190,8 +175,7 @@
 	guint counter = 0;
 
 	badges = purple_badges_new();
-	g_signal_connect(badges, "items-changed",
-	                 G_CALLBACK(test_purple_badges_items_changed), &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(badges), &counter);
 
 	badge = purple_badge_new("double-add", 0, "icon", "i");
 
@@ -219,8 +203,7 @@
 	guint counter = 0;
 
 	badges = purple_badges_new();
-	g_signal_connect(badges, "items-changed",
-	                 G_CALLBACK(test_purple_badges_items_changed), &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(badges), &counter);
 
 	badge = purple_badge_new("double-remove", 0, "icon", "i");
 
--- a/libpurple/tests/test_command_manager.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_command_manager.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,24 +18,9 @@
 
 #include <glib.h>
 
-#include <purple.h>
+#include <birb.h>
 
-/******************************************************************************
- * Resuable callbacks
- *****************************************************************************/
-static void
-test_purple_command_manager_items_changed_cb(GListModel *model,
-                                             G_GNUC_UNUSED guint position,
-                                             G_GNUC_UNUSED guint removed,
-                                             G_GNUC_UNUSED guint added,
-                                             gpointer data)
-{
-	guint *counter = data;
-
-	g_assert_true(PURPLE_IS_COMMAND_MANAGER(model));
-
-	*counter = *counter + 1;
-}
+#include <purple.h>
 
 /******************************************************************************
  * Tests
@@ -60,9 +45,7 @@
 
 	manager = purple_command_manager_new();
 	model = G_LIST_MODEL(manager);
-	g_signal_connect(manager, "items-changed",
-	                 G_CALLBACK(test_purple_command_manager_items_changed_cb),
-	                 &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(manager), &counter);
 
 	g_assert_cmpuint(g_list_model_get_n_items(model), ==, 0);
 
@@ -127,9 +110,7 @@
 
 	manager = purple_command_manager_new();
 	model = G_LIST_MODEL(manager);
-	g_signal_connect(manager, "items-changed",
-	                 G_CALLBACK(test_purple_command_manager_items_changed_cb),
-	                 &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(manager), &counter);
 
 	/* Make sure remove all works on an empty manager. */
 	counter = 0;
--- a/libpurple/tests/test_conversation_manager.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_conversation_manager.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,6 +18,8 @@
 
 #include <glib.h>
 
+#include <birb.h>
+
 #include <purple.h>
 
 /******************************************************************************
@@ -36,21 +38,6 @@
 	*counter = *counter + 1;
 }
 
-static void
-test_purple_conversation_manager_items_changed_cb(GListModel *model,
-                                                  G_GNUC_UNUSED guint position,
-                                                  G_GNUC_UNUSED guint removed,
-                                                  G_GNUC_UNUSED guint added,
-                                                  gpointer data)
-{
-	guint *counter = data;
-
-	g_assert_true(PURPLE_IS_CONVERSATION_MANAGER(model));
-	g_assert_true(G_IS_LIST_MODEL(model));
-
-	*counter = *counter + 1;
-}
-
 /******************************************************************************
  * Tests
  *****************************************************************************/
@@ -107,9 +94,8 @@
 	g_signal_connect(manager, "removed",
 	                 G_CALLBACK(test_purple_conversation_manager_counter_cb),
 	                 &removed_counter);
-	g_signal_connect(manager, "items-changed",
-	                 G_CALLBACK(test_purple_conversation_manager_items_changed_cb),
-	                 &changed_counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(manager),
+	                                    &changed_counter);
 
 	/* Create our account. */
 	account = purple_account_new("test", "test");
--- a/libpurple/tests/test_conversation_members.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_conversation_members.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,6 +18,8 @@
 
 #include <glib.h>
 
+#include <birb.h>
+
 #include <purple.h>
 
 /******************************************************************************
@@ -203,18 +205,6 @@
  * Active Typers Tests
  *****************************************************************************/
 static void
-test_purple_conversation_members_active_typers_changed_cb(G_GNUC_UNUSED GListModel *model,
-                                                          G_GNUC_UNUSED guint position,
-                                                          G_GNUC_UNUSED guint removed,
-                                                          G_GNUC_UNUSED guint added,
-                                                          gpointer data)
-{
-	guint *counter = data;
-
-	*counter = *counter + 1;
-}
-
-static void
 test_purple_conversation_members_active_typers(void) {
 	PurpleContactInfo *info = NULL;
 	PurpleConversationMember *member = NULL;
@@ -224,9 +214,7 @@
 
 	members = purple_conversation_members_new();
 	active_typers = purple_conversation_members_get_active_typers(members);
-	g_signal_connect(active_typers, "items-changed",
-	                 G_CALLBACK(test_purple_conversation_members_active_typers_changed_cb),
-	                 &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(active_typers), &counter);
 
 	info = purple_contact_info_new(NULL);
 	member = purple_conversation_members_add_member(members, info, FALSE,
@@ -268,28 +256,6 @@
  * Extend Tests
  *****************************************************************************/
 static void
-test_purple_conversation_members_extend_items_changed_counter(G_GNUC_UNUSED GListModel *model,
-                                                              G_GNUC_UNUSED guint position,
-                                                              G_GNUC_UNUSED guint removed,
-                                                              G_GNUC_UNUSED guint added,
-                                                              gpointer data)
-{
-	guint *counter = data;
-
-	*counter = *counter + 1;
-}
-
-static void
-test_purple_conversation_members_extend_notify_counter(G_GNUC_UNUSED GObject *obj,
-                                                       G_GNUC_UNUSED GParamSpec *pspec,
-                                                       gpointer data)
-{
-	guint *counter = data;
-
-	*counter = *counter + 1;
-}
-
-static void
 test_purple_conversation_members_extend_existing_cb(G_GNUC_UNUSED GListModel *model,
                                                     guint position,
                                                     guint removed,
@@ -326,20 +292,16 @@
 	guint n_items = 0;
 
 	existing_members = purple_conversation_members_new();
-	g_signal_connect(existing_members, "items-changed",
-	                 G_CALLBACK(test_purple_conversation_members_extend_items_changed_counter),
-	                 &existing_items_changed_counter);
-	g_signal_connect(existing_members, "notify::n-items",
-	                 G_CALLBACK(test_purple_conversation_members_extend_notify_counter),
-	                 &existing_n_items_counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(existing_members),
+	                                    &existing_items_changed_counter);
+	birb_count_property_changed(G_OBJECT(existing_members), "n-items",
+	                            &existing_n_items_counter);
 
 	new_members = purple_conversation_members_new();
-	g_signal_connect(new_members, "items-changed",
-	                 G_CALLBACK(test_purple_conversation_members_extend_items_changed_counter),
-	                 &new_items_changed_counter);
-	g_signal_connect(new_members, "notify::n-items",
-	                 G_CALLBACK(test_purple_conversation_members_extend_notify_counter),
-	                 &new_n_items_counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(new_members),
+	                                    &new_items_changed_counter);
+	birb_count_property_changed(G_OBJECT(new_members), "n-items",
+	                            &new_n_items_counter);
 
 	/* Add a member to the existing members. */
 	existing_items_changed_counter = 0;
--- a/libpurple/tests/test_credential_manager.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_credential_manager.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,6 +18,8 @@
 
 #include <glib.h>
 
+#include <birb.h>
+
 #include <purple.h>
 
 /******************************************************************************
@@ -139,21 +141,6 @@
  * Callbacks
  *****************************************************************************/
 static void
-test_purple_credential_provider_items_changed_cb(GListModel *model,
-                                                 G_GNUC_UNUSED guint position,
-                                                 G_GNUC_UNUSED guint removed,
-                                                 G_GNUC_UNUSED guint added,
-                                                 gpointer data)
-{
-	guint *counter = data;
-
-	g_assert_true(PURPLE_IS_CREDENTIAL_MANAGER(model));
-	g_assert_true(G_IS_LIST_MODEL(model));
-
-	*counter = *counter + 1;
-}
-
-static void
 test_purple_credential_provider_added_removed_cb(PurpleCredentialManager *manager,
                                                  PurpleCredentialProvider *provider,
                                                  gpointer data)
@@ -203,9 +190,7 @@
 	g_signal_connect(manager, "removed",
 	                 G_CALLBACK(test_purple_credential_provider_added_removed_cb),
 	                 &removed);
-	g_signal_connect(manager, "items-changed",
-	                 G_CALLBACK(test_purple_credential_provider_items_changed_cb),
-	                 &changed);
+	birb_count_list_model_items_changed(G_LIST_MODEL(manager), &changed);
 
 	provider = test_purple_credential_provider_new();
 
--- a/libpurple/tests/test_history_manager.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_history_manager.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,6 +18,8 @@
 
 #include <glib.h>
 
+#include <birb.h>
+
 #include <purple.h>
 
 #include "test_ui.h"
@@ -139,21 +141,6 @@
  * Callbacks
  *****************************************************************************/
 static void
-test_purple_history_manager_items_changed_cb(GListModel *model,
-                                             G_GNUC_UNUSED guint position,
-                                             G_GNUC_UNUSED guint removed,
-                                             G_GNUC_UNUSED guint added,
-                                             gpointer data)
-{
-	guint *counter = data;
-
-	g_assert_true(PURPLE_IS_HISTORY_MANAGER(model));
-	g_assert_true(G_IS_LIST_MODEL(model));
-
-	*counter = *counter + 1;
-}
-
-static void
 test_purple_history_manager_added_removed_cb(PurpleHistoryManager *manager,
                                              PurpleHistoryAdapter *adapter,
                                              gpointer data)
@@ -224,9 +211,7 @@
 	g_signal_connect(manager, "removed",
 	                 G_CALLBACK(test_purple_history_manager_added_removed_cb),
 	                 &removed);
-	g_signal_connect(manager, "items-changed",
-	                 G_CALLBACK(test_purple_history_manager_items_changed_cb),
-	                 &changed);
+	birb_count_list_model_items_changed(G_LIST_MODEL(manager), &changed);
 
 	adapter = test_purple_history_adapter_new();
 
--- a/libpurple/tests/test_messages.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_messages.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,22 +18,9 @@
 
 #include <glib.h>
 
-#include <purple.h>
+#include <birb.h>
 
-/******************************************************************************
- * Callbacks
- *****************************************************************************/
-static void
-test_purple_messages_items_changed_counter(G_GNUC_UNUSED GListModel *model,
-                                           G_GNUC_UNUSED guint position,
-                                           G_GNUC_UNUSED guint removed,
-                                           G_GNUC_UNUSED guint added,
-                                           gpointer data)
-{
-	guint *counter = data;
-
-	*counter = *counter + 1;
-}
+#include <purple.h>
 
 /******************************************************************************
  * Tests
@@ -126,9 +113,7 @@
 	                                                NULL);
 
 	messages = purple_messages_new(conversation);
-	g_signal_connect(messages, "items-changed",
-	                 G_CALLBACK(test_purple_messages_items_changed_counter),
-	                 &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(messages), &counter);
 
 	message1 = purple_message_new(author, "test message");
 	purple_messages_add(messages, message1);
@@ -175,9 +160,7 @@
 	                                                NULL);
 
 	messages = purple_messages_new(conversation);
-	g_signal_connect(messages, "items-changed",
-	                 G_CALLBACK(test_purple_messages_items_changed_counter),
-	                 &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(messages), &counter);
 
 	zone = g_time_zone_new_utc();
 
--- a/libpurple/tests/test_notification_manager.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_notification_manager.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,6 +18,8 @@
 
 #include <glib.h>
 
+#include <birb.h>
+
 #include <purple.h>
 
 /******************************************************************************
@@ -33,30 +35,6 @@
 	*counter = *counter + 1;
 }
 
-static void
-test_purple_notification_manager_unread_count_cb(G_GNUC_UNUSED GObject *obj,
-                                                 G_GNUC_UNUSED GParamSpec *pspec,
-                                                 gpointer data)
-{
-	guint *counter = data;
-
-	*counter = *counter + 1;
-}
-
-static void
-test_purple_notification_manager_items_changed_cb(GListModel *model,
-                                                  G_GNUC_UNUSED guint position,
-                                                  G_GNUC_UNUSED guint removed,
-                                                  G_GNUC_UNUSED guint added,
-                                                  gpointer data)
-{
-	guint *counter = data;
-
-	g_assert_true(PURPLE_IS_NOTIFICATION_MANAGER(model));
-
-	*counter = *counter + 1;
-}
-
 /******************************************************************************
  * Tests
  *****************************************************************************/
@@ -348,9 +326,8 @@
 	g_signal_connect(manager, "unread",
 	                 G_CALLBACK(test_purple_notification_manager_increment_cb),
 	                 &unread_called);
-	g_signal_connect(manager, "notify::unread-count",
-	                 G_CALLBACK(test_purple_notification_manager_unread_count_cb),
-	                 &unread_count_called);
+	birb_count_property_changed(G_OBJECT(manager), "unread-count",
+	                            &unread_count_called);
 
 	/* Create the notification. */
 	notification = purple_notification_new(NULL, NULL);
@@ -392,9 +369,7 @@
 	guint counter = 0;
 
 	manager = g_object_new(PURPLE_TYPE_NOTIFICATION_MANAGER, NULL);
-	g_signal_connect(manager, "items-changed",
-	                 G_CALLBACK(test_purple_notification_manager_items_changed_cb),
-	                 &counter);
+	birb_count_list_model_items_changed(G_LIST_MODEL(manager), &counter);
 
 	notification = purple_notification_new(NULL, "title");
 	purple_notification_manager_add(manager, notification);
--- a/libpurple/tests/test_person.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_person.c	Thu Jun 12 23:48:22 2025 -0500
@@ -18,32 +18,9 @@
 
 #include <glib.h>
 
-#include <purple.h>
+#include <birb.h>
 
-/******************************************************************************
- * Callbacks
- *****************************************************************************/
-static void
-test_purple_person_items_changed_cb(G_GNUC_UNUSED GListModel *model,
-                                    G_GNUC_UNUSED guint position,
-                                    G_GNUC_UNUSED guint removed,
-                                    G_GNUC_UNUSED guint added,
-                                    gpointer data)
-{
-	guint *counter = data;
-
-	*counter = *counter + 1;
-}
-
-static void
-test_purple_person_notify_cb(G_GNUC_UNUSED GObject *obj,
-                             G_GNUC_UNUSED GParamSpec *pspec,
-                             gpointer data)
-{
-	guint *called = data;
-
-	*called = *called + 1;
-}
+#include <purple.h>
 
 /******************************************************************************
  * Tests
@@ -133,16 +110,17 @@
 	PurpleAvatar *avatar = NULL;
 	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
-	guint called = 0;
+	guint avatar_counter = 0;
+	guint avatar_for_display_counter = 0;
 
 	person = purple_person_new();
-	g_signal_connect(person, "notify::avatar",
-	                 G_CALLBACK(test_purple_person_notify_cb), &called);
-	g_signal_connect(person, "notify::avatar-for-display",
-	                 G_CALLBACK(test_purple_person_notify_cb), &called);
+	birb_count_property_changed(G_OBJECT(person), "avatar", &avatar_counter);
+	birb_count_property_changed(G_OBJECT(person), "avatar-for-display",
+	                            &avatar_for_display_counter);
 	avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL);
 	purple_person_set_avatar(person, avatar);
-	g_assert_cmpuint(called, ==, 2);
+	g_assert_cmpuint(avatar_counter, ==, 1);
+	g_assert_cmpuint(avatar_for_display_counter, ==, 1);
 
 	info = purple_contact_info_new("id");
 	purple_person_add_contact_info(person, info);
@@ -165,31 +143,30 @@
 	PurpleAvatar *avatar = NULL;
 	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
-	guint called = 0;
+	guint counter = 0;
 
 	person = purple_person_new();
-	g_signal_connect(person, "notify::avatar-for-display",
-	                 G_CALLBACK(test_purple_person_notify_cb), &called);
+	birb_count_property_changed(G_OBJECT(person), "avatar-for-display",
+	                            &counter);
 
 	info = purple_contact_info_new("id");
 	avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL);
 	purple_contact_info_set_avatar(info, avatar);
 	purple_person_add_contact_info(person, info);
 
-	g_assert_cmpuint(called, ==, 1);
-	called = 0;
+	g_assert_cmpuint(counter, ==, 1);
 
-	/* Make sure the person's alias is overriding the contact info. */
+	/* Make sure the person's avatar is overriding the contact info. */
 	g_assert_true(purple_person_get_avatar_for_display(person) == avatar);
 	g_clear_object(&avatar);
 
 	/* Now change the avatar on the contact info an verify that we not notified
 	 * of the property changing.
 	 */
-	called = 0;
+	counter = 0;
 	avatar = g_object_new(PURPLE_TYPE_AVATAR, NULL);
 	purple_contact_info_set_avatar(info, avatar);
-	g_assert_cmpuint(called, ==, 1);
+	g_assert_cmpuint(counter, ==, 1);
 
 	/* Contact info's have a reference on the person, so the easiest way to
 	 * remove that is to remove them from the person.
@@ -206,32 +183,29 @@
 	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	const char *color = NULL;
-	guint color_called = 0;
-	guint color_for_display_called = 0;
+	guint color_counter = 0;
+	guint color_for_display_counter = 0;
 
 	person = purple_person_new();
-	g_signal_connect(person, "notify::color",
-	                 G_CALLBACK(test_purple_person_notify_cb), &color_called);
-	g_signal_connect(person, "notify::color-for-display",
-	                 G_CALLBACK(test_purple_person_notify_cb),
-	                 &color_for_display_called);
+	birb_count_property_changed(G_OBJECT(person), "color", &color_counter);
+	birb_count_property_changed(G_OBJECT(person), "color-for-display",
+	                            &color_for_display_counter);
 	purple_person_set_color(person, "#abcdef");
 
-	g_assert_cmpuint(color_called, ==, 1);
-	color_called = 0;
-
-	g_assert_cmpuint(color_for_display_called, ==, 1);
-	color_for_display_called = 0;
+	g_assert_cmpuint(color_counter, ==, 1);
+	g_assert_cmpuint(color_for_display_counter, ==, 1);
 
 	/* Make sure the person's color is overriding the contact info. */
+	color_counter = 0;
+	color_for_display_counter = 0;
 	info = purple_contact_info_new("id");
 	purple_person_add_contact_info(person, info);
 
 	color = purple_person_get_color_for_display(person);
 	g_assert_cmpstr(color, ==, "#abcdef");
 
-	g_assert_cmpuint(color_called, ==, 0);
-	g_assert_cmpuint(color_for_display_called, ==, 0);
+	g_assert_cmpuint(color_counter, ==, 0);
+	g_assert_cmpuint(color_for_display_counter, ==, 0);
 
 	/* Contact info's have a reference on the person, so the easiest way to
 	 * remove that is to remove them from the person.
@@ -248,28 +222,28 @@
 	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	const char *color = NULL;
-	guint called = 0;
+	guint counter = 0;
 
 	person = purple_person_new();
-	g_signal_connect(person, "notify::color-for-display",
-	                 G_CALLBACK(test_purple_person_notify_cb), &called);
+	birb_count_property_changed(G_OBJECT(person), "color-for-display",
+	                            &counter);
 
 	info = purple_contact_info_new("id");
 	purple_contact_info_set_color(info, "#012345");
 	purple_person_add_contact_info(person, info);
 
-	g_assert_cmpuint(called, ==, 1);
-	called = 0;
+	g_assert_cmpuint(counter, ==, 1);
 
-	/* Make sure the person's alias is overriding the contact info. */
+	/* Make sure the person's color is overriding the contact info. */
 	color = purple_person_get_color_for_display(person);
 	g_assert_cmpstr(color, ==, "#012345");
 
-	/* Now change the avatar on the contact info and verify that we are
-	 * notified of the property changing.
+	/* Now change the color on the contact info and verify that we are notified
+	 * of the property changing.
 	 */
+	counter = 0;
 	purple_contact_info_set_color(info, "#6789ab");
-	g_assert_cmpuint(called, ==, 1);
+	g_assert_cmpuint(counter, ==, 1);
 
 	/* Contact info's have a reference on the person, so the easiest way to
 	 * remove that is to remove them from the person.
@@ -308,15 +282,15 @@
 test_purple_person_name_for_display_contact(void) {
 	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
-	guint called = 0;
+	guint counter = 0;
 
 	person = purple_person_new();
-	g_signal_connect(person, "notify::name-for-display",
-	                 G_CALLBACK(test_purple_person_notify_cb), &called);
+	birb_count_property_changed(G_OBJECT(person), "name-for-display",
+	                            &counter);
 
 	info = purple_contact_info_new("id");
 	purple_person_add_contact_info(person, info);
-	g_assert_cmpuint(called, ==, 1);
+	g_assert_cmpuint(counter, ==, 1);
 
 	/* Make sure the name for display matches the id of the contact. */
 	g_assert_cmpstr(purple_person_get_name_for_display(person), ==, "id");
@@ -324,9 +298,10 @@
 	/* Now set a username on the contact and verify that the name for display
 	 * matches and that the notify signal was emitted for the property.
 	 */
+	counter = 0;
 	purple_contact_info_set_username(info, "clu");
 	g_assert_cmpstr(purple_person_get_name_for_display(person), ==, "clu");
-	g_assert_cmpuint(called, ==, 2);
+	g_assert_cmpuint(counter, ==, 1);
 
 	/* Contact info's have a reference on the person, so the easiest way to
 	 * remove that is to remove them from the person.
@@ -342,31 +317,26 @@
 	PurpleContactInfo *info = NULL;
 	PurplePerson *person = NULL;
 	PurplePerson *person1 = NULL;
-	guint n_items = 0;
 	gboolean removed = FALSE;
-	guint changed = 0;
+	guint counter = 0;
 
 	info = purple_contact_info_new("id");
 	person = purple_person_new();
-	g_signal_connect(person, "items-changed",
-	                 G_CALLBACK(test_purple_person_items_changed_cb), &changed);
+	birb_count_list_model_items_changed(G_LIST_MODEL(person), &counter);
 
-	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-	g_assert_cmpuint(n_items, ==, 0);
+	birb_assert_list_model_n_items(person, 0);
 	purple_person_add_contact_info(person, info);
-	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-	g_assert_cmpuint(n_items, ==, 1);
-	g_assert_cmpuint(changed, ==, 1);
+	birb_assert_list_model_n_items(person, 1);
+	g_assert_cmpuint(counter, ==, 1);
 
 	person1 = purple_contact_info_get_person(info);
 	g_assert_true(person1 == person);
 
-	changed = 0;
+	counter = 0;
 	removed = purple_person_remove_contact_info(person, info);
 	g_assert_true(removed);
-	g_assert_cmpuint(changed, ==, 1);
-	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-	g_assert_cmpuint(n_items, ==, 0);
+	g_assert_cmpuint(counter, ==, 1);
+	birb_assert_list_model_n_items(person, 0);
 
 	person1 = purple_contact_info_get_person(info);
 	g_assert_null(person1);
@@ -379,23 +349,20 @@
 test_purple_person_contacts_multiple(void) {
 	PurplePerson *person = NULL;
 	GPtrArray *infos = NULL;
-	guint n_items = 0;
 	const int n_infos = 5;
-	guint changed = 0;
+	guint counter = 0;
 
 	person = purple_person_new();
-	g_signal_connect(person, "items-changed",
-	                 G_CALLBACK(test_purple_person_items_changed_cb), &changed);
+	birb_count_list_model_items_changed(G_LIST_MODEL(person), &counter);
 
 	infos = g_ptr_array_new_full(n_infos, g_object_unref);
 	for(int i = 0; i < n_infos; i++) {
 		PurpleContactInfo *info = NULL;
 		char *username = NULL;
 
-		changed = 0;
+		counter = 0;
 
-		n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-		g_assert_cmpuint(n_items, ==, i);
+		birb_assert_list_model_n_items(person, i);
 
 		username = g_strdup_printf("username%d", i);
 		info = purple_contact_info_new(NULL);
@@ -409,32 +376,27 @@
 		 * happened.
 		 */
 		purple_person_add_contact_info(person, info);
-		n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-		g_assert_cmpuint(n_items, ==, i + 1);
-		g_assert_cmpuint(changed, ==, 1);
+		birb_assert_list_model_n_items(person, i + 1);
+		g_assert_cmpuint(counter, ==, 1);
 	}
 
 	for(int i = 0; i < n_infos; i++) {
 		PurpleContactInfo *info = g_ptr_array_index(infos, i);
 		gboolean removed = FALSE;
 
-		changed = 0;
+		counter = 0;
 
-		n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-		g_assert_cmpuint(n_items, ==, n_infos - i);
+		birb_assert_list_model_n_items(person, n_infos - i);
 
 		removed = purple_person_remove_contact_info(person, info);
 		g_assert_true(removed);
 
-		n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-		g_assert_cmpuint(n_items, ==, n_infos - (i + 1));
-
-		g_assert_cmpuint(changed, ==, 1);
+		birb_assert_list_model_n_items(person, n_infos - (i + 1));
+		g_assert_cmpuint(counter, ==, 1);
 	}
 
 	/* Final sanity check that the person has no more contacts. */
-	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-	g_assert_cmpuint(n_items, ==, 0);
+	birb_assert_list_model_n_items(person, 0);
 
 	g_ptr_array_free(infos, TRUE);
 
@@ -447,11 +409,11 @@
 	PurpleContactInfo *priority = NULL;
 	PurplePerson *person = NULL;
 	PurplePresence *presence = NULL;
-	guint called = 0;
+	guint counter = 0;
 
 	person = purple_person_new();
-	g_signal_connect(person, "notify::priority-contact-info",
-	                 G_CALLBACK(test_purple_person_notify_cb), &called);
+	birb_count_property_changed(G_OBJECT(person), "priority-contact-info",
+	                            &counter);
 	priority = purple_person_get_priority_contact_info(person);
 	g_assert_null(priority);
 
@@ -464,7 +426,7 @@
 	purple_presence_set_primitive(presence,
 	                              PURPLE_PRESENCE_PRIMITIVE_AVAILABLE);
 
-	g_assert_cmpuint(called, ==, 1);
+	g_assert_cmpuint(counter, ==, 1);
 
 	priority = purple_person_get_priority_contact_info(person);
 	g_assert_true(priority == info);
@@ -485,9 +447,8 @@
 	PurpleContactInfo *sorted_contact = NULL;
 	PurplePerson *person = NULL;
 	PurplePresence *sorted_presence = NULL;
-	guint called = 0;
+	guint counter = 0;
 	int n_infos = 5;
-	guint n_items = 0;
 
 	/* This unit test is a bit complicated, but it adds 5 contact infos to a
 	 * person all whose presences are set to offline. After adding all the
@@ -501,8 +462,8 @@
 	 * priority-contact property.
 	 */
 	person = purple_person_new();
-	g_signal_connect(person, "notify::priority-contact-info",
-	                 G_CALLBACK(test_purple_person_notify_cb), &called);
+	birb_count_property_changed(G_OBJECT(person), "priority-contact-info",
+	                            &counter);
 	priority = purple_person_get_priority_contact_info(person);
 	g_assert_null(priority);
 
@@ -511,10 +472,10 @@
 		PurpleContactInfo *info = NULL;
 		char *username = NULL;
 
-		/* Set called to 0 as it shouldn't be called as the priority contact
+		/* Set counter to 0 as it shouldn't be called as the priority contact
 		 * info shouldn't change except for the first index.
 		 */
-		called = 0;
+		counter = 0;
 
 		/* Now create a real contact. */
 		username = g_strdup_printf("username%d", i + 1);
@@ -526,9 +487,9 @@
 
 		if(i == 0) {
 			first = g_object_ref(info);
-			g_assert_cmpuint(called, ==, 1);
+			g_assert_cmpuint(counter, ==, 1);
 		} else {
-			g_assert_cmpuint(called, ==, 0);
+			g_assert_cmpuint(counter, ==, 0);
 
 			if(i == n_infos - 2) {
 				PurplePresence *presence = NULL;
@@ -546,8 +507,7 @@
 		g_clear_object(&info);
 	}
 
-	n_items = g_list_model_get_n_items(G_LIST_MODEL(person));
-	g_assert_cmpuint(n_items, ==, n_infos);
+	birb_assert_list_model_n_items(person, n_infos);
 
 	priority = purple_person_get_priority_contact_info(person);
 	g_assert_true(priority == first);
@@ -556,12 +516,12 @@
 	/* Now set the second from the last contact info's status to available, and
 	 * verify that that contact info is now the priority contact info.
 	 */
-	called = 0;
+	counter = 0;
 	purple_presence_set_primitive(sorted_presence,
 	                              PURPLE_PRESENCE_PRIMITIVE_AVAILABLE);
 	priority = purple_person_get_priority_contact_info(person);
 	g_assert_true(priority == sorted_contact);
-	g_assert_cmpuint(called, ==, 1);
+	g_assert_cmpuint(counter, ==, 1);
 
 	/* Cleanup. */
 	purple_person_remove_all_contact_infos(person);
--- a/libpurple/tests/test_presence_manager.c	Tue May 20 17:21:16 2025 -0500
+++ b/libpurple/tests/test_presence_manager.c	Thu Jun 12 23:48:22 2025 -0500
@@ -19,6 +19,8 @@
 #include <glib.h>
 #include <glib/gstdio.h>
 
+#include <birb.h>
+
 #include <purple.h>
 
 /******************************************************************************
@@ -34,18 +36,6 @@
 	*counter = *counter + 1;
 }
 
-static void
-test_purple_presence_manager_list_changed_counter(G_GNUC_UNUSED GListModel *list,
-                                                  G_GNUC_UNUSED guint position,
-                                                  G_GNUC_UNUSED guint removed,
-                                                  G_GNUC_UNUSED guint added,
-                                                  gpointer data)
-{
-	guint *counter = data;
-
-	*counter = *counter + 1;
-}
-
 /******************************************************************************
  * Tests
  *****************************************************************************/
@@ -72,10 +62,9 @@
 	PurplePresenceManager *manager = NULL;
 	PurpleSavedPresence *presence = NULL;
 	gboolean success = FALSE;
-	guint len = 0;
 	guint added = 0;
 	guint removed = 0;
-	guint changed = 0;
+	guint counter = 0;
 	const char *id = NULL;
 
 	manager = purple_presence_manager_new(NULL);
@@ -87,35 +76,31 @@
 	g_signal_connect(manager, "removed",
 	                 G_CALLBACK(test_purple_presence_manager_add_remove_counter),
 	                 &removed);
-	g_signal_connect(manager, "items-changed",
-	                 G_CALLBACK(test_purple_presence_manager_list_changed_counter),
-	                 &changed);
+	birb_count_list_model_items_changed(G_LIST_MODEL(manager), &counter);
 
-	len = g_list_model_get_n_items(G_LIST_MODEL(manager));
 	/* The manager makes sure we always have online and offline presences. */
-	g_assert_cmpuint(len, ==, 2);
+	birb_assert_list_model_n_items(manager, 2);
 
 	presence = purple_presence_manager_create(manager);
 	g_assert_true(PURPLE_IS_SAVED_PRESENCE(presence));
 	purple_saved_presence_set_name(presence, "test presence");
 	g_assert_cmpuint(added, ==, 1);
 	g_assert_cmpuint(removed, ==, 0);
-	g_assert_cmpuint(changed, ==, 1);
+	g_assert_cmpuint(counter, ==, 1);
 
 	id = purple_saved_presence_get_id(presence);
 	g_assert_nonnull(id);
 
-	len = g_list_model_get_n_items(G_LIST_MODEL(manager));
-	g_assert_cmpuint(len, ==, 3);
+	birb_assert_list_model_n_items(manager, 3);
 
+	counter = 0;
 	success = purple_presence_manager_remove(manager, id);
 	g_assert_true(success);
 	g_assert_cmpuint(added, ==, 1);
 	g_assert_cmpuint(removed, ==, 1);
-	g_assert_cmpuint(changed, ==, 2);
+	g_assert_cmpuint(counter, ==, 1);
 
-	len = g_list_model_get_n_items(G_LIST_MODEL(manager));
-	g_assert_cmpuint(len, ==, 2);
+	birb_assert_list_model_n_items(manager, 2);
 
 	g_clear_object(&presence);
 	g_clear_object(&manager);
--- a/meson.build	Tue May 20 17:21:16 2025 -0500
+++ b/meson.build	Thu Jun 12 23:48:22 2025 -0500
@@ -226,7 +226,7 @@
 #######################################################################
 # Additional Dependencies
 #######################################################################
-birb_dep = dependency('birb', version : '>=0.3.1')
+birb_dep = dependency('birb', version : '>=0.4.0')
 gdk_pixbuf = dependency('gdk-pixbuf-2.0', version : '>= 2.26.0')
 gstreamer = dependency('gstreamer-1.0', version : '>=1.14')
 gstreamer_app = dependency('gstreamer-app-1.0')
--- a/subprojects/birb.wrap	Tue May 20 17:21:16 2025 -0500
+++ b/subprojects/birb.wrap	Thu Jun 12 23:48:22 2025 -0500
@@ -1,5 +1,5 @@
 [wrap-file]
-directory = birb-0.3.1
-source_url = https://sourceforge.net/projects/pidgin/files/birb/0.3.1/birb-0.3.1.tar.xz
-source_filename = birb-0.3.1.tar.xz
-source_hash = 70fa6462042f7d7c86a495eb93355fa14af057136b691e23838290bbcf57465c
+directory = birb-0.4.0
+source_url = https://sourceforge.net/projects/pidgin/files/birb/0.4.0/birb-0.4.0.tar.xz
+source_filename = birb-0.4.0.tar.xz
+source_hash = 8fcb67559a6bddb305f59be5c9cb12eb35ec45a0a9a6e4184bb1df33d0028084

mercurial