libpurple/tests/test_conversation_member.c

Fri, 07 Jun 2024 15:18:15 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Fri, 07 Jun 2024 15:18:15 -0500
changeset 42779
365eaa9d46f8
parent 42113
393c2ea6b399
child 42866
4b201e18638f
permissions
-rw-r--r--

Add ConversationMember:nickname and ConversationMember:name-for-display properties

Matrix and XMPP allow users to set a conversation specific nickname, these
properties allow us to support them while providing a method for the ui to know
which name to display.

I also did a few minor clean ups like dedenting [gs]et_property and `NULL`'d out the `nick` and `blurb` parameters for the existing properties.

Testing Done:
Ran the `conversation_member` tests under valgrind, and ran the turtles for good measure.

Bugs closed: PIDGIN-17862

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

/*
 * 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>

/******************************************************************************
 * Callbacks
 *****************************************************************************/
static void
test_purple_conversation_member_notify_counter(GObject *self,
                                               G_GNUC_UNUSED GParamSpec *pspec,
                                               gpointer data)
{
	guint *counter = data;

	g_assert_true(PURPLE_IS_CONVERSATION_MEMBER(self));

	*counter = *counter + 1;
}

/******************************************************************************
 * Tests
 *****************************************************************************/
static void
test_purple_conversation_member_new(void) {
	PurpleContactInfo *info = NULL;
	PurpleConversationMember *member = NULL;

	info = purple_contact_info_new(NULL);
	g_assert_true(PURPLE_IS_CONTACT_INFO(info));

	member = purple_conversation_member_new(info);
	g_assert_true(PURPLE_IS_CONVERSATION_MEMBER(member));

	g_clear_object(&info);
	g_clear_object(&member);
}

static void
test_purple_conversation_member_properties(void) {
	PurpleContactInfo *info = NULL;
	PurpleContactInfo *info1 = NULL;
	PurpleConversationMember *member = NULL;
	PurpleTags *tags = NULL;
	PurpleTypingState typing_state = PURPLE_TYPING_STATE_NONE;
	char *name_for_display = NULL;
	char *nickname = NULL;

	info = purple_contact_info_new("abc123");

	/* Use g_object_new so we can test setting properties by name. All of them
	 * call the setter methods, so by doing it this way we exercise more of the
	 * code.
	 */
	member = g_object_new(
		PURPLE_TYPE_CONVERSATION_MEMBER,
		"contact-info", info,
		"nickname", "pidgy",
		"typing-state", PURPLE_TYPING_STATE_TYPING,
		NULL);

	/* Now use g_object_get to read all of the properties. */
	g_object_get(member,
		"contact-info", &info1,
		"name-for-display", &name_for_display,
		"nickname", &nickname,
		"tags", &tags,
		"typing-state", &typing_state,
		NULL);

	g_assert_true(info1 == info);
	g_clear_object(&info1);

	g_assert_cmpstr(name_for_display, ==, "pidgy");
	g_clear_pointer(&name_for_display, g_free);

	g_assert_cmpstr(nickname, ==, "pidgy");
	g_clear_pointer(&nickname, g_free);

	g_assert_true(PURPLE_IS_TAGS(tags));
	g_clear_object(&tags);

	g_assert_cmpint(typing_state, ==, PURPLE_TYPING_STATE_TYPING);

	g_assert_finalize_object(member);
	g_assert_finalize_object(info);
}

