# HG changeset patch
# Node ID 0d571e288e91795b88e6c5e1a7c1661873035246
# Parent  27c407608b6b5563fc605d00e78a4025dcab64ae
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -17,6 +17,7 @@
 	'purpleattachment.c',
 	'purpleauthorizationrequest.c',
 	'purpleavatar.c',
+	'purplebadge.c',
 	'purplechanneljoindetails.c',
 	'purpleconnectionerrorinfo.c',
 	'purplecontact.c',
@@ -105,6 +106,7 @@
 	'purpleaddcontactrequest.h',
 	'purpleauthorizationrequest.h',
 	'purpleavatar.h',
+	'purplebadge.h',
 	'purplechanneljoindetails.h',
 	'purpleconnectionerrorinfo.h',
 	'purplecontact.h',
diff --git a/libpurple/purplebadge.c b/libpurple/purplebadge.c
new file mode 100644
--- /dev/null
+++ b/libpurple/purplebadge.c
@@ -0,0 +1,451 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "purplebadge.h"
+
+#include "util.h"
+
+struct _PurpleBadge {
+	GObject parent;
+
+	char *id;
+	int priority;
+	char *icon_name;
+	char *mnemonic;
+	char *tooltip_text;
+	char *description;
+
+	char *link_text;
+	char *link_uri;
+};
+
+enum {
+	PROP_0,
+	PROP_ID,
+	PROP_PRIORITY,
+	PROP_ICON_NAME,
+	PROP_MNEMONIC,
+	PROP_TOOLTIP_TEXT,
+	PROP_DESCRIPTION,
+	PROP_LINK_TEXT,
+	PROP_LINK_URI,
+	N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL, };
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+purple_badge_set_id(PurpleBadge *badge, const char *id) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(g_set_str(&badge->id, id)) {
+		g_object_notify_by_pspec(G_OBJECT(badge), properties[PROP_ID]);
+	}
+}
+
+static void
+purple_badge_set_priority(PurpleBadge *badge, int priority) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(badge->priority != priority) {
+		badge->priority = priority;
+
+		g_object_notify_by_pspec(G_OBJECT(badge), properties[PROP_PRIORITY]);
+	}
+}
+
+static void
+purple_badge_set_icon_name(PurpleBadge *badge, const char *icon_name) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(g_set_str(&badge->icon_name, icon_name)) {
+		g_object_notify_by_pspec(G_OBJECT(badge), properties[PROP_ICON_NAME]);
+	}
+}
+
+static void
+purple_badge_set_mnemonic(PurpleBadge *badge, const char *mnemonic) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(g_set_str(&badge->mnemonic, mnemonic)) {
+		g_object_notify_by_pspec(G_OBJECT(badge), properties[PROP_MNEMONIC]);
+	}
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_FINAL_TYPE(PurpleBadge, purple_badge,
+                    G_TYPE_OBJECT)
+
+static void
+purple_badge_get_property(GObject *obj, guint param_id, GValue *value,
+                          GParamSpec *pspec)
+{
+	PurpleBadge *badge = PURPLE_BADGE(obj);
+
+	switch(param_id) {
+	case PROP_ID:
+		g_value_set_string(value, purple_badge_get_id(badge));
+		break;
+	case PROP_PRIORITY:
+		g_value_set_int(value, purple_badge_get_priority(badge));
+		break;
+	case PROP_ICON_NAME:
+		g_value_set_string(value, purple_badge_get_icon_name(badge));
+		break;
+	case PROP_MNEMONIC:
+		g_value_set_string(value, purple_badge_get_mnemonic(badge));
+		break;
+	case PROP_TOOLTIP_TEXT:
+		g_value_set_string(value, purple_badge_get_tooltip_text(badge));
+		break;
+	case PROP_DESCRIPTION:
+		g_value_set_string(value, purple_badge_get_description(badge));
+		break;
+	case PROP_LINK_TEXT:
+		g_value_set_string(value, purple_badge_get_link_text(badge));
+		break;
+	case PROP_LINK_URI:
+		g_value_set_string(value, purple_badge_get_link_uri(badge));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_badge_set_property(GObject *obj, guint param_id, const GValue *value,
+                          GParamSpec *pspec)
+{
+	PurpleBadge *badge = PURPLE_BADGE(obj);
+
+	switch(param_id) {
+	case PROP_ID:
+		purple_badge_set_id(badge, g_value_get_string(value));
+		break;
+	case PROP_PRIORITY:
+		purple_badge_set_priority(badge, g_value_get_int(value));
+		break;
+	case PROP_ICON_NAME:
+		purple_badge_set_icon_name(badge, g_value_get_string(value));
+		break;
+	case PROP_MNEMONIC:
+		purple_badge_set_mnemonic(badge, g_value_get_string(value));
+		break;
+	case PROP_TOOLTIP_TEXT:
+		purple_badge_set_tooltip_text(badge, g_value_get_string(value));
+		break;
+	case PROP_DESCRIPTION:
+		purple_badge_set_description(badge, g_value_get_string(value));
+		break;
+	case PROP_LINK_TEXT:
+		purple_badge_set_link_text(badge, g_value_get_string(value));
+		break;
+	case PROP_LINK_URI:
+		purple_badge_set_link_uri(badge, g_value_get_string(value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+		break;
+	}
+}
+
+static void
+purple_badge_finalize(GObject *obj) {
+	PurpleBadge *badge = PURPLE_BADGE(obj);
+
+	g_clear_pointer(&badge->id, g_free);
+	g_clear_pointer(&badge->icon_name, g_free);
+	g_clear_pointer(&badge->mnemonic, g_free);
+	g_clear_pointer(&badge->tooltip_text, g_free);
+	g_clear_pointer(&badge->description, g_free);
+	g_clear_pointer(&badge->link_text, g_free);
+	g_clear_pointer(&badge->link_uri, g_free);
+
+	G_OBJECT_CLASS(purple_badge_parent_class)->finalize(obj);
+}
+
+static void
+purple_badge_init(G_GNUC_UNUSED PurpleBadge *badge) {
+}
+
+static void
+purple_badge_class_init(PurpleBadgeClass *klass)
+{
+	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+	obj_class->get_property = purple_badge_get_property;
+	obj_class->set_property = purple_badge_set_property;
+	obj_class->finalize = purple_badge_finalize;
+
+	/**
+	 * PurpleBadge:id:
+	 *
+	 * The id for this badge.
+	 *
+	 * This should be name spaced to avoid collisions. For example, the IRCv3
+	 * protocol would use ircv3-prefix-operator for operators.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_ID] = g_param_spec_string(
+		"id", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleBadge:priority:
+	 *
+	 * The priority of this badge.
+	 *
+	 * Badges with higher priorities will be sorted first.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_PRIORITY] = g_param_spec_int(
+		"priority", NULL, NULL,
+		G_MININT32, G_MAXINT32, 0,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleBadge:icon-name:
+	 *
+	 * The name of the icon for the badge.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_ICON_NAME] = g_param_spec_string(
+		"icon-name", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleBadge:mnemonic:
+	 *
+	 * The mnemonic for the badge.
+	 *
+	 * The mnemonic is a fallback in case the the icon can not be found or can
+	 * be used by text interfaces.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_MNEMONIC] = g_param_spec_string(
+		"mnemonic", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleBadge:tooltip-text:
+	 *
+	 * Text to be displayed in the tooltip for this badge.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_TOOLTIP_TEXT] = g_param_spec_string(
+		"tooltip-text", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleBadge:description:
+	 *
+	 * The description of the badge.
+	 *
+	 * This may be shown as part of the tool tip to describe to the end user
+	 * what this badge is for.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_DESCRIPTION] = g_param_spec_string(
+		"description", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleBadge:link-text:
+	 *
+	 * The text to display for the link of the badge.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_LINK_TEXT] = g_param_spec_string(
+		"link-text", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	/**
+	 * PurpleBadge:link-uri:
+	 *
+	 * A URI for the badge that could link to a page describing more about it.
+	 *
+	 * Since: 3.0
+	 */
+	properties[PROP_LINK_URI] = g_param_spec_string(
+		"link-uri", NULL, NULL,
+		NULL,
+		G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleBadge *
+purple_badge_new(const char *id, int priority, const char *icon_name,
+                 const char *mnemonic)
+{
+	g_return_val_if_fail(!purple_strempty(id), NULL);
+	g_return_val_if_fail(!purple_strempty(icon_name), NULL);
+	g_return_val_if_fail(!purple_strempty(mnemonic), NULL);
+
+	return g_object_new(
+		PURPLE_TYPE_BADGE,
+		"id", id,
+		"priority", priority,
+		"icon-name", icon_name,
+		"mnemonic", mnemonic,
+		NULL);
+}
+
+const char *
+purple_badge_get_id(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), NULL);
+
+	return badge->id;
+}
+
+int
+purple_badge_get_priority(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), 0);
+
+	return badge->priority;
+}
+
+const char *
+purple_badge_get_icon_name(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), NULL);
+
+	return badge->icon_name;
+}
+
+const char *
+purple_badge_get_mnemonic(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), NULL);
+
+	return badge->mnemonic;
+}
+
+const char *
+purple_badge_get_tooltip_text(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), NULL);
+
+	return badge->tooltip_text;
+}
+
+void
+purple_badge_set_tooltip_text(PurpleBadge *badge, const char *tooltip_text) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(g_set_str(&badge->tooltip_text, tooltip_text)) {
+		g_object_notify_by_pspec(G_OBJECT(badge),
+		                         properties[PROP_TOOLTIP_TEXT]);
+	}
+}
+
+const char *
+purple_badge_get_description(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), NULL);
+
+	return badge->description;
+}
+
+void
+purple_badge_set_description(PurpleBadge *badge, const char *description) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(g_set_str(&badge->description, description)) {
+		g_object_notify_by_pspec(G_OBJECT(badge),
+		                         properties[PROP_DESCRIPTION]);
+	}
+}
+
+const char *
+purple_badge_get_link_text(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), NULL);
+
+	return badge->link_text;
+}
+
+void
+purple_badge_set_link_text(PurpleBadge *badge, const char *link_text) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(g_set_str(&badge->link_text, link_text)) {
+		g_object_notify_by_pspec(G_OBJECT(badge), properties[PROP_LINK_TEXT]);
+	}
+}
+
+const char *
+purple_badge_get_link_uri(PurpleBadge *badge) {
+	g_return_val_if_fail(PURPLE_IS_BADGE(badge), NULL);
+
+	return badge->link_uri;
+}
+
+void
+purple_badge_set_link_uri(PurpleBadge *badge, const char *link_uri) {
+	g_return_if_fail(PURPLE_IS_BADGE(badge));
+
+	if(g_set_str(&badge->link_uri, link_uri)) {
+		g_object_notify_by_pspec(G_OBJECT(badge), properties[PROP_LINK_URI]);
+	}
+}
+
+int
+purple_badge_compare(PurpleBadge *badge1, PurpleBadge *badge2) {
+	if(badge1 == NULL && badge2 == NULL) {
+		return 0;
+	}
+
+	if(!PURPLE_IS_BADGE(badge1)) {
+		return 1;
+	}
+
+	if(!PURPLE_IS_BADGE(badge2)) {
+		return -1;
+	}
+
+	if(badge1->priority == badge2->priority) {
+		return 0;
+	}
+
+	if(badge1->priority > badge2->priority) {
+		return -1;
+	}
+
+	return 1;
+}
diff --git a/libpurple/purplebadge.h b/libpurple/purplebadge.h
new file mode 100644
--- /dev/null
+++ b/libpurple/purplebadge.h
@@ -0,0 +1,244 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
+# error "only <purple.h> may be included directly"
+#endif
+
+#ifndef PURPLE_BADGE_H
+#define PURPLE_BADGE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "purpleversion.h"
+
+G_BEGIN_DECLS
+
+/**
+ * PurpleBadge:
+ *
+ * #PurpleBadge is a data structure for badges. They are intended to be used
+ * on [class@ConversationMembers] to display badges like "admin", "moderator",
+ * "broadcaster", etc.
+ *
+ * Since: 3.0
+ */
+
+#define PURPLE_TYPE_BADGE (purple_badge_get_type())
+
+PURPLE_AVAILABLE_IN_3_0
+G_DECLARE_FINAL_TYPE(PurpleBadge, purple_badge, PURPLE, BADGE, GObject)
+
+/**
+ * purple_badge_new:
+ * @id: The id.
+ * @priority: The priority.
+ * @icon_name: The icon name.
+ * @mnemonic: A character as a mnemonic.
+ *
+ * Creates a new badge.
+ *
+ * Returns: (transfer full): The new instance.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+PurpleBadge *purple_badge_new(const char *id, int priority, const char *icon_name, const char *mnemonic);
+
+/**
+ * purple_badge_get_id:
+ * @badge: The instance.
+ *
+ * Gets the id of @badge.
+ *
+ * Returns: The id of @badge.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_badge_get_id(PurpleBadge *badge);
+
+/**
+ * purple_badge_get_priority:
+ * @badge: The instance.
+ *
+ * Gets the priority of @badge.
+ *
+ * Returns: The priority of @badge.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+int purple_badge_get_priority(PurpleBadge *badge);
+
+/**
+ * purple_badge_get_icon_name:
+ * @badge: The instance.
+ *
+ * Gets the icon-name from @badge.
+ *
+ * Returns: The icon-name.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_badge_get_icon_name(PurpleBadge *badge);
+
+/**
+ * purple_badge_get_mnemonic:
+ * @badge: The instance.
+ *
+ * Gets the mnemonic from @badge.
+ *
+ * Returns: The mnemonic.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_badge_get_mnemonic(PurpleBadge *badge);
+
+/**
+ * purple_badge_get_tooltip_text:
+ * @badge: The instance.
+ *
+ * Gets the tooltip text from @badge.
+ *
+ * Returns: (nullable): The tooltip text.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_badge_get_tooltip_text(PurpleBadge *badge);
+
+/**
+ * purple_badge_set_tooltip_text:
+ * @badge: The instance.
+ * @tooltip_text: (nullable): The new tooltip text.
+ *
+ * Sets the tooltip text of @badge.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_badge_set_tooltip_text(PurpleBadge *badge, const char *tooltip_text);
+
+/**
+ * purple_badge_get_description:
+ * @badge: The instance.
+ *
+ * Gets the description of @badge.
+ *
+ * This can be used by user interfaces to tell the user what this badge
+ * represents.
+ *
+ * Returns: (nullable): The description of @badge.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_badge_get_description(PurpleBadge *badge);
+
+/**
+ * purple_badge_set_description:
+ * @badge: The instance.
+ * @description: (nullable): The new description.
+ *
+ * Sets the description of @badge to @description.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_badge_set_description(PurpleBadge *badge, const char *description);
+
+/**
+ * purple_badge_get_link_text:
+ * @badge: The instance.
+ *
+ * Gets the text that should be displayed when displaying the link for @badge.
+ *
+ * Returns: (nullable): The link text.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_badge_get_link_text(PurpleBadge *badge);
+
+/**
+ * purple_badge_set_link_text:
+ * @badge: The instance.
+ * @link_text: (nullable): The new link text.
+ *
+ * Sets the link text of @badge to @link_text.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_badge_set_link_text(PurpleBadge *badge, const char *link_text);
+
+/**
+ * purple_badge_get_link_uri:
+ * @badge: The instance.
+ *
+ * Gets the link URI of @badge.
+ *
+ * Returns: (nullable): The URI.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+const char *purple_badge_get_link_uri(PurpleBadge *badge);
+
+/**
+ * purple_badge_set_link_uri:
+ * @badge: The instance.
+ * @link_uri: (nullable): The new link URI.
+ *
+ * Sets the link URI of @badge to @link_uri.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+void purple_badge_set_link_uri(PurpleBadge *badge, const char *link_uri);
+
+/**
+ * purple_badge_compare:
+ * @badge1: (nullable): The first badge.
+ * @badge2: (nullable): The second badge.
+ *
+ * Gets which badge has higher priority.
+ *
+ * If @badge1 has a higher priority then -1 will be returned. If their
+ * priorities are equal, 0 will be returned. If @badge2 has a higher priority,
+ * 1 will be returned.
+ *
+ * Returns: -1 if @badge1 has higher priorty, 0 if they have equal priorities,
+ *          and 1 if @badge2 has a higher priority.
+ *
+ * Since: 3.0
+ */
+PURPLE_AVAILABLE_IN_3_0
+int purple_badge_compare(PurpleBadge *badge1, PurpleBadge *badge2);
+
+G_END_DECLS
+
+#endif /* PURPLE_BADGE_H */
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -2,6 +2,7 @@
     'account_option',
     'account_manager',
     'authorization_request',
