[calls] tests: Add ringer tests



commit 7dadb3c50ffae88592003901c6d5b7d8a030a7d7
Author: Evangelos Ribeiro Tzaras <devrtz fortysixandtwo eu>
Date:   Fri Oct 22 07:23:29 2021 +0200

    tests: Add ringer tests
    
    We mock libfeedback and CallsCall to test the ringer for the following
    scenarios:
    - Call state changes
    - User requested silencing of ringer
    - Multiple calls

 tests/meson.build              |  31 +++
 tests/mock-call.c              | 192 ++++++++++++++++
 tests/mock-call.h              |  30 +++
 tests/mock-contacts-provider.h |   5 +
 tests/mock-libfeedback.h       |  28 +++
 tests/mock/mock-libfeedback.c  |  83 +++++++
 tests/test-ringer.c            | 509 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 878 insertions(+)
---
diff --git a/tests/meson.build b/tests/meson.build
index ecec6b92..67f63d3a 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -115,4 +115,35 @@ t = executable('util', test_sources,
                )
 test('util', t, env: test_env)
 
+mock_link_args = [ test_link_args,
+                   '-Wl,--wrap=lfb_init',
+                   '-Wl,--wrap=lfb_uninit',
+                   '-Wl,--wrap=lfb_event_set_feedback_profile',
+                   '-Wl,--wrap=lfb_event_trigger_feedback_async',
+                   '-Wl,--wrap=lfb_event_trigger_feedback_finish',
+                   '-Wl,--wrap=lfb_event_end_feedback_async',
+                   '-Wl,--wrap=lfb_event_end_feedback_finish',
+                   '-Wl,--wrap=calls_contacts_provider_new',
+                 ]
+cmocka = dependency ('cmocka', required: false)
+
+if cmocka.found ()
+    test_sources = [
+                    'mock-call.c', 'mock-call.h', 'mock-libfeedback.h',
+                    'test-ringer.c'
+                   ]
+
+    t = executable('ringer', test_sources,
+                   c_args : test_cflags,
+                   link_args: mock_link_args,
+                   pie: true,
+                   link_with : [calls_vala, libcalls],
+                   dependencies: [calls_deps, cmocka],
+                   include_directories : [
+                       calls_includes,
+                     ]
+                   )
+    test('ringer', t, env: test_env)
+endif
+
 endif