static void
test_purple_conversation_member_name_for_display(void) {
	PurpleContactInfo *info = NULL;
	PurpleConversationMember *member = NULL;
	const char *name_for_display = NULL;
	guint counter = 0;

	info = purple_contact_info_new("abc123");
	member = purple_conversation_member_new(info);
	g_signal_connect(member, "notify::name-for-display",
	                 G_CALLBACK(test_purple_conversation_member_notify_counter),
	                 &counter);

	/* Make sure our counter is still 0. */
	g_assert_cmpuint(counter, ==, 0);

	/* Make sure the default falls back to the contact info's id. */
	name_for_display = purple_conversation_member_get_name_for_display(member);
	g_assert_cmpstr(name_for_display, ==, "abc123");

	/* Set the username on the contact info and make sure it propagates up. */
	purple_contact_info_set_username(info, "tron");
	name_for_display = purple_conversation_member_get_name_for_display(member);
	g_assert_cmpstr(name_for_display, ==, "tron");
	g_assert_cmpuint(counter, ==, 1);

	/* Set the nickname on the conversation member and make sure that takes
	 * precedence.
	 */
	purple_conversation_member_set_nickname(member, "rinzler");
	name_for_display = purple_conversation_member_get_name_for_display(member);
	g_assert_cmpstr(name_for_display, ==, "rinzler");
	g_assert_cmpuint(counter, ==, 2);

	/* Remove the nickname and verify it falls back to the value from the
	 * contact info.
	 */
	purple_conversation_member_set_nickname(member, NULL);
	name_for_display = purple_conversation_member_get_name_for_display(member);
	g_assert_cmpstr(name_for_display, ==, "tron");
	g_assert_cmpuint(counter, ==, 3);

	g_assert_finalize_object(member);
	g_assert_finalize_object(info);
}

/******************************************************************************
 * Typing State Timeout
 *****************************************************************************/
static void
test_purple_conversation_manager_timeout_notify(G_GNUC_UNUSED GObject *obj,
                                                G_GNUC_UNUSED GParamSpec *pspec,
                                                gpointer data)
{
	GMainLoop *loop = data;
	static guint count = 0;

	/* Increment count each time we're called. We're expecting to be called
	 * twice, so after that quit the main loop.
	 */
	count++;
	if(count >= 2) {
		g_main_loop_quit(loop);
	}
}

static gboolean
test_purple_conversation_manager_timeout_fail_safe(gpointer data) {
	GMainLoop *loop = data;

	g_warning("fail safe triggered");

	g_main_loop_quit(loop);

	return G_SOURCE_REMOVE;
}

static void
test_purple_conversation_member_typing_state_timeout(void) {
	PurpleContactInfo *info = NULL;
	PurpleConversationMember *member = NULL;
	PurpleTypingState typing_state = PURPLE_TYPING_STATE_TYPING;
	GMainLoop *loop = NULL;

	/* Create the main loop as we'll need it to let the timeout fire. */
	loop = g_main_loop_new(NULL, FALSE);

	/* Create the member and add a notify callback on the typing-state property
	 * so we can check it and exit the main loop.
	 */
	info = purple_contact_info_new(NULL);
	member = purple_conversation_member_new(info);
	g_signal_connect(member, "notify::typing-state",
	                 G_CALLBACK(test_purple_conversation_manager_timeout_notify),
	                 loop);

	/* Set the state to typing with a timeout of 1 second. */
	purple_conversation_member_set_typing_state(member,
	                                            PURPLE_TYPING_STATE_TYPING, 1);

	/* Add a fail safe timeout at 2 seconds to make sure the test won't get
	 * stuck waiting forever.
	 */
	g_timeout_add_seconds(2,
	                      test_purple_conversation_manager_timeout_fail_safe,
	                      loop);

	/* Run the main loop and let the timeouts fire. */
	g_main_loop_run(loop);

	/* Verify that our state got reset back to PURPLE_TYPING_STATE_NONE. */
	typing_state = purple_conversation_member_get_typing_state(member);
	g_assert_cmpint(typing_state, ==, PURPLE_TYPING_STATE_NONE);

	/* Clean everything up. */
	g_clear_object(&info);
	g_clear_object(&member);
}

/******************************************************************************
 * Main
 *****************************************************************************/
gint
main(gint argc, gchar *argv[]) {
	g_test_init(&argc, &argv, NULL);

	g_test_add_func("/conversation-member/new",
	                test_purple_conversation_member_new);
	g_test_add_func("/conversation-member/properties",
	                test_purple_conversation_member_properties);
	g_test_add_func("/conversation-member/name-for-display",
	                test_purple_conversation_member_name_for_display);

	g_test_add_func("/conversation-member/typing-state/timeout",
	                test_purple_conversation_member_typing_state_timeout);

	return g_test_run();
}

mercurial