mirror of
https://gitlab.gnome.org/GNOME/calls.git
synced 2024-11-16 13:25:39 +00:00
6d122b066f
This will get removed soon while refactoring the ringer as cancelling the async methods would not guarantee that the requested operation would not be performed. It could actually already be started (e.g. starting or stopping the feedback), but we have not yet received the reply, so it was always a bit flaky.
537 lines
14 KiB
C
537 lines
14 KiB
C
/*
|
|
* Copyright (C) 2021 Purism SPC
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
*
|
|
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
|
*
|
|
*/
|
|
|
|
#include "calls-manager.h"
|
|
#include "calls-ringer.h"
|
|
#include "calls-ui-call-data.h"
|
|
#include "mock-call.h"
|
|
#include "mock-libfeedback.h"
|
|
#include "mock-contacts-provider.h"
|
|
|
|
#include <cmocka.h>
|
|
#include <setjmp.h>
|
|
|
|
|
|
/* mock libfeedback functions */
|
|
|
|
static gboolean
|
|
on_mock_timeout (gpointer user_data)
|
|
{
|
|
GTask *task;
|
|
GCancellable *cancellable;
|
|
|
|
if (!G_IS_TASK (user_data))
|
|
return G_SOURCE_REMOVE;
|
|
|
|
task = G_TASK (user_data);
|
|
cancellable = g_task_get_cancellable (task);
|
|
|
|
if (!g_cancellable_is_cancelled (cancellable))
|
|
g_task_return_boolean (task, TRUE);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static gboolean
|
|
on_check_task_cancelled (gpointer user_data)
|
|
{
|
|
GTask *task;
|
|
|
|
if (!G_IS_TASK (user_data))
|
|
return G_SOURCE_REMOVE;
|
|
|
|
task = G_TASK (user_data);
|
|
|
|
if (g_task_get_completed (task) || g_task_return_error_if_cancelled (task))
|
|
return G_SOURCE_REMOVE;
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
|
|
gboolean
|
|
__wrap_lfb_init (const char *app_id,
|
|
GError **error)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void
|
|
__wrap_lfb_uninit (void)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
__wrap_lfb_event_set_feedback_profile (LfbEvent *self,
|
|
const char *profile)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
__wrap_lfb_event_trigger_feedback_async (LfbEvent *self,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *trigger_task = g_task_new (self, cancellable, callback, user_data);
|
|
int mock_time_ms = mock_type (int);
|
|
|
|
g_timeout_add (mock_time_ms, on_mock_timeout, trigger_task);
|
|
g_idle_add (G_SOURCE_FUNC (on_check_task_cancelled), trigger_task);
|
|
}
|
|
|
|
|
|
gboolean
|
|
__wrap_lfb_event_trigger_feedback_finish (LfbEvent *self,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
GTask *task = G_TASK (res);
|
|
gboolean ret;
|
|
|
|
ret = g_task_propagate_boolean (task, error);
|
|
|
|
g_object_unref (task);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
void
|
|
__wrap_lfb_event_end_feedback_async (LfbEvent *self,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
GTask *trigger_task = g_task_new (self, cancellable, callback, user_data);
|
|
int mock_time_ms = mock_type (int);
|
|
|
|
g_timeout_add (mock_time_ms, on_mock_timeout, trigger_task);
|
|
}
|
|
|
|
|
|
gboolean
|
|
__wrap_lfb_event_end_feedback_finish (LfbEvent *self,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
GTask *task = G_TASK (res);
|
|
gboolean ret;
|
|
|
|
ret = g_task_propagate_boolean (G_TASK (res), error);
|
|
|
|
g_object_unref (task);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
CallsContactsProvider *
|
|
__wrap_calls_contacts_provider_new (void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* add or remove calls */
|
|
|
|
static void
|
|
add_call (CallsManager *manager,
|
|
CallsUiCallData *call)
|
|
{
|
|
g_assert (CALLS_IS_MANAGER (manager));
|
|
g_assert (CALLS_IS_UI_CALL_DATA (call));
|
|
|
|
g_signal_emit_by_name (manager, "ui-call-added", call, NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
remove_call (CallsManager *manager,
|
|
CallsUiCallData *call)
|
|
{
|
|
g_assert (CALLS_IS_MANAGER (manager));
|
|
g_assert (CALLS_IS_UI_CALL_DATA (call));
|
|
|
|
g_signal_emit_by_name (manager, "ui-call-removed", call, NULL);
|
|
}
|
|
|
|
/* TestData setup and tear down */
|
|
typedef struct {
|
|
CallsManager *manager;
|
|
CallsRinger *ringer;
|
|
CallsMockCall *call_one;
|
|
CallsUiCallData *ui_call_one;
|
|
CallsMockCall *call_two;
|
|
CallsUiCallData *ui_call_two;
|
|
GMainLoop *loop;
|
|
} TestData;
|
|
|
|
|
|
static int
|
|
setup_test_data (void **state)
|
|
{
|
|
TestData *data = g_new0 (TestData, 1);
|
|
|
|
if (data == NULL)
|
|
return -1;
|
|
|
|
data->manager = calls_manager_get_default ();
|
|
data->ringer = calls_ringer_new ();
|
|
data->call_one = calls_mock_call_new ();
|
|
data->ui_call_one = calls_ui_call_data_new (CALLS_CALL (data->call_one), NULL);
|
|
data->call_two = calls_mock_call_new ();
|
|
data->ui_call_two = calls_ui_call_data_new (CALLS_CALL (data->call_two), NULL);
|
|
data->loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
*state = data;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
tear_down_test_data (void **state)
|
|
{
|
|
TestData *data = *state;
|
|
|
|
g_object_unref (data->call_one);
|
|
g_object_unref (data->ui_call_one);
|
|
g_object_unref (data->call_two);
|
|
g_object_unref (data->ui_call_two);
|
|
g_object_unref (data->ringer);
|
|
g_main_loop_unref (data->loop);
|
|
|
|
g_free (data);
|
|
return 0;
|
|
}
|
|
|
|
/* t1: test_ringing_incoming_call */
|
|
static void
|
|
t1_on_ringer_call_accepted (CallsRinger *ringer,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
static guint test_phase = 0;
|
|
TestData *data = user_data;
|
|
|
|
switch (test_phase++) {
|
|
case 0: /* incoming call */
|
|
assert_true (calls_ringer_get_is_ringing (ringer));
|
|
calls_call_answer (CALLS_CALL (data->call_one));
|
|
break;
|
|
case 1: /* incoming call accepted */
|
|
assert_false (calls_ringer_get_is_ringing (ringer));
|
|
g_main_loop_quit ((GMainLoop *) data->loop);
|
|
break;
|
|
default:
|
|
g_assert_not_reached (); /* did not find equivalent cmocka assertion */
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
test_ringing_accept_call (void **state)
|
|
{
|
|
TestData *data = *state;
|
|
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
|
|
g_signal_connect (data->ringer,
|
|
"notify::ringing",
|
|
G_CALLBACK (t1_on_ringer_call_accepted),
|
|
data);
|
|
|
|
/* delay before completion of __wrap_lfb_event_trigger_feedback_async() */
|
|
will_return (__wrap_lfb_event_trigger_feedback_async, 10);
|
|
/* delay before completion of __wrap_lfb_event_end_feedback_async() */
|
|
will_return (__wrap_lfb_event_end_feedback_async, 10);
|
|
|
|
calls_call_set_state (CALLS_CALL (data->call_one), CALLS_CALL_STATE_INCOMING);
|
|
add_call (data->manager, data->ui_call_one);
|
|
|
|
/* main loop will quit in callback of notify::ring */
|
|
g_main_loop_run (data->loop);
|
|
|
|
remove_call (data->manager, data->ui_call_one);
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
}
|
|
|
|
/* t2: test_ringing_hang_up_call */
|
|
static void
|
|
t2_on_ringer_call_hang_up (CallsRinger *ringer,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
static guint test_phase = 0;
|
|
TestData *data = user_data;
|
|
|
|
switch (test_phase++) {
|
|
case 0: /* incoming call */
|
|
assert_true (calls_ringer_get_is_ringing (ringer));
|
|
calls_call_hang_up (CALLS_CALL (data->call_one));
|
|
break;
|
|
case 1: /* incoming call hung up */
|
|
assert_false (calls_ringer_get_is_ringing (ringer));
|
|
g_main_loop_quit ((GMainLoop *) data->loop);
|
|
break;
|
|
default:
|
|
g_assert_not_reached (); /* did not find equivalent cmocka assertion */
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
test_ringing_hang_up_call (void **state)
|
|
{
|
|
TestData *data = *state;
|
|
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
|
|
g_signal_connect (data->ringer,
|
|
"notify::ringing",
|
|
G_CALLBACK (t2_on_ringer_call_hang_up),
|
|
data);
|
|
|
|
/* delay before completion of __wrap_lfb_event_trigger_feedback_async() */
|
|
will_return (__wrap_lfb_event_trigger_feedback_async, 10);
|
|
/* delay before completion of __wrap_lfb_event_end_feedback_async() */
|
|
will_return (__wrap_lfb_event_end_feedback_async, 10);
|
|
|
|
calls_call_set_state (CALLS_CALL (data->call_one), CALLS_CALL_STATE_INCOMING);
|
|
add_call (data->manager, data->ui_call_one);
|
|
|
|
/* main loop will quit in callback of notify::ring */
|
|
g_main_loop_run (data->loop);
|
|
|
|
remove_call (data->manager, data->ui_call_one);
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
}
|
|
|
|
|
|
/* t4: test_ringing_silence_call */
|
|
static void
|
|
t4_on_ringer_call_silence (CallsRinger *ringer,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
static guint test_phase = 0;
|
|
TestData *data = user_data;
|
|
|
|
switch (test_phase++) {
|
|
case 0: /* incoming call */
|
|
assert_true (calls_ringer_get_is_ringing (ringer));
|
|
calls_ui_call_data_silence_ring (data->ui_call_one);
|
|
assert_true (calls_ui_call_data_get_silenced (data->ui_call_one));
|
|
break;
|
|
case 1: /* incoming call hung up */
|
|
assert_false (calls_ringer_get_is_ringing (ringer));
|
|
g_main_loop_quit ((GMainLoop *) data->loop);
|
|
break;
|
|
default:
|
|
g_assert_not_reached (); /* did not find equivalent cmocka assertion */
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
test_ringing_silence_call (void **state)
|
|
{
|
|
TestData *data = *state;
|
|
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
|
|
g_signal_connect (data->ringer,
|
|
"notify::ringing",
|
|
G_CALLBACK (t4_on_ringer_call_silence),
|
|
data);
|
|
|
|
/* delay before completion of __wrap_lfb_event_trigger_feedback_async() */
|
|
will_return (__wrap_lfb_event_trigger_feedback_async, 10);
|
|
/* delay before completion of __wrap_lfb_event_end_feedback_async() */
|
|
will_return (__wrap_lfb_event_end_feedback_async, 10);
|
|
|
|
calls_call_set_state (CALLS_CALL (data->call_one), CALLS_CALL_STATE_INCOMING);
|
|
add_call (data->manager, data->ui_call_one);
|
|
|
|
/* main loop will quit in callback of notify::ring */
|
|
g_main_loop_run (data->loop);
|
|
|
|
remove_call (data->manager, data->ui_call_one);
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
}
|
|
|
|
|
|
/* t5: test_ringing_multiple_call */
|
|
static gboolean
|
|
t5_remove_calls (gpointer user_data)
|
|
{
|
|
static guint test_phase = 0;
|
|
TestData *data = user_data;
|
|
|
|
if (test_phase == 0) {
|
|
remove_call (data->manager, data->ui_call_one);
|
|
test_phase++;
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
assert_true (calls_ringer_get_is_ringing (data->ringer));
|
|
remove_call (data->manager, data->ui_call_two);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
|
|
static void
|
|
t5_on_ringer_multiple_calls (CallsRinger *ringer,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
static guint test_phase = 0;
|
|
TestData *data = user_data;
|
|
|
|
switch (test_phase++) {
|
|
case 0: /* add second call, and schedule call removal */
|
|
assert_true (calls_ringer_get_is_ringing (ringer));
|
|
add_call (data->manager, data->ui_call_two);
|
|
g_timeout_add (25, t5_remove_calls, data);
|
|
break;
|
|
case 1: /* both calls should be removed now */
|
|
assert_false (calls_ringer_get_is_ringing (ringer));
|
|
g_main_loop_quit ((GMainLoop *) data->loop);
|
|
break;
|
|
default:
|
|
g_assert_not_reached (); /* did not find equivalent cmocka assertion */
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
test_ringing_multiple_calls (void **state)
|
|
{
|
|
TestData *data = *state;
|
|
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
|
|
g_signal_connect (data->ringer,
|
|
"notify::ringing",
|
|
G_CALLBACK (t5_on_ringer_multiple_calls),
|
|
data);
|
|
|
|
/* delay before completion of __wrap_lfb_event_trigger_feedback_async() */
|
|
will_return (__wrap_lfb_event_trigger_feedback_async, 10);
|
|
/* delay before completion of __wrap_lfb_event_end_feedback_async() */
|
|
will_return (__wrap_lfb_event_end_feedback_async, 10);
|
|
|
|
calls_call_set_state (CALLS_CALL (data->call_one), CALLS_CALL_STATE_INCOMING);
|
|
add_call (data->manager, data->ui_call_one);
|
|
|
|
/* main loop will quit in callback of notify::ring */
|
|
g_main_loop_run (data->loop);
|
|
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
}
|
|
|
|
|
|
static void
|
|
t6_on_ringer_multiple_calls_with_restart (CallsRinger *ringer,
|
|
GParamSpec *pspec,
|
|
gpointer user_data)
|
|
{
|
|
static guint test_phase = 0;
|
|
TestData *data = user_data;
|
|
|
|
switch (test_phase++) {
|
|
case 0:
|
|
assert_true (calls_ringer_get_is_ringing (ringer));
|
|
assert_false (calls_ringer_get_ring_is_quiet (ringer));
|
|
|
|
calls_call_answer (CALLS_CALL (data->call_one));
|
|
break;
|
|
case 1:
|
|
assert_true (calls_ringer_get_is_ringing (ringer));
|
|
assert_true (calls_ringer_get_ring_is_quiet (ringer));
|
|
|
|
calls_call_hang_up (CALLS_CALL (data->call_one));
|
|
break;
|
|
case 2:
|
|
assert_true (calls_ringer_get_is_ringing (ringer));
|
|
assert_false (calls_ringer_get_ring_is_quiet (ringer));
|
|
|
|
calls_call_hang_up (CALLS_CALL (data->call_two));
|
|
break;
|
|
case 3:
|
|
assert_false (calls_ringer_get_is_ringing (ringer));
|
|
assert_false (calls_ringer_get_ring_is_quiet (ringer));
|
|
|
|
g_main_loop_quit (data->loop);
|
|
break;
|
|
default:
|
|
g_assert_not_reached (); /* did not find equivalent cmocka assertion */
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_ringing_multiple_calls_with_restart (void **state)
|
|
{
|
|
TestData *data = *state;
|
|
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
|
|
g_signal_connect (data->ringer,
|
|
"notify::ringing",
|
|
G_CALLBACK (t6_on_ringer_multiple_calls_with_restart),
|
|
data);
|
|
|
|
/* delay before completion of __wrap_lfb_event_trigger_feedback_async() */
|
|
will_return_always (__wrap_lfb_event_trigger_feedback_async, 10);
|
|
/* delay before completion of __wrap_lfb_event_end_feedback_async() */
|
|
will_return_always (__wrap_lfb_event_end_feedback_async, 10);
|
|
|
|
calls_call_set_state (CALLS_CALL (data->call_one), CALLS_CALL_STATE_INCOMING);
|
|
add_call (data->manager, data->ui_call_one);
|
|
calls_call_set_state (CALLS_CALL (data->call_two), CALLS_CALL_STATE_INCOMING);
|
|
add_call (data->manager, data->ui_call_two);
|
|
|
|
/* main loop will quit in callback of notify::ring */
|
|
g_main_loop_run (data->loop);
|
|
|
|
assert_false (calls_ringer_get_is_ringing (data->ringer));
|
|
}
|
|
|
|
int
|
|
main (int argc,
|
|
char *argv[])
|
|
{
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test_setup_teardown (test_ringing_accept_call,
|
|
setup_test_data,
|
|
tear_down_test_data),
|
|
cmocka_unit_test_setup_teardown (test_ringing_hang_up_call,
|
|
setup_test_data,
|
|
tear_down_test_data),
|
|
cmocka_unit_test_setup_teardown (test_ringing_silence_call,
|
|
setup_test_data,
|
|
tear_down_test_data),
|
|
cmocka_unit_test_setup_teardown (test_ringing_multiple_calls,
|
|
setup_test_data,
|
|
tear_down_test_data),
|
|
cmocka_unit_test_setup_teardown (test_ringing_multiple_calls_with_restart,
|
|
setup_test_data,
|
|
tear_down_test_data)
|
|
};
|
|
|
|
return cmocka_run_group_tests (tests, NULL, NULL);
|
|
}
|
|
|