/* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "bta/jv/bta_jv_int.h" #include "bta_jv_api.h" #include "osi/include/allocator.h" #include "stack/include/sdp_status.h" #include "test/common/mock_functions.h" #include "test/fake/fake_osi.h" #include "test/mock/mock_stack_sdp_legacy_api.h" #include "types/bluetooth/uuid.h" #include "types/raw_address.h" namespace { const RawAddress kRawAddress = RawAddress({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}); const RawAddress kRawAddress2 = RawAddress({0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc}); const bluetooth::Uuid kUuid = bluetooth::Uuid::From16Bit(0x1234); const bluetooth::Uuid kUuid2 = bluetooth::Uuid::From16Bit(0x789a); constexpr uint32_t kSlotId = 0x1234568; constexpr uint8_t kScn = 123; } // namespace namespace bluetooth::legacy::testing { void bta_jv_start_discovery_cback(uint32_t rfcomm_slot_id, const RawAddress& bd_addr, tSDP_RESULT result); } // namespace bluetooth::legacy::testing class FakeSdp { public: FakeSdp() { test::mock::stack_sdp_legacy::api_ = { .service = { .SDP_InitDiscoveryDb = [](tSDP_DISCOVERY_DB*, uint32_t, uint16_t, const bluetooth::Uuid*, uint16_t, const uint16_t*) -> bool { return true; }, .SDP_CancelServiceSearch = nullptr, .SDP_ServiceSearchRequest = nullptr, .SDP_ServiceSearchAttributeRequest = nullptr, .SDP_ServiceSearchAttributeRequest2 = [](const RawAddress& /* p_bd_addr */, tSDP_DISCOVERY_DB* /* p_db */, base::RepeatingCallback< tSDP_DISC_CMPL_CB> /* complete_callback */) { return true; }, }, .db = { .SDP_FindServiceInDb = nullptr, .SDP_FindServiceUUIDInDb = [](const tSDP_DISCOVERY_DB* /* p_db */, const bluetooth::Uuid& /* uuid */, tSDP_DISC_REC* /* p_start_rec */) -> tSDP_DISC_REC* { return nullptr; }, .SDP_FindServiceInDb_128bit = nullptr, }, .record = { .SDP_FindAttributeInRec = nullptr, .SDP_FindServiceUUIDInRec_128bit = nullptr, .SDP_FindProtocolListElemInRec = [](const tSDP_DISC_REC* /* p_rec */, uint16_t /* layer_uuid */, tSDP_PROTOCOL_ELEM* /* p_elem */) -> bool { return false; }, .SDP_FindProfileVersionInRec = nullptr, .SDP_FindServiceUUIDInRec = nullptr, }, .handle = { .SDP_CreateRecord = nullptr, .SDP_DeleteRecord = nullptr, .SDP_AddAttribute = nullptr, .SDP_AddSequence = nullptr, .SDP_AddUuidSequence = nullptr, .SDP_AddProtocolList = nullptr, .SDP_AddAdditionProtoLists = nullptr, .SDP_AddProfileDescriptorList = nullptr, .SDP_AddLanguageBaseAttrIDList = nullptr, .SDP_AddServiceClassIdList = nullptr, }, .device_id = { .SDP_SetLocalDiRecord = nullptr, .SDP_DiDiscover = nullptr, .SDP_GetNumDiRecords = nullptr, .SDP_GetDiRecord = nullptr, }, }; } ~FakeSdp() { test::mock::stack_sdp_legacy::api_ = {}; } }; class BtaJvMockAndFakeTest : public ::testing::Test { protected: void SetUp() override { reset_mock_function_count_map(); fake_osi_ = std::make_unique(); fake_sdp_ = std::make_unique(); } void TearDown() override {} std::unique_ptr fake_osi_; std::unique_ptr fake_sdp_; }; class BtaJvTest : public BtaJvMockAndFakeTest { protected: void SetUp() override { BtaJvMockAndFakeTest::SetUp(); bta_jv_cb.sdp_cb = {}; } void TearDown() override { bta_jv_cb.sdp_cb = {}; BtaJvMockAndFakeTest::TearDown(); } }; TEST_F(BtaJvTest, bta_jv_start_discovery_cback__no_callback) { bta_jv_enable(nullptr); bluetooth::legacy::testing::bta_jv_start_discovery_cback( 0x12345678, kRawAddress, SDP_SUCCESS); } TEST_F(BtaJvTest, bta_jv_start_discovery_cback__with_callback_success_no_record) { // Ensure that there was an sdp active bta_jv_cb.sdp_cb = { .sdp_active = true, .bd_addr = kRawAddress, .uuid = kUuid, }; bta_jv_enable([](tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) { switch (event) { case BTA_JV_DISCOVERY_COMP_EVT: ASSERT_EQ(p_data->disc_comp.status, tBTA_JV_STATUS::FAILURE); ASSERT_EQ(kSlotId, id); break; case BTA_JV_ENABLE_EVT: ASSERT_EQ(p_data->disc_comp.status, tBTA_JV_STATUS::SUCCESS); ASSERT_EQ(0U, id); break; default: FAIL(); } }); bluetooth::legacy::testing::bta_jv_start_discovery_cback(kSlotId, kRawAddress, SDP_SUCCESS); } TEST_F(BtaJvTest, bta_jv_start_discovery_cback__with_callback_success_with_record) { static tSDP_DISC_REC sdp_disc_rec = { .p_first_attr = nullptr, .p_next_rec = nullptr, .time_read = 1, .remote_bd_addr = RawAddress::kAny, }; test::mock::stack_sdp_legacy::api_.db.SDP_FindServiceUUIDInDb = [](const tSDP_DISCOVERY_DB* /* p_db */, const bluetooth::Uuid& /* uuid */, tSDP_DISC_REC* /* p_start_rec */) -> tSDP_DISC_REC* { return &sdp_disc_rec; }; test::mock::stack_sdp_legacy::api_.record.SDP_FindProtocolListElemInRec = [](const tSDP_DISC_REC* /* p_rec */, uint16_t /* layer_uuid */, tSDP_PROTOCOL_ELEM* p_elem) -> bool { p_elem->params[0] = (uint16_t)kScn; return true; }; // Ensure that there was an sdp active bta_jv_cb.sdp_cb = { .sdp_active = true, .bd_addr = kRawAddress, .uuid = kUuid, }; bta_jv_enable([](tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) { switch (event) { case BTA_JV_DISCOVERY_COMP_EVT: ASSERT_EQ(tBTA_JV_STATUS::SUCCESS, p_data->disc_comp.status); ASSERT_EQ(kScn, p_data->disc_comp.scn); ASSERT_EQ(kSlotId, id); break; case BTA_JV_ENABLE_EVT: ASSERT_EQ(tBTA_JV_STATUS::SUCCESS, p_data->disc_comp.status); ASSERT_EQ(0U, id); break; default: FAIL(); } }); bluetooth::legacy::testing::bta_jv_start_discovery_cback(kSlotId, kRawAddress, SDP_SUCCESS); } TEST_F(BtaJvTest, bta_jv_start_discovery_cback__with_callback_failure) { tSDP_RESULT result = SDP_CONN_FAILED; // Ensure that there was an sdp active bta_jv_cb.sdp_cb = { .sdp_active = true, .bd_addr = kRawAddress, .uuid = kUuid, }; bta_jv_enable([](tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) { switch (event) { case BTA_JV_DISCOVERY_COMP_EVT: ASSERT_EQ(tBTA_JV_STATUS::FAILURE, p_data->disc_comp.status); ASSERT_EQ(kSlotId, id); break; case BTA_JV_ENABLE_EVT: ASSERT_EQ(tBTA_JV_STATUS::SUCCESS, p_data->disc_comp.status); ASSERT_EQ(0U, id); break; default: FAIL(); } }); bluetooth::legacy::testing::bta_jv_start_discovery_cback(kSlotId, kRawAddress, result); } TEST_F(BtaJvTest, bta_jv_start_discovery__idle) { bluetooth::Uuid uuid_list[1] = { kUuid, }; uint16_t num_uuid = (uint16_t)(sizeof(uuid_list) / sizeof(uuid_list[0])); bta_jv_start_discovery(kRawAddress, num_uuid, uuid_list, kSlotId); ASSERT_EQ(true, bta_jv_cb.sdp_cb.sdp_active); ASSERT_EQ(kRawAddress, bta_jv_cb.sdp_cb.bd_addr); ASSERT_EQ(kUuid, bta_jv_cb.sdp_cb.uuid); } TEST_F(BtaJvTest, bta_jv_start_discovery__idle_failed_to_start) { bluetooth::Uuid uuid_list[1] = { kUuid, }; uint16_t num_uuid = (uint16_t)(sizeof(uuid_list) / sizeof(uuid_list[0])); test::mock::stack_sdp_legacy::api_.service .SDP_ServiceSearchAttributeRequest2 = [](const RawAddress& /* p_bd_addr */, tSDP_DISCOVERY_DB* /* p_db */, base::RepeatingCallback /* complete_callback */) { return false; }; bta_jv_enable([](tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) { switch (event) { case BTA_JV_DISCOVERY_COMP_EVT: ASSERT_EQ(tBTA_JV_STATUS::FAILURE, p_data->disc_comp.status); ASSERT_EQ(kSlotId, id); break; case BTA_JV_ENABLE_EVT: ASSERT_EQ(tBTA_JV_STATUS::SUCCESS, p_data->disc_comp.status); ASSERT_EQ(0U, id); break; default: FAIL(); } }); bta_jv_start_discovery(kRawAddress2, num_uuid, uuid_list, kSlotId); ASSERT_EQ(false, bta_jv_cb.sdp_cb.sdp_active); ASSERT_EQ(RawAddress::kEmpty, bta_jv_cb.sdp_cb.bd_addr); ASSERT_EQ(bluetooth::Uuid::kEmpty, bta_jv_cb.sdp_cb.uuid); } TEST_F(BtaJvTest, bta_jv_start_discovery__already_active) { bta_jv_cb.sdp_cb = { .sdp_active = true, .bd_addr = kRawAddress, .uuid = kUuid, }; bluetooth::Uuid uuid_list[1] = { kUuid2, }; uint16_t num_uuid = (uint16_t)(sizeof(uuid_list) / sizeof(uuid_list[0])); bta_jv_enable([](tBTA_JV_EVT event, tBTA_JV* p_data, uint32_t id) { switch (event) { case BTA_JV_DISCOVERY_COMP_EVT: ASSERT_EQ(tBTA_JV_STATUS::BUSY, p_data->disc_comp.status); ASSERT_EQ(kSlotId, id); break; case BTA_JV_ENABLE_EVT: ASSERT_EQ(tBTA_JV_STATUS::SUCCESS, p_data->disc_comp.status); ASSERT_EQ(0U, id); break; default: FAIL(); } }); bta_jv_start_discovery(kRawAddress2, num_uuid, uuid_list, kSlotId); ASSERT_EQ(true, bta_jv_cb.sdp_cb.sdp_active); ASSERT_EQ(kRawAddress, bta_jv_cb.sdp_cb.bd_addr); ASSERT_EQ(kUuid, bta_jv_cb.sdp_cb.uuid); }