1
0
Fork 0
mirror of https://gitlab.gnome.org/GNOME/calls.git synced 2024-12-14 00:17:35 +00:00
Purism-Calls/tests/test-ringer.c
Evangelos Ribeiro Tzaras 93cf894a8c ringer: Take ui-active property into account
Only start ringing once the UI is deemed active, i.e. the "pre-ring" phase has
passed.

Fixes #371
2022-02-03 12:37:05 +01:00

588 lines
16 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 (CallsSettings *settings)
{
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));
data->call_two = calls_mock_call_new ();
data->ui_call_two = calls_ui_call_data_new (CALLS_CALL (data->call_two));
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));
}
/* t3: test_ringing_hang_up_call_ringer_cancelled */
static gboolean
t3_on_ringer_timeout (gpointer user_data)
{
TestData *data = user_data;
static guint test_phase = 0;
assert_false (calls_ringer_get_is_ringing (data->ringer));
if (test_phase == 0) {
calls_call_hang_up (CALLS_CALL (data->call_one));
test_phase++;
return G_SOURCE_CONTINUE;
}
g_main_loop_quit ((GMainLoop *) data->loop);
return G_SOURCE_REMOVE;
}
/** this test should use cancellable code path by hanging up before
* event triggering completes
*/
static void
test_ringing_hang_up_call_ringer_cancelled (void **state)
{
TestData *data = *state;
assert_false (calls_ringer_get_is_ringing (data->ringer));
/* delay before completion of __wrap_lfb_event_trigger_feedback_async() */
will_return (__wrap_lfb_event_trigger_feedback_async, 50);
calls_call_set_state (CALLS_CALL (data->call_one), CALLS_CALL_STATE_INCOMING);
add_call (data->manager, data->ui_call_one);
/** this timeout needs to be longer than the delay for activating the UI/ringer,
* see DELAY_UI_MS in calls-ui-call-data.c
*/
g_timeout_add (20, G_SOURCE_FUNC (t3_on_ringer_timeout), data);
/* main loop will quit in t3_on_ringer_timeout() */
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_hang_up_call_ringer_cancelled,
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);
}