diff --git a/tests/mock-call.c b/tests/mock-call.c
new file mode 100644
index 00000000..62c9d1e1
--- /dev/null
+++ b/tests/mock-call.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Author: Evangelos Ribeiro Tzaras <devrtz fortysixandtwo eu>
+ *
+ */
+
+#include "mock-call.h"
+
+#include <glib/gi18n.h>
+
+enum {
+  PROP_0,
+  PROP_NAME,
+  PROP_ID,
+  PROP_STATE,
+  PROP_LAST_PROP,
+};
+static GParamSpec *props[PROP_LAST_PROP];
+
+struct _CallsMockCall
+{
+  CallsCall       parent_instance;
+
+  char           *id;
+  char           *display_name;
+  CallsCallState  state;
+};
+
+G_DEFINE_TYPE (CallsMockCall, calls_mock_call, CALLS_TYPE_CALL)
+
+
+static void
+calls_mock_call_answer (CallsCall *call)
+{
+  g_assert (CALLS_IS_MOCK_CALL (call));
+  g_assert_cmpint (calls_call_get_state (call), ==, CALLS_CALL_STATE_INCOMING);
+
+  calls_mock_call_set_state (CALLS_MOCK_CALL (call), CALLS_CALL_STATE_ACTIVE);
+}
+
+
+static void
+calls_mock_call_hang_up (CallsCall *call)
+{
+  g_assert (CALLS_IS_MOCK_CALL (call));
+  g_assert_cmpint (calls_call_get_state (call), !=, CALLS_CALL_STATE_DISCONNECTED);
+
+  calls_mock_call_set_state (CALLS_MOCK_CALL (call), CALLS_CALL_STATE_DISCONNECTED);
+}
+
+
+static CallsCallState
+calls_mock_call_get_state (CallsCall *call)
+{
+  g_assert (CALLS_IS_MOCK_CALL (call));
+
+  return CALLS_MOCK_CALL (call)->state;
+}
+
+static void
+calls_mock_call_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  CallsMockCall *self = CALLS_MOCK_CALL (object);
+
+  switch (prop_id) {
+  case PROP_ID:
+    g_value_set_string (value, self->id);
+    break;
+  case PROP_NAME:
+    g_value_set_string (value, self->display_name);
+    break;
+  case PROP_STATE:
+    g_value_set_enum (value, self->state);
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+
+static void
+calls_mock_call_finalize (GObject *object)
+{
+  CallsMockCall *self = CALLS_MOCK_CALL (object);
+
+  g_free (self->id);
+  g_free (self->display_name);
+
+  G_OBJECT_CLASS (calls_mock_call_parent_class)->finalize (object);
+}
+
+
+static void
+calls_mock_call_class_init (CallsMockCallClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  CallsCallClass *call_class = CALLS_CALL_CLASS (klass);
+
+  call_class->answer = calls_mock_call_answer;
+  call_class->hang_up = calls_mock_call_hang_up;
+  call_class->get_state = calls_mock_call_get_state;
+
+  object_class->get_property = calls_mock_call_get_property;
+  object_class->finalize = calls_mock_call_finalize;
+
+  g_object_class_override_property (object_class,
+                                    PROP_ID,
+                                    "id");
+  props[PROP_ID] = g_object_class_find_property (object_class, "id");
+
+  g_object_class_override_property (object_class,
+                                    PROP_NAME,
+                                    "name");
+  props[PROP_NAME] = g_object_class_find_property (object_class, "name");
+
+  g_object_class_override_property (object_class,
+                                    PROP_STATE,
+                                    "state");
+  props[PROP_STATE] = g_object_class_find_property (object_class, "state");
+
+}
+
+
+static void
+calls_mock_call_init (CallsMockCall *self)
+{
+  self->display_name = g_strdup ("John Doe");
+  self->id = g_strdup ("0800 1234");
+  self->state = CALLS_CALL_STATE_INCOMING;
+}
+
+
+CallsMockCall *
+calls_mock_call_new (void)
+{
+   return g_object_new (CALLS_TYPE_MOCK_CALL, NULL);
+}
+
+
+void
+calls_mock_call_set_id (CallsMockCall *self,
+                        const char   *id)
+{
+  g_return_if_fail (CALLS_IS_MOCK_CALL (self));
+
+  g_free (self->id);
+  self->id = g_strdup (id);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ID]);
+}
+
+
+void
+calls_mock_call_set_name (CallsMockCall *self,
+                          const char    *name)
+{
+  g_return_if_fail (CALLS_IS_MOCK_CALL (self));
+
+  g_free (self->display_name);
+  self->display_name = g_strdup (name);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NAME]);
+}
+
+
+void
+calls_mock_call_set_state (CallsMockCall *self,
+                           CallsCallState  state)
+{
+  CallsCallState old_state;
+
+  g_return_if_fail (CALLS_IS_MOCK_CALL (self));
+
+  old_state = self->state;
+  if (old_state == state)
+    return;
+
+  self->state = state;
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]);
+  g_signal_emit_by_name (CALLS_CALL (self),
+                         "state-changed",
+                         state,
+                         old_state);
+}
+
diff --git a/tests/mock-call.h b/tests/mock-call.h
new file mode 100644
index 00000000..45935685
--- /dev/null
+++ b/tests/mock-call.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Author: Evangelos Ribeiro Tzaras <devrtz fortysixandtwo eu>
+ *
+ */
+
+#pragma once
+
+#include "calls-call.h"
+
+G_BEGIN_DECLS
+
+#define CALLS_TYPE_MOCK_CALL (calls_mock_call_get_type())
+
+G_DECLARE_FINAL_TYPE (CallsMockCall, calls_mock_call, CALLS, MOCK_CALL, CallsCall)
+
+CallsMockCall    *calls_mock_call_new               (void);
+void              calls_mock_call_set_id            (CallsMockCall *self,
+                                                     const char    *id);
+void              calls_mock_call_set_name          (CallsMockCall *self,
+                                                     const char    *name);
+void              calls_mock_call_set_state         (CallsMockCall *self,
+                                                     CallsCallState state);
+void              calls_mock_call_set_inbound       (CallsMockCall *self,
+                                                     gboolean       inbound);
+
+G_END_DECLS
diff --git a/tests/mock-contacts-provider.h b/tests/mock-contacts-provider.h
new file mode 100644
index 00000000..dc85931c
--- /dev/null
+++ b/tests/mock-contacts-provider.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "calls-contacts-provider.h"
+
+CallsContactsProvider *__wrap_calls_contacts_provider_new (CallsSettings *seetings);
diff --git a/tests/mock-libfeedback.h b/tests/mock-libfeedback.h
new file mode 100644
index 00000000..66bdcabd
--- /dev/null
+++ b/tests/mock-libfeedback.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#define LIBFEEDBACK_USE_UNSTABLE_API
+
+#include <libfeedback.h>
+#include <glib.h>
+
+
+gboolean        __wrap_lfb_init                            (const char *app_id,
+                                                            GError    **error);
+void            __wrap_lfb_uninit                          (void);
+void            __wrap_lfb_event_set_feedback_profile      (LfbEvent   *self,
+                                                            const char *profile);
+
+void            __wrap_lfb_event_trigger_feedback_async    (LfbEvent           *self,
+                                                            GCancellable       *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer            user_data);
+gboolean        __wrap_lfb_event_trigger_feedback_finish   (LfbEvent     *self,
+                                                            GAsyncResult *res,
+                                                            GError      **error);
+void            __wrap_lfb_event_end_feedback_async        (LfbEvent           *self,
+                                                            GCancellable       *cancellable,
+                                                            GAsyncReadyCallback callback,
+                                                            gpointer            user_data);
+gboolean        __wrap_lfb_event_end_feedback_finish       (LfbEvent     *self,
+                                                            GAsyncResult *res,
+                                                            GError      **error);
diff --git a/tests/mock/mock-libfeedback.c b/tests/mock/mock-libfeedback.c
new file mode 100644
index 00000000..073225b4
--- /dev/null
+++ b/tests/mock/mock-libfeedback.c
@@ -0,0 +1,83 @@
+#include "mock-libfeedback.h"
+
+#include <setjmp.h>
+#include <cmocka.h>
+
+
+static gboolean
+on_mock_timeout (gpointer user_data)
+{
+  GTask *task = user_data;
+
+  g_task_return_boolean (task, TRUE);
+  return G_SOURCE_REMOVE;
+}
+
+/* could probably also live without mocking/stubbing lfb_{un,}init()
+ * and run under GTestDBus since we're actually only interested
+ * in the feedback trigger and end functions
+ */
+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);
+  gboolean mock_will_be_cancelled = mock_type (gboolean);
+
+  if (!mock_will_be_cancelled)
+    g_timeout_add (mock_time_ms, on_mock_timeout, trigger_task);
+}
+
+
+gboolean
+__wrap_lfb_event_trigger_feedback_finish (LfbEvent     *self,
+                                          GAsyncResult *res,
+                                          GError      **error)
+{
+  return TRUE;
+}
+
+
+void
+__wrap_lfb_event_end_feedback_async (LfbEvent           *self,
+                                     GCancellable       *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer            user_data)
+{
+  ;
+}
+
+
+gboolean
+__wrap_lfb_event_end_feedback_finish (LfbEvent     *self,
+                                      GAsyncResult *res,
+                                      GError      **error)
+{
+  return TRUE;
+}
diff --git a/tests/test-ringer.c b/tests/test-ringer.c
new file mode 100644
index 00000000..893591e9
--- /dev/null
+++ b/tests/test-ringer.c
@@ -0,0 +1,509 @@
+/*
+ * 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 "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,
+          CallsMockCall *call)
+{
+  g_assert (CALLS_IS_MANAGER (manager));
+  g_assert (CALLS_IS_MOCK_CALL (call));
+
+  g_signal_emit_by_name (manager, "call-add", CALLS_CALL (call), NULL);
+}
+
+
+static void
+remove_call (CallsManager  *manager,
+             CallsMockCall *call)
+{
+  g_assert (CALLS_IS_MANAGER (manager));
+  g_assert (CALLS_IS_MOCK_CALL (call));
+
+  g_signal_emit_by_name (manager, "call-remove", CALLS_CALL (call), NULL);
+}
+
+/* TestData setup and tear down */
+typedef struct {
+  CallsManager  *manager;
+  CallsRinger   *ringer;
+  CallsMockCall *call_one;
+  CallsMockCall *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->call_two = calls_mock_call_new ();
+  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->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_mock_call_set_state (data->call_one, CALLS_CALL_STATE_INCOMING);
+  add_call (data->manager, data->call_one);
+
+  /* main loop will quit in callback of notify::ring */
+  g_main_loop_run (data->loop);
+
+  remove_call (data->manager, data->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_mock_call_set_state (data->call_one, CALLS_CALL_STATE_INCOMING);
+  add_call (data->manager, data->call_one);
+
+  /* main loop will quit in callback of notify::ring */
+  g_main_loop_run (data->loop);
+
+  remove_call (data->manager, data->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_mock_call_set_state (data->call_one, CALLS_CALL_STATE_INCOMING);
+  add_call (data->manager, data->call_one);
+
+  g_timeout_add (10, 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->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_call_silence_ring (CALLS_CALL (data->call_one));
+    assert_true (calls_call_get_silenced (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_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_mock_call_set_state (data->call_one, CALLS_CALL_STATE_INCOMING);
+  add_call (data->manager, data->call_one);
+
+  /* main loop will quit in callback of notify::ring */
+  g_main_loop_run (data->loop);
+
+  remove_call (data->manager, data->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->call_one);
+    test_phase++;
+    return G_SOURCE_CONTINUE;
+  }
+
+  assert_true (calls_ringer_get_is_ringing (data->ringer));
+  remove_call (data->manager, data->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->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_mock_call_set_state (data->call_one, CALLS_CALL_STATE_INCOMING);
+  add_call (data->manager, data->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));
+}
+
+
+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),
+  };
+
+  return cmocka_run_group_tests (tests, NULL, NULL);
+}
+


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]