// 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" { #include "cras_bt_io.h" #include "cras_bt_device.h" #include "cras_iodev.h" #include "cras_main_message.h" #define FAKE_OBJ_PATH "/obj/path" } static struct cras_iodev *cras_bt_io_create_profile_ret; static struct cras_iodev *cras_bt_io_append_btio_val; static struct cras_ionode* cras_bt_io_get_profile_ret; static unsigned int cras_bt_io_create_called; static unsigned int cras_bt_io_append_called; static unsigned int cras_bt_io_remove_called; static unsigned int cras_bt_io_destroy_called; static enum cras_bt_device_profile cras_bt_io_create_profile_val; static enum cras_bt_device_profile cras_bt_io_append_profile_val; static unsigned int cras_bt_io_try_remove_ret; static cras_main_message *cras_main_message_send_msg; static cras_message_callback cras_main_message_add_handler_callback; static void *cras_main_message_add_handler_callback_data; void ResetStubData() { cras_bt_io_get_profile_ret = NULL; cras_bt_io_create_called = 0; cras_bt_io_append_called = 0; cras_bt_io_remove_called = 0; cras_bt_io_destroy_called = 0; cras_bt_io_try_remove_ret = 0; cras_main_message_send_msg = NULL; } namespace { class BtDeviceTestSuite : public testing::Test { protected: virtual void SetUp() { ResetStubData(); bt_iodev1.direction = CRAS_STREAM_OUTPUT; bt_iodev1.update_active_node = update_active_node; bt_iodev2.direction = CRAS_STREAM_INPUT; bt_iodev2.update_active_node = update_active_node; d1_.direction = CRAS_STREAM_OUTPUT; d1_.update_active_node = update_active_node; d2_.direction = CRAS_STREAM_OUTPUT; d2_.update_active_node = update_active_node; d3_.direction = CRAS_STREAM_INPUT; d3_.update_active_node = update_active_node; } virtual void TearDown() { if(cras_main_message_send_msg) free(cras_main_message_send_msg); } static void update_active_node(struct cras_iodev *iodev, unsigned node_idx, unsigned dev_enabled) { } struct cras_iodev bt_iodev1; struct cras_iodev bt_iodev2; struct cras_iodev d3_; struct cras_iodev d2_; struct cras_iodev d1_; }; TEST(BtDeviceSuite, CreateBtDevice) { struct cras_bt_device *device; device = cras_bt_device_create(NULL, FAKE_OBJ_PATH); EXPECT_NE((void *)NULL, device); device = cras_bt_device_get(FAKE_OBJ_PATH); EXPECT_NE((void *)NULL, device); cras_bt_device_destroy(device); device = cras_bt_device_get(FAKE_OBJ_PATH); EXPECT_EQ((void *)NULL, device); } TEST_F(BtDeviceTestSuite, AppendRmIodev) { struct cras_bt_device *device; device = cras_bt_device_create(NULL, FAKE_OBJ_PATH); bt_iodev1.nodes = reinterpret_cast<struct cras_ionode*>(0x123); cras_bt_io_create_profile_ret = &bt_iodev1; cras_bt_device_append_iodev(device, &d1_, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); EXPECT_EQ(1, cras_bt_io_create_called); EXPECT_EQ(0, cras_bt_io_append_called); EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE, cras_bt_io_create_profile_val); cras_bt_device_set_active_profile(device, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); cras_bt_device_append_iodev(device, &d2_, CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); EXPECT_EQ(1, cras_bt_io_create_called); EXPECT_EQ(1, cras_bt_io_append_called); EXPECT_EQ(CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY, cras_bt_io_append_profile_val); EXPECT_EQ(&bt_iodev1, cras_bt_io_append_btio_val); /* Test HFP disconnected and switch to A2DP. */ cras_bt_io_get_profile_ret = bt_iodev1.nodes; cras_bt_io_try_remove_ret = CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE; cras_bt_device_set_active_profile( device, CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); cras_bt_device_rm_iodev(device, &d2_); EXPECT_EQ(1, cras_bt_io_remove_called); /* Test A2DP disconnection will cause bt_io destroy. */ cras_bt_io_try_remove_ret = 0; cras_bt_device_rm_iodev(device, &d1_); EXPECT_EQ(1, cras_bt_io_remove_called); EXPECT_EQ(1, cras_bt_io_destroy_called); EXPECT_EQ(0, cras_bt_device_get_active_profile(device)); cras_bt_device_destroy(device); } TEST_F(BtDeviceTestSuite, SwitchProfile) { struct cras_bt_device *device; ResetStubData(); device = cras_bt_device_create(NULL, FAKE_OBJ_PATH); cras_bt_io_create_profile_ret = &bt_iodev1; cras_bt_device_append_iodev(device, &d1_, CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE); cras_bt_io_create_profile_ret = &bt_iodev2; cras_bt_device_append_iodev(device, &d3_, CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY); cras_bt_device_start_monitor(); cras_bt_device_switch_profile_enable_dev(device, &bt_iodev1); /* Two bt iodevs were all active. */ cras_main_message_add_handler_callback( cras_main_message_send_msg, cras_main_message_add_handler_callback_data); /* One bt iodev was active, the other was not. */ cras_bt_device_switch_profile_enable_dev(device, &bt_iodev2); cras_main_message_add_handler_callback( cras_main_message_send_msg, cras_main_message_add_handler_callback_data); /* Output bt iodev wasn't active, close the active input iodev. */ cras_bt_device_switch_profile(device, &bt_iodev2); cras_main_message_add_handler_callback( cras_main_message_send_msg, cras_main_message_add_handler_callback_data); cras_bt_device_destroy(device); } /* Stubs */ extern "C" { /* From bt_io */ struct cras_iodev *cras_bt_io_create( struct cras_bt_device *device, struct cras_iodev *dev, enum cras_bt_device_profile profile) { cras_bt_io_create_called++; cras_bt_io_create_profile_val = profile; return cras_bt_io_create_profile_ret; } void cras_bt_io_destroy(struct cras_iodev *bt_iodev) { cras_bt_io_destroy_called++; } struct cras_ionode* cras_bt_io_get_profile( struct cras_iodev *bt_iodev, enum cras_bt_device_profile profile) { return cras_bt_io_get_profile_ret; } int cras_bt_io_append(struct cras_iodev *bt_iodev, struct cras_iodev *dev, enum cras_bt_device_profile profile) { cras_bt_io_append_called++; cras_bt_io_append_profile_val = profile; cras_bt_io_append_btio_val = bt_iodev; return 0; } int cras_bt_io_on_profile(struct cras_iodev *bt_iodev, enum cras_bt_device_profile profile) { return 0; } int cras_bt_io_update_buffer_size(struct cras_iodev *bt_iodev) { return 0; } unsigned int cras_bt_io_try_remove(struct cras_iodev *bt_iodev, struct cras_iodev *dev) { return cras_bt_io_try_remove_ret; } int cras_bt_io_remove(struct cras_iodev *bt_iodev, struct cras_iodev *dev) { cras_bt_io_remove_called++; return 0; } /* From bt_adapter */ struct cras_bt_adapter *cras_bt_adapter_get(const char *object_path) { return NULL; } const char *cras_bt_adapter_address(const struct cras_bt_adapter *adapter) { return NULL; } int cras_bt_adapter_on_usb(struct cras_bt_adapter *adapter) { return 1; } /* From bt_profile */ void cras_bt_profile_on_device_disconnected(struct cras_bt_device *device) { } /* From hfp_ag_profile */ struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device) { return NULL; } void cras_hfp_ag_suspend_connected_device(struct cras_bt_device *device) { } void cras_a2dp_suspend_connected_device(struct cras_bt_device *device) { } void cras_a2dp_start(struct cras_bt_device *device) { } int cras_hfp_ag_start(struct cras_bt_device *device) { return 0; } void cras_hfp_ag_suspend() { } /* From hfp_slc */ int hfp_event_speaker_gain(struct hfp_slc_handle *handle, int gain) { return 0; } /* From iodev_list */ int cras_iodev_open(struct cras_iodev *dev, unsigned int cb_level, const struct cras_audio_format *fmt) { return 0; } int cras_iodev_close(struct cras_iodev *dev) { return 0; } int cras_iodev_list_dev_is_enabled(const struct cras_iodev *dev) { return 0; } void cras_iodev_list_disable_dev(struct cras_iodev *dev) { } void cras_iodev_list_enable_dev(struct cras_iodev *dev) { } void cras_iodev_list_notify_node_volume(struct cras_ionode *node) { } int cras_main_message_send(struct cras_main_message *msg) { // cras_main_message is a local variable from caller, we should allocate // memory from heap and copy its data if(cras_main_message_send_msg) free(cras_main_message_send_msg); cras_main_message_send_msg = (struct cras_main_message *)calloc(1, msg->length); memcpy((void *)cras_main_message_send_msg, (void *)msg, msg->length); return 0; } int cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type, cras_message_callback callback, void *callback_data) { cras_main_message_add_handler_callback = callback; cras_main_message_add_handler_callback_data = callback_data; return 0; } /* From cras_system_state */ struct cras_tm *cras_system_state_get_tm() { return NULL; } /* From cras_tm */ struct cras_timer *cras_tm_create_timer( struct cras_tm *tm, unsigned int ms, void (*cb)(struct cras_timer *t, void *data), void *cb_data) { return NULL; } void cras_tm_cancel_timer(struct cras_tm *tm, struct cras_timer *t) { } } // extern "C" } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }