/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <gtest/gtest.h>
#include <stdint.h>
#include <sys/socket.h>
#include <stdio.h>
extern "C" {
#include "cras_hfp_slc.h"
#include "cras_telephony.h"
}
static struct hfp_slc_handle *handle;
static struct cras_telephony_handle fake_telephony;
static int cras_bt_device_update_hardware_volume_called;
static int slc_initialized_cb_called;
static int slc_disconnected_cb_called;
static int cras_system_add_select_fd_called;
static void(*slc_cb)(void *data);
static void *slc_cb_data;
static int fake_errno;
static struct cras_bt_device *device =
reinterpret_cast<struct cras_bt_device *>(2);
int slc_initialized_cb(struct hfp_slc_handle *handle);
int slc_disconnected_cb(struct hfp_slc_handle *handle);
void ResetStubData() {
slc_initialized_cb_called = 0;
cras_system_add_select_fd_called = 0;
cras_bt_device_update_hardware_volume_called = 0;
slc_cb = NULL;
slc_cb_data = NULL;
}
namespace {
TEST(HfpSlc, CreateSlcHandle) {
ResetStubData();
handle = hfp_slc_create(0, 0, device, slc_initialized_cb,
slc_disconnected_cb);
ASSERT_EQ(1, cras_system_add_select_fd_called);
ASSERT_EQ(handle, slc_cb_data);
hfp_slc_destroy(handle);
}
TEST(HfpSlc, InitializeSlc) {
int err;
int sock[2];
char buf[256];
char *chp;
ResetStubData();
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
handle = hfp_slc_create(sock[0], 0, device, slc_initialized_cb,
slc_disconnected_cb);
err = write(sock[1], "AT+CIND=?\r", 10);
ASSERT_EQ(10, err);
slc_cb(slc_cb_data);
err = read(sock[1], buf, 256);
/* Assert "\r\n+CIND: ... \r\n" response is received */
chp = strstr(buf, "\r\n");
ASSERT_NE((void *)NULL, (void *)chp);
ASSERT_EQ(0, strncmp("\r\n+CIND:", chp, 8));
chp+=2;
chp = strstr(chp, "\r\n");
ASSERT_NE((void *)NULL, (void *)chp);
/* Assert "\r\nOK\r\n" response is received */
chp+=2;
chp = strstr(chp, "\r\n");
ASSERT_NE((void *)NULL, (void *)chp);
ASSERT_EQ(0, strncmp("\r\nOK", chp, 4));
err = write(sock[1], "AT+CMER=3,0,0,1\r", 16);
ASSERT_EQ(16, err);
slc_cb(slc_cb_data);
ASSERT_EQ(1, slc_initialized_cb_called);
/* Assert "\r\nOK\r\n" response is received */
err = read(sock[1], buf, 256);
chp = strstr(buf, "\r\n");
ASSERT_NE((void *)NULL, (void *)chp);
ASSERT_EQ(0, strncmp("\r\nOK", chp, 4));
err = write(sock[1], "AT+VGS=13\r", 10);
ASSERT_EQ(err, 10);
slc_cb(slc_cb_data);
err = read(sock[1], buf, 256);
chp = strstr(buf, "\r\n");
ASSERT_NE((void *)NULL, (void *)chp);
ASSERT_EQ(0, strncmp("\r\nOK", chp, 4));
ASSERT_EQ(1, cras_bt_device_update_hardware_volume_called);
hfp_slc_destroy(handle);
}
TEST(HfpSlc, DisconnectSlc) {
int sock[2];
ResetStubData();
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
handle = hfp_slc_create(sock[0], 0, device, slc_initialized_cb,
slc_disconnected_cb);
/* Close socket right away to make read() get negative err code, and
* fake the errno to ECONNRESET. */
close(sock[0]);
close(sock[1]);
fake_errno = 104;
slc_cb(slc_cb_data);
ASSERT_EQ(1, slc_disconnected_cb_called);
hfp_slc_destroy(handle);
}
} // namespace
int slc_initialized_cb(struct hfp_slc_handle *handle) {
slc_initialized_cb_called++;
return 0;
}
int slc_disconnected_cb(struct hfp_slc_handle *handle) {
slc_disconnected_cb_called++;
return 0;
}
extern "C" {
int cras_system_add_select_fd(int fd,
void (*callback)(void *data),
void *callback_data) {
cras_system_add_select_fd_called++;
slc_cb = callback;
slc_cb_data = callback_data;
return 0;
}
void cras_system_rm_select_fd(int fd) {
}
void cras_bt_device_update_hardware_volume(struct cras_bt_device *device,
int volume)
{
cras_bt_device_update_hardware_volume_called++;
}
/* To return fake errno */
int *__errno_location() {
return &fake_errno;
}
}
// For telephony
struct cras_telephony_handle* cras_telephony_get()
{
return &fake_telephony;
}
void cras_telephony_store_dial_number(int len, const char* num)
{
}
int cras_telephony_event_answer_call()
{
return 0;
}
int cras_telephony_event_terminate_call()
{
return 0;
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}