+    'badge',
     'channel_join_details',
     'circular_buffer',
     'create_conversation_details',
diff --git a/libpurple/tests/test_badge.c b/libpurple/tests/test_badge.c
new file mode 100644
--- /dev/null
+++ b/libpurple/tests/test_badge.c
@@ -0,0 +1,154 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <purple.h>
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_purple_badge_properties(void) {
+	PurpleBadge *badge;
+	char *description;
+	char *icon_name;
+	char *id;
+	char *link_text;
+	char *link_uri;
+	char *mnemonic;
+	char *tooltip_text;
+	int priority;
+
+	badge = g_object_new(
+		PURPLE_TYPE_BADGE,
+		"description", "description",
+		"icon-name", "icon-name",
+		"id", "test-badge",
+		"link-text", "pidgy",
+		"link-uri", "https://pidgin.im/",
+		"mnemonic", "@",
+		"priority", 1000,
+		"tooltip-text", "tooltip-text",
+		NULL);
+
+	g_object_get(
+		badge,
+		"description", &description,
+		"icon-name", &icon_name,
+		"id", &id,
+		"link-text", &link_text,
+		"link-uri", &link_uri,
+		"mnemonic", &mnemonic,
+		"priority", &priority,
+		"tooltip-text", &tooltip_text,
+		NULL);
+
+	g_assert_cmpstr(description, ==, "description");
+	g_clear_pointer(&description, g_free);
+
+	g_assert_cmpstr(icon_name, ==, "icon-name");
+	g_clear_pointer(&icon_name, g_free);
+
+	g_assert_cmpstr(id, ==, "test-badge");
+	g_clear_pointer(&id, g_free);
+
+	g_assert_cmpstr(link_text, ==, "pidgy");
+	g_clear_pointer(&link_text, g_free);
+
+	g_assert_cmpstr(link_uri, ==, "https://pidgin.im/");
+	g_clear_pointer(&link_uri, g_free);
+
+	g_assert_cmpstr(mnemonic, ==, "@");
+	g_clear_pointer(&mnemonic, g_free);
+
+	g_assert_cmpint(priority, ==, 1000);
+
+	g_assert_cmpstr(tooltip_text, ==, "tooltip-text");
+	g_clear_pointer(&tooltip_text, g_free);
+
+	g_assert_finalize_object(badge);
+}
+
+static void
+test_purple_badge_compare_first(void) {
+	PurpleBadge *badge1 = NULL;
+	PurpleBadge *badge2 = NULL;
+	int result = 0;
+
+	badge1 = purple_badge_new("one", 1000, "icon1", "@");
+	badge2 = purple_badge_new("two", -1000, "icon2", "+");
+
+	result = purple_badge_compare(badge1, badge2);
+
+	g_assert_cmpint(result, ==, -1);
+
+	g_assert_finalize_object(badge1);
+	g_assert_finalize_object(badge2);
+}
+
+static void
+test_purple_badge_compare_equal(void) {
+	PurpleBadge *badge1 = NULL;
+	PurpleBadge *badge2 = NULL;
+	int result = 0;
+
+	badge1 = purple_badge_new("one", 500, "icon1", "@");
+	badge2 = purple_badge_new("two", 500, "icon2", "+");
+
+	result = purple_badge_compare(badge1, badge2);
+
+	g_assert_cmpint(result, ==, 0);
+
+	g_assert_finalize_object(badge1);
+	g_assert_finalize_object(badge2);
+}
+
+static void
+test_purple_badge_compare_second(void) {
+	PurpleBadge *badge1 = NULL;
+	PurpleBadge *badge2 = NULL;
+	int result = 0;
+
+	badge1 = purple_badge_new("one", -1000, "icon1", "@");
+	badge2 = purple_badge_new("two", -500, "icon2", "+");
+
+	result = purple_badge_compare(badge1, badge2);
+
+	g_assert_cmpint(result, ==, 1);
+
+	g_assert_finalize_object(badge1);
+	g_assert_finalize_object(badge2);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+int
+main(int argc, char *argv[]) {
+	g_test_init(&argc, &argv, NULL);
+	g_test_set_nonfatal_assertions();
+
+	g_test_add_func("/badge/properties", test_purple_badge_properties);
+
+	g_test_add_func("/badge/compare/first", test_purple_badge_compare_first);
+	g_test_add_func("/badge/compare/equal", test_purple_badge_compare_equal);
+	g_test_add_func("/badge/compare/second", test_purple_badge_compare_second);
+
+	return g_test_run();
+}
