// Copyright (c) 2014 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>
extern "C" {
// To test static functions.
#include "cras_bt_io.c"
}
static struct cras_bt_device *fake_device =
reinterpret_cast<struct cras_bt_device*>(0x123);
static unsigned int cras_iodev_add_node_called;
static unsigned int cras_iodev_rm_node_called;
static unsigned int cras_iodev_free_format_called;
static unsigned int cras_iodev_set_active_node_called;
static unsigned int cras_iodev_list_add_output_called;
static unsigned int cras_iodev_list_rm_output_called;
static unsigned int cras_iodev_list_add_input_called;
static unsigned int cras_iodev_list_rm_input_called;
static unsigned int cras_bt_device_set_active_profile_called;
static unsigned int cras_bt_device_set_active_profile_val;
static int cras_bt_device_get_active_profile_ret;
static int cras_bt_device_switch_profile_enable_dev_called;
static int cras_bt_device_switch_profile_called;
static int cras_bt_device_can_switch_to_a2dp_ret;
static int cras_bt_device_has_a2dp_ret;
static int is_utf8_string_ret_value;
void ResetStubData() {
cras_iodev_add_node_called = 0;
cras_iodev_rm_node_called = 0;
cras_iodev_free_format_called = 0;
cras_iodev_set_active_node_called = 0;
cras_iodev_list_add_output_called = 0;
cras_iodev_list_rm_output_called = 0;
cras_iodev_list_add_input_called = 0;
cras_iodev_list_rm_input_called = 0;
cras_bt_device_set_active_profile_called = 0;
cras_bt_device_set_active_profile_val = 0;
cras_bt_device_get_active_profile_ret = 0;
cras_bt_device_switch_profile_enable_dev_called= 0;
cras_bt_device_switch_profile_called = 0;
cras_bt_device_can_switch_to_a2dp_ret = 0;
cras_bt_device_has_a2dp_ret = 0;
is_utf8_string_ret_value = 1;
}
namespace {
class BtIoBasicSuite : public testing::Test {
protected:
virtual void SetUp() {
ResetStubData();
SetUpIodev(&iodev_, CRAS_STREAM_OUTPUT);
SetUpIodev(&iodev2_, CRAS_STREAM_OUTPUT);
update_supported_formats_called_ = 0;
frames_queued_called_ = 0;
delay_frames_called_ = 0;
get_buffer_called_ = 0;
put_buffer_called_ = 0;
open_dev_called_ = 0;
close_dev_called_ = 0;
}
virtual void TearDown() {
}
static void SetUpIodev(struct cras_iodev *d,
enum CRAS_STREAM_DIRECTION dir) {
d->direction = dir;
d->update_supported_formats = update_supported_formats;
d->frames_queued = frames_queued;
d->delay_frames = delay_frames;
d->get_buffer = get_buffer;
d->put_buffer = put_buffer;
d->open_dev = open_dev;
d->close_dev = close_dev;
}
// Stub functions for the iodev structure.
static int update_supported_formats(struct cras_iodev *iodev) {
iodev->supported_rates = (size_t *)calloc(
2, sizeof(*iodev->supported_rates));
iodev->supported_rates[0] = 48000;
iodev->supported_rates[1] = 0;
iodev->supported_channel_counts = (size_t *)calloc(
2, sizeof(*iodev->supported_channel_counts));
iodev->supported_channel_counts[0] = 2;
iodev->supported_channel_counts[1] = 0;
iodev->supported_formats = (snd_pcm_format_t *)calloc(
2, sizeof(*iodev->supported_formats));
iodev->supported_formats[0] = SND_PCM_FORMAT_S16_LE;
iodev->supported_formats[1] = (snd_pcm_format_t)0;
update_supported_formats_called_++;
return 0;
}
static int frames_queued(const cras_iodev* iodev,
struct timespec *tstamp) {
frames_queued_called_++;
return 0;
}
static int delay_frames(const cras_iodev* iodev) {
delay_frames_called_++;
return 0;
}
static int get_buffer(cras_iodev* iodev,
struct cras_audio_area** area,
unsigned int* num) {
get_buffer_called_++;
return 0;
}
static int put_buffer(cras_iodev* iodev,
unsigned int num) {
put_buffer_called_++;
return 0;
}
static int open_dev(cras_iodev* iodev) {
open_dev_called_++;
return 0;
}
static int close_dev(cras_iodev* iodev) {
close_dev_called_++;
return 0;
}
static struct cras_iodev *bt_iodev;
static struct cras_iodev iodev_;
static struct cras_iodev iodev2_;
static unsigned int update_supported_formats_called_;
static unsigned int frames_queued_called_;
static unsigned int delay_frames_called_;
static unsigned int get_buffer_called_;
static unsigned int put_buffer_called_;
static unsigned int open_dev_called_;
static unsigned int close_dev_called_;
};
struct cras_iodev *BtIoBasicSuite::bt_iodev;
struct cras_iodev BtIoBasicSuite::iodev_;
struct cras_iodev BtIoBasicSuite::iodev2_;
unsigned int BtIoBasicSuite::update_supported_formats_called_;
unsigned int BtIoBasicSuite::frames_queued_called_;
unsigned int BtIoBasicSuite::delay_frames_called_;
unsigned int BtIoBasicSuite::get_buffer_called_;
unsigned int BtIoBasicSuite::put_buffer_called_;
unsigned int BtIoBasicSuite::open_dev_called_;
unsigned int BtIoBasicSuite::close_dev_called_;
TEST_F(BtIoBasicSuite, CreateBtIo) {
struct cras_audio_area *fake_area;
struct cras_audio_format fake_fmt;
struct timespec tstamp;
unsigned fr;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
EXPECT_NE((void *)NULL, bt_iodev);
EXPECT_EQ(&iodev_, active_profile_dev(bt_iodev));
EXPECT_EQ(1, cras_iodev_list_add_output_called);
bt_iodev->format = &fake_fmt;
bt_iodev->update_supported_formats(bt_iodev);
EXPECT_EQ(1, update_supported_formats_called_);
bt_iodev->open_dev(bt_iodev);
EXPECT_EQ(1, open_dev_called_);
bt_iodev->frames_queued(bt_iodev, &tstamp);
EXPECT_EQ(1, frames_queued_called_);
bt_iodev->get_buffer(bt_iodev, &fake_area, &fr);
EXPECT_EQ(1, get_buffer_called_);
bt_iodev->put_buffer(bt_iodev, fr);
EXPECT_EQ(1, put_buffer_called_);
bt_iodev->close_dev(bt_iodev);
EXPECT_EQ(1, close_dev_called_);
EXPECT_EQ(1, cras_iodev_free_format_called);
cras_bt_io_destroy(bt_iodev);
EXPECT_EQ(1, cras_iodev_list_rm_output_called);
}
TEST_F(BtIoBasicSuite, SwitchProfileOnUpdateFormatForInputDev) {
ResetStubData();
iodev_.direction = CRAS_STREAM_INPUT;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
cras_bt_device_get_active_profile_ret = CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE;
bt_iodev->update_supported_formats(bt_iodev);
EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY |
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY,
cras_bt_device_set_active_profile_val);
EXPECT_EQ(1, cras_bt_device_switch_profile_enable_dev_called);
}
TEST_F(BtIoBasicSuite, NoSwitchProfileOnUpdateFormatForInputDevAlreadyOnHfp) {
ResetStubData();
iodev_.direction = CRAS_STREAM_INPUT;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
/* No need to switch profile if already on HFP. */
cras_bt_device_get_active_profile_ret =
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY;
bt_iodev->update_supported_formats(bt_iodev);
EXPECT_EQ(0, cras_bt_device_switch_profile_enable_dev_called);
}
TEST_F(BtIoBasicSuite, SwitchProfileOnCloseInputDev) {
ResetStubData();
iodev_.direction = CRAS_STREAM_INPUT;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
cras_bt_device_get_active_profile_ret =
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY |
CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY;
cras_bt_device_has_a2dp_ret = 1;
bt_iodev->close_dev(bt_iodev);
EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE,
cras_bt_device_set_active_profile_val);
EXPECT_EQ(1, cras_bt_device_switch_profile_called);
}
TEST_F(BtIoBasicSuite, NoSwitchProfileOnCloseInputDevNoSupportA2dp) {
ResetStubData();
iodev_.direction = CRAS_STREAM_INPUT;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
cras_bt_device_get_active_profile_ret =
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY |
CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY;
cras_bt_device_has_a2dp_ret = 0;
bt_iodev->close_dev(bt_iodev);
EXPECT_EQ(0, cras_bt_device_switch_profile_called);
}
TEST_F(BtIoBasicSuite, SwitchProfileOnAppendA2dpDev) {
ResetStubData();
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
cras_bt_device_can_switch_to_a2dp_ret = 1;
cras_bt_io_append(bt_iodev, &iodev2_,
CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE,
cras_bt_device_set_active_profile_val);
EXPECT_EQ(0, cras_bt_device_switch_profile_enable_dev_called);
EXPECT_EQ(1, cras_bt_device_switch_profile_called);
}
TEST_F(BtIoBasicSuite, NoSwitchProfileOnAppendHfpDev) {
ResetStubData();
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
cras_bt_device_can_switch_to_a2dp_ret = 1;
cras_bt_io_append(bt_iodev, &iodev2_,
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
EXPECT_EQ(0, cras_bt_device_switch_profile_enable_dev_called);
}
TEST_F(BtIoBasicSuite, CreateSetDeviceActiveProfileToA2DP) {
ResetStubData();
cras_bt_device_get_active_profile_ret =
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY;
cras_bt_device_can_switch_to_a2dp_ret = 1;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
EXPECT_EQ(1, cras_bt_device_set_active_profile_called);
EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE,
cras_bt_device_set_active_profile_val);
cras_bt_io_destroy(bt_iodev);
}
TEST_F(BtIoBasicSuite, CreateNoSetDeviceActiveProfileToA2DP) {
ResetStubData();
cras_bt_device_get_active_profile_ret =
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY;
cras_bt_device_can_switch_to_a2dp_ret = 0;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
EXPECT_EQ(0, cras_bt_device_set_active_profile_called);
cras_bt_io_destroy(bt_iodev);
}
TEST_F(BtIoBasicSuite, CreateSetDeviceActiveProfileToHFP) {
ResetStubData();
cras_bt_device_get_active_profile_ret = 0;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
EXPECT_EQ(
CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY |
CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY,
cras_bt_device_set_active_profile_val);
cras_bt_io_destroy(bt_iodev);
}
TEST_F(BtIoBasicSuite, CreateDeviceWithInvalidUTF8Name) {
ResetStubData();
strcpy(iodev_.info.name, "Something BT");
iodev_.info.name[0] = 0xfe;
is_utf8_string_ret_value = 0;
bt_iodev = cras_bt_io_create(fake_device, &iodev_,
CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE);
ASSERT_STREQ("BLUETOOTH", bt_iodev->active_node->name);
}
} // namespace
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
extern "C" {
// Cras iodev
void cras_iodev_add_node(struct cras_iodev *iodev, struct cras_ionode *node)
{
cras_iodev_add_node_called++;
iodev->nodes = node;
}
void cras_iodev_rm_node(struct cras_iodev *iodev, struct cras_ionode *node)
{
cras_iodev_rm_node_called++;
iodev->nodes = NULL;
}
void cras_iodev_free_format(struct cras_iodev *iodev)
{
cras_iodev_free_format_called++;
}
void cras_iodev_set_active_node(struct cras_iodev *iodev,
struct cras_ionode *node)
{
cras_iodev_set_active_node_called++;
iodev->active_node = node;
}
int cras_iodev_set_node_attr(struct cras_ionode *ionode,
enum ionode_attr attr, int value)
{
return 0;
}
// From iodev list.
int cras_iodev_list_add_output(struct cras_iodev *output)
{
cras_iodev_list_add_output_called++;
return 0;
}
int cras_iodev_list_rm_output(struct cras_iodev *dev)
{
cras_iodev_list_rm_output_called++;
return 0;
}
int cras_iodev_list_add_input(struct cras_iodev *output)
{
cras_iodev_list_add_input_called++;
return 0;
}
int cras_iodev_list_rm_input(struct cras_iodev *dev)
{
cras_iodev_list_rm_input_called++;
return 0;
}
// From bt device
int cras_bt_device_get_active_profile(const struct cras_bt_device *device)
{
return cras_bt_device_get_active_profile_ret;
}
void cras_bt_device_set_active_profile(struct cras_bt_device *device,
unsigned int profile)
{
cras_bt_device_set_active_profile_called++;
cras_bt_device_set_active_profile_val = profile;
}
int cras_bt_device_has_a2dp(struct cras_bt_device *device)
{
return cras_bt_device_has_a2dp_ret;
}
int cras_bt_device_can_switch_to_a2dp(struct cras_bt_device *device)
{
return cras_bt_device_can_switch_to_a2dp_ret;
}
int cras_bt_device_switch_profile(struct cras_bt_device *device,
struct cras_iodev *bt_iodev)
{
cras_bt_device_switch_profile_called++;
return 0;
}
int cras_bt_device_switch_profile_enable_dev(struct cras_bt_device *device,
struct cras_iodev *bt_iodev)
{
cras_bt_device_switch_profile_enable_dev_called++;
return 0;
}
const char *cras_bt_device_object_path(const struct cras_bt_device *device)
{
return "/fake/object/path";
}
int is_utf8_string(const char* string)
{
return is_utf8_string_ret_value;
}
int cras_iodev_default_no_stream_playback(struct cras_iodev *odev, int enable)
{
return 0;
}
} // extern "C"