| /* |
| * Copyright 2018 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 <algorithm> |
| #include <iostream> |
| |
| #include <base/bind.h> |
| #include <base/logging.h> |
| #include <base/threading/thread.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "avrcp_packet.h" |
| #include "avrcp_test_helper.h" |
| #include "device.h" |
| #include "stack_config.h" |
| #include "tests/avrcp/avrcp_test_packets.h" |
| #include "tests/packet_test_helper.h" |
| |
| namespace bluetooth { |
| namespace avrcp { |
| |
| // TODO (apanicke): All the tests below are just basic positive unit tests. |
| // Add more tests to increase code coverage. |
| |
| using AvrcpResponse = std::unique_ptr<::bluetooth::PacketBuilder>; |
| using TestAvrcpPacket = TestPacketType<Packet>; |
| using TestBrowsePacket = TestPacketType<BrowsePacket>; |
| |
| using ::testing::_; |
| using ::testing::MockFunction; |
| using ::testing::Mock; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| |
| bool get_pts_avrcp_test(void) { return false; } |
| |
| const stack_config_t interface = { |
| nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr, |
| nullptr}; |
| |
| // TODO (apanicke): All the tests below are just basic positive unit tests. |
| // Add more tests to increase code coverage. |
| class AvrcpDeviceTest : public ::testing::Test { |
| public: |
| virtual void SetUp() override { |
| // NOTE: We use a wrapper lambda for the MockFunction in order to |
| // add a const qualifier to the response. Otherwise the MockFunction |
| // type doesn't match the callback type and a compiler error occurs. |
| base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = base::Bind( |
| [](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, |
| uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, |
| &response_cb); |
| |
| // TODO (apanicke): Test setting avrc13 to false once we have full |
| // functionality. |
| test_device = new Device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF); |
| } |
| |
| virtual void TearDown() override { |
| delete test_device; |
| Mock::VerifyAndClear(&response_cb); |
| } |
| |
| void SendMessage(uint8_t label, std::shared_ptr<Packet> message) { |
| test_device->MessageReceived(label, message); |
| } |
| |
| void SendBrowseMessage(uint8_t label, std::shared_ptr<BrowsePacket> message) { |
| test_device->BrowseMessageReceived(label, message); |
| } |
| |
| MockFunction<void(uint8_t, bool, const AvrcpResponse&)> response_cb; |
| Device* test_device; |
| }; |
| |
| TEST_F(AvrcpDeviceTest, addressTest) { |
| base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = |
| base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, |
| uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, |
| &response_cb); |
| |
| Device device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF); |
| ASSERT_EQ(device.GetAddress(), RawAddress::kAny); |
| } |
| |
| TEST_F(AvrcpDeviceTest, trackChangedTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {// The attribute map |
| AttributeEntry(Attribute::TITLE, "Test Song"), |
| AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), |
| AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), |
| AttributeEntry(Attribute::TRACK_NUMBER, "1"), |
| AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), |
| AttributeEntry(Attribute::GENRE, "Test Genre"), |
| AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; |
| std::vector<SongInfo> list = {info}; |
| |
| EXPECT_CALL(interface, GetNowPlayingList(_)) |
| .Times(2) |
| .WillRepeatedly(InvokeCb<0>("test_id", list)); |
| |
| // Test the interim response for track changed |
| auto interim_response = |
| RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(true, 0x01); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(interim_response)))) |
| .Times(1); |
| |
| auto request = |
| RegisterNotificationRequestBuilder::MakeBuilder(Event::TRACK_CHANGED, 0); |
| auto pkt = TestAvrcpPacket::Make(); |
| request->Serialize(pkt); |
| SendMessage(1, pkt); |
| |
| // Test the changed response for track changed |
| auto changed_response = |
| RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(false, 0x01); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(changed_response)))) |
| .Times(1); |
| |
| test_device->HandleTrackUpdate(); |
| } |
| |
| TEST_F(AvrcpDeviceTest, playStatusTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| PlayStatus status1 = {0x1234, 0x5678, PlayState::PLAYING}; |
| PlayStatus status2 = {0x1234, 0x5678, PlayState::STOPPED}; |
| |
| EXPECT_CALL(interface, GetPlayStatus(_)) |
| .Times(2) |
| .WillOnce(InvokeCb<0>(status1)) |
| .WillOnce(InvokeCb<0>(status2)); |
| |
| // Pretend the device is active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(test_device->GetAddress())); |
| |
| // Test the interim response for play status changed |
| auto interim_response = |
| RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( |
| true, PlayState::PLAYING); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(interim_response)))) |
| .Times(1); |
| |
| auto request = RegisterNotificationRequestBuilder::MakeBuilder( |
| Event::PLAYBACK_STATUS_CHANGED, 0); |
| auto pkt = TestAvrcpPacket::Make(); |
| request->Serialize(pkt); |
| SendMessage(1, pkt); |
| |
| // Test the changed response for play status changed |
| auto changed_response = |
| RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( |
| false, PlayState::STOPPED); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(changed_response)))) |
| .Times(1); |
| test_device->HandlePlayStatusUpdate(); |
| } |
| |
| TEST_F(AvrcpDeviceTest, playPositionTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| PlayStatus status1 = {0x1234, 0x5678, PlayState::PLAYING}; |
| PlayStatus status2 = {0x5678, 0x9ABC, PlayState::STOPPED}; |
| |
| EXPECT_CALL(interface, GetPlayStatus(_)) |
| .Times(2) |
| .WillOnce(InvokeCb<0>(status1)) |
| .WillOnce(InvokeCb<0>(status2)); |
| |
| // Pretend the device is active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(test_device->GetAddress())); |
| |
| // Test the interim response for play status changed |
| auto interim_response = |
| RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( |
| true, PlayState::PLAYING); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(interim_response)))) |
| .Times(1); |
| |
| auto request = RegisterNotificationRequestBuilder::MakeBuilder( |
| Event::PLAYBACK_STATUS_CHANGED, 0); |
| auto pkt = TestAvrcpPacket::Make(); |
| request->Serialize(pkt); |
| SendMessage(1, pkt); |
| |
| // Test the changed response for play status changed |
| auto changed_response = |
| RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder( |
| false, PlayState::STOPPED); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(changed_response)))) |
| .Times(1); |
| test_device->HandlePlayStatusUpdate(); |
| } |
| |
| TEST_F(AvrcpDeviceTest, nowPlayingTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {// The attribute map |
| AttributeEntry(Attribute::TITLE, "Test Song"), |
| AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), |
| AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), |
| AttributeEntry(Attribute::TRACK_NUMBER, "1"), |
| AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), |
| AttributeEntry(Attribute::GENRE, "Test Genre"), |
| AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; |
| std::vector<SongInfo> list = {info}; |
| EXPECT_CALL(interface, GetNowPlayingList(_)) |
| .Times(2) |
| .WillRepeatedly(InvokeCb<0>("test_id", list)); |
| |
| // Test the interim response for now playing list changed |
| auto interim_response = |
| RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(true); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(interim_response)))) |
| .Times(1); |
| |
| auto request = RegisterNotificationRequestBuilder::MakeBuilder( |
| Event::NOW_PLAYING_CONTENT_CHANGED, 0); |
| auto pkt = TestAvrcpPacket::Make(); |
| request->Serialize(pkt); |
| SendMessage(1, pkt); |
| |
| // Test the changed response for now playing list changed |
| auto changed_response = |
| RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(false); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(changed_response)))) |
| .Times(1); |
| test_device->HandleNowPlayingUpdate(); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getPlayStatusTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING}; |
| |
| EXPECT_CALL(interface, GetPlayStatus(_)) |
| .Times(1) |
| .WillOnce(InvokeCb<0>(status)); |
| |
| // Pretend the device is active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(test_device->GetAddress())); |
| |
| auto expected_response = GetPlayStatusResponseBuilder::MakeBuilder( |
| 0x5678, 0x1234, PlayState::PLAYING); |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(expected_response)))) |
| .Times(1); |
| |
| auto request = TestAvrcpPacket::Make(get_play_status_request); |
| SendMessage(1, request); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getElementAttributesTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {// The attribute map |
| AttributeEntry(Attribute::TITLE, "Test Song"), |
| AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), |
| AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), |
| AttributeEntry(Attribute::TRACK_NUMBER, "1"), |
| AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), |
| AttributeEntry(Attribute::GENRE, "Test Genre"), |
| AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; |
| |
| EXPECT_CALL(interface, GetSongInfo(_)).WillRepeatedly(InvokeCb<0>(info)); |
| |
| auto compare_to_partial = |
| GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF); |
| compare_to_partial->AddAttributeEntry(Attribute::TITLE, "Test Song"); |
| EXPECT_CALL(response_cb, |
| Call(2, false, matchPacket(std::move(compare_to_partial)))) |
| .Times(1); |
| SendMessage(2, TestAvrcpPacket::Make(get_element_attributes_request_partial)); |
| |
| auto compare_to_full = |
| GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF); |
| compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song"); |
| compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist"); |
| compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album"); |
| compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1"); |
| compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"); |
| compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre"); |
| compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000"); |
| EXPECT_CALL(response_cb, |
| Call(3, false, matchPacket(std::move(compare_to_full)))) |
| .Times(1); |
| SendMessage(3, TestAvrcpPacket::Make(get_element_attributes_request_full)); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getElementAttributesMtuTest) { |
| auto truncated_packet = |
| GetElementAttributesResponseBuilder::MakeBuilder(0xFFFF); |
| truncated_packet->AddAttributeEntry(Attribute::TITLE, "1234"); |
| |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = |
| base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, |
| uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, |
| &response_cb); |
| Device device(RawAddress::kAny, true, cb, truncated_packet->size(), 0xFFFF); |
| |
| device.RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {AttributeEntry(Attribute::TITLE, "1234truncated")}}; |
| EXPECT_CALL(interface, GetSongInfo(_)).WillRepeatedly(InvokeCb<0>(info)); |
| |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(truncated_packet)))) |
| .Times(1); |
| |
| device.MessageReceived( |
| 1, TestAvrcpPacket::Make(get_element_attributes_request_full)); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsMediaPlayersTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| std::vector<MediaPlayerInfo> player_list = { |
| {0, "player1", true}, {1, "player2", true}, {2, "player3", true}, |
| }; |
| |
| EXPECT_CALL(interface, GetMediaPlayerList(_)) |
| .Times(1) |
| .WillOnce(InvokeCb<0>(0, player_list)); |
| |
| auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder( |
| Status::NO_ERROR, 0, player_list.size()); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(expected_response)))) |
| .Times(1); |
| |
| SendBrowseMessage(1, TestBrowsePacket::Make( |
| get_total_number_of_items_request_media_players)); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsVFSTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| std::vector<ListItem> vfs_list = { |
| {ListItem::FOLDER, {"id1", true, "folder1"}, SongInfo()}, |
| {ListItem::FOLDER, {"id2", true, "folder2"}, SongInfo()}, |
| }; |
| |
| EXPECT_CALL(interface, GetFolderItems(_, "", _)) |
| .Times(1) |
| .WillOnce(InvokeCb<2>(vfs_list)); |
| |
| auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder( |
| Status::NO_ERROR, 0, vfs_list.size()); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(expected_response)))) |
| .Times(1); |
| |
| SendBrowseMessage( |
| 1, TestBrowsePacket::Make(get_total_number_of_items_request_vfs)); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getTotalNumberOfItemsNowPlayingTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| std::vector<SongInfo> now_playing_list = { |
| {"test_id1", {}}, {"test_id2", {}}, {"test_id3", {}}, |
| {"test_id4", {}}, {"test_id5", {}}, |
| }; |
| |
| EXPECT_CALL(interface, GetNowPlayingList(_)) |
| .WillRepeatedly(InvokeCb<0>("test_id1", now_playing_list)); |
| |
| auto expected_response = GetTotalNumberOfItemsResponseBuilder::MakeBuilder( |
| Status::NO_ERROR, 0, now_playing_list.size()); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(expected_response)))) |
| .Times(1); |
| |
| SendBrowseMessage( |
| 1, TestBrowsePacket::Make(get_total_number_of_items_request_now_playing)); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getMediaPlayerListTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| MediaPlayerInfo info = {0, "Test Player", true}; |
| std::vector<MediaPlayerInfo> list = {info}; |
| |
| EXPECT_CALL(interface, GetMediaPlayerList(_)) |
| .Times(1) |
| .WillOnce(InvokeCb<0>(0, list)); |
| |
| auto expected_response = GetFolderItemsResponseBuilder::MakePlayerListBuilder( |
| Status::NO_ERROR, 0x0000, 0xFFFF); |
| expected_response->AddMediaPlayer(MediaPlayerItem(0, "Test Player", true)); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(expected_response)))) |
| .Times(1); |
| |
| auto request = TestBrowsePacket::Make(get_folder_items_request); |
| SendBrowseMessage(1, request); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getNowPlayingListTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {// The attribute map |
| AttributeEntry(Attribute::TITLE, "Test Song"), |
| AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), |
| AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), |
| AttributeEntry(Attribute::TRACK_NUMBER, "1"), |
| AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), |
| AttributeEntry(Attribute::GENRE, "Test Genre"), |
| AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; |
| std::vector<SongInfo> list = {info}; |
| |
| EXPECT_CALL(interface, GetNowPlayingList(_)) |
| .WillRepeatedly(InvokeCb<0>("test_id", list)); |
| |
| auto expected_response = GetFolderItemsResponseBuilder::MakeNowPlayingBuilder( |
| Status::NO_ERROR, 0x0000, 0xFFFF); |
| expected_response->AddSong(MediaElementItem(1, "Test Song", info.attributes)); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(expected_response)))) |
| .Times(1); |
| |
| auto request = TestBrowsePacket::Make(get_folder_items_request_now_playing); |
| SendBrowseMessage(1, request); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getVFSFolderTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| FolderInfo info = {"test_id", true, "Test Folder"}; |
| ListItem item = {ListItem::FOLDER, info, SongInfo()}; |
| std::vector<ListItem> list = {item}; |
| |
| EXPECT_CALL(interface, GetFolderItems(_, "", _)) |
| .Times(1) |
| .WillOnce(InvokeCb<2>(list)); |
| |
| auto expected_response = GetFolderItemsResponseBuilder::MakeVFSBuilder( |
| Status::NO_ERROR, 0x0000, 0xFFFF); |
| expected_response->AddFolder(FolderItem(1, 0, true, "Test Folder")); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(expected_response)))) |
| .Times(1); |
| |
| auto request = TestBrowsePacket::Make(get_folder_items_request_vfs); |
| SendBrowseMessage(1, request); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getFolderItemsMtuTest) { |
| auto truncated_packet = GetFolderItemsResponseBuilder::MakeVFSBuilder( |
| Status::NO_ERROR, 0x0000, 0xFFFF); |
| truncated_packet->AddFolder(FolderItem(1, 0, true, "Test Folder0")); |
| truncated_packet->AddFolder(FolderItem(2, 0, true, "Test Folder1")); |
| |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = |
| base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, |
| uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, |
| &response_cb); |
| Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size()); |
| device.RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| FolderInfo info0 = {"test_id0", true, "Test Folder0"}; |
| FolderInfo info1 = {"test_id1", true, "Test Folder1"}; |
| FolderInfo info2 = {"test_id1", true, "Truncated folder"}; |
| ListItem item0 = {ListItem::FOLDER, info0, SongInfo()}; |
| ListItem item1 = {ListItem::FOLDER, info1, SongInfo()}; |
| ListItem item2 = {ListItem::FOLDER, info1, SongInfo()}; |
| std::vector<ListItem> list0 = {item0, item1, item2}; |
| EXPECT_CALL(interface, GetFolderItems(_, "", _)) |
| .WillRepeatedly(InvokeCb<2>(list0)); |
| |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(truncated_packet)))) |
| .Times(1); |
| device.BrowseMessageReceived( |
| 1, TestBrowsePacket::Make(get_folder_items_request_vfs)); |
| } |
| |
| TEST_F(AvrcpDeviceTest, changePathTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| FolderInfo info0 = {"test_id0", true, "Test Folder0"}; |
| FolderInfo info1 = {"test_id1", true, "Test Folder1"}; |
| ListItem item0 = {ListItem::FOLDER, info0, SongInfo()}; |
| ListItem item1 = {ListItem::FOLDER, info1, SongInfo()}; |
| std::vector<ListItem> list0 = {item0, item1}; |
| EXPECT_CALL(interface, GetFolderItems(_, "", _)) |
| .Times(1) |
| .WillRepeatedly(InvokeCb<2>(list0)); |
| |
| FolderInfo info2 = {"test_id2", true, "Test Folder2"}; |
| FolderInfo info3 = {"test_id3", true, "Test Folder3"}; |
| FolderInfo info4 = {"test_id4", true, "Test Folder4"}; |
| ListItem item2 = {ListItem::FOLDER, info2, SongInfo()}; |
| ListItem item3 = {ListItem::FOLDER, info3, SongInfo()}; |
| ListItem item4 = {ListItem::FOLDER, info4, SongInfo()}; |
| std::vector<ListItem> list1 = {item2, item3, item4}; |
| EXPECT_CALL(interface, GetFolderItems(_, "test_id1", _)) |
| .Times(3) |
| .WillRepeatedly(InvokeCb<2>(list1)); |
| |
| std::vector<ListItem> list2 = {}; |
| EXPECT_CALL(interface, GetFolderItems(_, "test_id3", _)) |
| .Times(1) |
| .WillOnce(InvokeCb<2>(list2)); |
| |
| // Populate the VFS ID map |
| auto folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder( |
| Status::NO_ERROR, 0x0000, 0xFFFF); |
| folder_items_response->AddFolder(FolderItem(1, 0, true, "Test Folder0")); |
| folder_items_response->AddFolder(FolderItem(2, 0, true, "Test Folder1")); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(folder_items_response)))) |
| .Times(1); |
| |
| auto folder_request_builder = |
| GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {}); |
| auto request = TestBrowsePacket::Make(); |
| folder_request_builder->Serialize(request); |
| SendBrowseMessage(1, request); |
| |
| // Change path down into Test Folder1 |
| auto change_path_response = |
| ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size()); |
| EXPECT_CALL(response_cb, |
| Call(2, true, matchPacket(std::move(change_path_response)))); |
| auto path_request_builder = |
| ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 2); |
| request = TestBrowsePacket::Make(); |
| path_request_builder->Serialize(request); |
| SendBrowseMessage(2, request); |
| |
| // Populate the new VFS ID |
| folder_items_response = GetFolderItemsResponseBuilder::MakeVFSBuilder( |
| Status::NO_ERROR, 0x0000, 0xFFFF); |
| folder_items_response->AddFolder(FolderItem(3, 0, true, "Test Folder2")); |
| folder_items_response->AddFolder(FolderItem(4, 0, true, "Test Folder3")); |
| folder_items_response->AddFolder(FolderItem(5, 0, true, "Test Folder4")); |
| EXPECT_CALL(response_cb, |
| Call(3, true, matchPacket(std::move(folder_items_response)))) |
| .Times(1); |
| folder_request_builder = |
| GetFolderItemsRequestBuilder::MakeBuilder(Scope::VFS, 0, 3, {}); |
| request = TestBrowsePacket::Make(); |
| folder_request_builder->Serialize(request); |
| SendBrowseMessage(3, request); |
| |
| // Change path down into Test Folder3 |
| change_path_response = |
| ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list2.size()); |
| EXPECT_CALL(response_cb, |
| Call(4, true, matchPacket(std::move(change_path_response)))); |
| path_request_builder = |
| ChangePathRequestBuilder::MakeBuilder(0, Direction::DOWN, 4); |
| request = TestBrowsePacket::Make(); |
| path_request_builder->Serialize(request); |
| SendBrowseMessage(4, request); |
| |
| // Change path up back into Test Folder1 |
| change_path_response = |
| ChangePathResponseBuilder::MakeBuilder(Status::NO_ERROR, list1.size()); |
| EXPECT_CALL(response_cb, |
| Call(5, true, matchPacket(std::move(change_path_response)))); |
| path_request_builder = |
| ChangePathRequestBuilder::MakeBuilder(0, Direction::UP, 0); |
| request = TestBrowsePacket::Make(); |
| path_request_builder->Serialize(request); |
| SendBrowseMessage(5, request); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getItemAttributesNowPlayingTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {// The attribute map |
| AttributeEntry(Attribute::TITLE, "Test Song"), |
| AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), |
| AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), |
| AttributeEntry(Attribute::TRACK_NUMBER, "1"), |
| AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), |
| AttributeEntry(Attribute::GENRE, "Test Genre"), |
| AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; |
| std::vector<SongInfo> list = {info}; |
| |
| EXPECT_CALL(interface, GetNowPlayingList(_)) |
| .WillRepeatedly(InvokeCb<0>("test_id", list)); |
| |
| auto compare_to_full = |
| GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF); |
| compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song"); |
| compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist"); |
| compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album"); |
| compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1"); |
| compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"); |
| compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre"); |
| compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000"); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(compare_to_full)))) |
| .Times(1); |
| |
| auto request = |
| TestBrowsePacket::Make(get_item_attributes_request_all_attributes); |
| SendBrowseMessage(1, request); |
| } |
| |
| TEST_F(AvrcpDeviceTest, geItemAttributesMtuTest) { |
| auto truncated_packet = |
| GetItemAttributesResponseBuilder::MakeBuilder(Status::NO_ERROR, 0xFFFF); |
| truncated_packet->AddAttributeEntry(Attribute::TITLE, "1234"); |
| |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| base::Callback<void(uint8_t, bool, AvrcpResponse)> cb = |
| base::Bind([](MockFunction<void(uint8_t, bool, const AvrcpResponse&)>* a, |
| uint8_t b, bool c, AvrcpResponse d) { a->Call(b, c, d); }, |
| &response_cb); |
| Device device(RawAddress::kAny, true, cb, 0xFFFF, truncated_packet->size()); |
| device.RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {AttributeEntry(Attribute::TITLE, "1234truncated")}}; |
| std::vector<SongInfo> list = {info}; |
| EXPECT_CALL(interface, GetNowPlayingList(_)) |
| .WillRepeatedly(InvokeCb<0>("test_id", list)); |
| |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(truncated_packet)))) |
| .Times(1); |
| device.BrowseMessageReceived( |
| 1, TestBrowsePacket::Make(get_item_attributes_request_all_attributes)); |
| } |
| |
| TEST_F(AvrcpDeviceTest, setAddressedPlayerTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| auto set_addr_player_rsp = RejectBuilder::MakeBuilder( |
| CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PLAYER_ID); |
| |
| EXPECT_CALL(response_cb, |
| Call(1, false, matchPacket(std::move(set_addr_player_rsp)))) |
| .Times(1); |
| |
| auto request = TestAvrcpPacket::Make(set_addressed_player_request); |
| SendMessage(1, request); |
| } |
| |
| TEST_F(AvrcpDeviceTest, volumeChangedTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| MockVolumeInterface vol_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); |
| |
| // Pretend the device is active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(test_device->GetAddress())); |
| |
| auto reg_notif = |
| RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); |
| EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif)))) |
| .Times(1); |
| test_device->RegisterVolumeChanged(); |
| |
| EXPECT_CALL(vol_interface, DeviceConnected(test_device->GetAddress(), _)) |
| .Times(1) |
| .WillOnce(InvokeCb<1>(0x30)); |
| auto set_vol = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0x30); |
| EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(set_vol)))) |
| .Times(1); |
| |
| auto response = TestAvrcpPacket::Make(interim_volume_changed_notification); |
| SendMessage(1, response); |
| |
| EXPECT_CALL(vol_interface, SetVolume(0x47)).Times(1); |
| auto reg_notif2 = |
| RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); |
| EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif2)))) |
| .Times(1); |
| response = TestAvrcpPacket::Make(changed_volume_changed_notification); |
| SendMessage(1, response); |
| response = TestAvrcpPacket::Make(interim_volume_changed_notification); |
| SendMessage(1, response); |
| } |
| |
| TEST_F(AvrcpDeviceTest, volumeChangedNonActiveTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| MockVolumeInterface vol_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); |
| |
| // Pretend the device isn't active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(RawAddress::kEmpty)); |
| |
| auto reg_notif = |
| RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); |
| EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif)))) |
| .Times(1); |
| test_device->RegisterVolumeChanged(); |
| |
| EXPECT_CALL(vol_interface, DeviceConnected(test_device->GetAddress(), _)) |
| .Times(1) |
| .WillOnce(InvokeCb<1>(0x30)); |
| auto set_vol = SetAbsoluteVolumeRequestBuilder::MakeBuilder(0x30); |
| EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(set_vol)))) |
| .Times(1); |
| |
| auto response = TestAvrcpPacket::Make(interim_volume_changed_notification); |
| SendMessage(1, response); |
| |
| // Ensure that SetVolume is never called |
| EXPECT_CALL(vol_interface, SetVolume(0x47)).Times(0); |
| |
| auto reg_notif2 = |
| RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); |
| EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif2)))) |
| .Times(1); |
| response = TestAvrcpPacket::Make(changed_volume_changed_notification); |
| SendMessage(1, response); |
| response = TestAvrcpPacket::Make(interim_volume_changed_notification); |
| SendMessage(1, response); |
| } |
| |
| TEST_F(AvrcpDeviceTest, volumeRejectedTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| MockVolumeInterface vol_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); |
| |
| auto reg_notif = |
| RegisterNotificationRequestBuilder::MakeBuilder(Event::VOLUME_CHANGED, 0); |
| EXPECT_CALL(response_cb, Call(_, false, matchPacket(std::move(reg_notif)))) |
| .Times(1); |
| test_device->RegisterVolumeChanged(); |
| |
| auto response = TestAvrcpPacket::Make(rejected_volume_changed_notification); |
| SendMessage(1, response); |
| |
| EXPECT_CALL(response_cb, Call(_, _, _)).Times(0); |
| } |
| |
| TEST_F(AvrcpDeviceTest, playPushedActiveDeviceTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| MockVolumeInterface vol_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); |
| |
| // Pretend the device is active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(test_device->GetAddress())); |
| |
| auto play_pushed = PassThroughPacketBuilder::MakeBuilder(false, true, 0x44); |
| auto play_pushed_response = |
| PassThroughPacketBuilder::MakeBuilder(true, true, 0x44); |
| EXPECT_CALL(response_cb, |
| Call(_, false, matchPacket(std::move(play_pushed_response)))) |
| .Times(1); |
| |
| PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING}; |
| EXPECT_CALL(interface, GetPlayStatus(_)) |
| .Times(1) |
| .WillOnce(InvokeCb<0>(status)); |
| |
| EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::PUSHED)).Times(1); |
| |
| auto play_pushed_pkt = TestAvrcpPacket::Make(); |
| play_pushed->Serialize(play_pushed_pkt); |
| |
| SendMessage(1, play_pushed_pkt); |
| } |
| |
| TEST_F(AvrcpDeviceTest, playPushedInactiveDeviceTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| MockVolumeInterface vol_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); |
| |
| // Pretend the device is not active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(RawAddress::kEmpty)); |
| |
| auto play_pushed = PassThroughPacketBuilder::MakeBuilder(false, true, 0x44); |
| auto play_pushed_response = |
| PassThroughPacketBuilder::MakeBuilder(true, true, 0x44); |
| EXPECT_CALL(response_cb, |
| Call(_, false, matchPacket(std::move(play_pushed_response)))) |
| .Times(1); |
| |
| // Expect that the device will try to set itself as active |
| EXPECT_CALL(interface, SetActiveDevice(test_device->GetAddress())).Times(1); |
| |
| // No play command should be sent since the music is already playing |
| PlayStatus status = {0x1234, 0x5678, PlayState::PLAYING}; |
| EXPECT_CALL(interface, GetPlayStatus(_)) |
| .Times(1) |
| .WillOnce(InvokeCb<0>(status)); |
| EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::PUSHED)).Times(0); |
| |
| auto play_pushed_pkt = TestAvrcpPacket::Make(); |
| play_pushed->Serialize(play_pushed_pkt); |
| |
| SendMessage(1, play_pushed_pkt); |
| } |
| |
| TEST_F(AvrcpDeviceTest, mediaKeyActiveDeviceTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| MockVolumeInterface vol_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); |
| |
| // Pretend the device is active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(test_device->GetAddress())); |
| |
| auto play_released = |
| PassThroughPacketBuilder::MakeBuilder(false, false, 0x44); |
| auto play_released_response = |
| PassThroughPacketBuilder::MakeBuilder(true, false, 0x44); |
| EXPECT_CALL(response_cb, |
| Call(_, false, matchPacket(std::move(play_released_response)))) |
| .Times(1); |
| |
| EXPECT_CALL(interface, GetPlayStatus(_)).Times(0); |
| |
| EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::RELEASED)).Times(1); |
| |
| auto play_released_pkt = TestAvrcpPacket::Make(); |
| play_released->Serialize(play_released_pkt); |
| |
| SendMessage(1, play_released_pkt); |
| } |
| |
| TEST_F(AvrcpDeviceTest, mediaKeyInactiveDeviceTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| MockVolumeInterface vol_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, &vol_interface); |
| |
| // Pretend the device is not active |
| EXPECT_CALL(a2dp_interface, active_peer()) |
| .WillRepeatedly(Return(RawAddress::kEmpty)); |
| |
| auto play_released = |
| PassThroughPacketBuilder::MakeBuilder(false, false, 0x44); |
| auto play_released_response = |
| PassThroughPacketBuilder::MakeBuilder(true, false, 0x44); |
| EXPECT_CALL(response_cb, |
| Call(_, false, matchPacket(std::move(play_released_response)))) |
| .Times(1); |
| |
| EXPECT_CALL(interface, GetPlayStatus(_)).Times(0); |
| |
| // Expect that the key event wont be sent to the media interface |
| EXPECT_CALL(interface, SendKeyEvent(0x44, KeyState::RELEASED)).Times(0); |
| |
| auto play_released_pkt = TestAvrcpPacket::Make(); |
| play_released->Serialize(play_released_pkt); |
| |
| SendMessage(1, play_released_pkt); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getCapabilitiesTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| // GetCapabilities with CapabilityID COMPANY_ID |
| auto request_company_id_response = |
| GetCapabilitiesResponseBuilder::MakeCompanyIdBuilder(0x001958); |
| request_company_id_response->AddCompanyId(0x002345); |
| EXPECT_CALL( |
| response_cb, |
| Call(1, false, matchPacket(std::move(request_company_id_response)))) |
| .Times(1); |
| |
| auto request_company_id = |
| TestAvrcpPacket::Make(get_capabilities_request_company_id); |
| SendMessage(1, request_company_id); |
| |
| // GetCapabilities with CapabilityID EVENTS_SUPPORTED |
| auto request_events_supported_response = |
| GetCapabilitiesResponseBuilder::MakeEventsSupportedBuilder( |
| Event::PLAYBACK_STATUS_CHANGED); |
| request_events_supported_response->AddEvent(Event::TRACK_CHANGED); |
| request_events_supported_response->AddEvent(Event::PLAYBACK_POS_CHANGED); |
| |
| EXPECT_CALL( |
| response_cb, |
| Call(2, false, matchPacket(std::move(request_events_supported_response)))) |
| .Times(1); |
| |
| auto request_events_supported = |
| TestAvrcpPacket::Make(get_capabilities_request); |
| SendMessage(2, request_events_supported); |
| |
| // GetCapabilities with CapabilityID UNKNOWN |
| auto request_unknown_response = RejectBuilder::MakeBuilder( |
| CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER); |
| |
| EXPECT_CALL(response_cb, |
| Call(3, false, matchPacket(std::move(request_unknown_response)))) |
| .Times(1); |
| |
| auto request_unknown = |
| TestAvrcpPacket::Make(get_capabilities_request_unknown); |
| SendMessage(3, request_unknown); |
| } |
| |
| TEST_F(AvrcpDeviceTest, getInvalidItemAttributesTest) { |
| MockMediaInterface interface; |
| NiceMock<MockA2dpInterface> a2dp_interface; |
| |
| test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr); |
| |
| SongInfo info = {"test_id", |
| {// The attribute map |
| AttributeEntry(Attribute::TITLE, "Test Song"), |
| AttributeEntry(Attribute::ARTIST_NAME, "Test Artist"), |
| AttributeEntry(Attribute::ALBUM_NAME, "Test Album"), |
| AttributeEntry(Attribute::TRACK_NUMBER, "1"), |
| AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"), |
| AttributeEntry(Attribute::GENRE, "Test Genre"), |
| AttributeEntry(Attribute::PLAYING_TIME, "1000")}}; |
| std::vector<SongInfo> list = {info}; |
| |
| EXPECT_CALL(interface, GetNowPlayingList(_)) |
| .WillRepeatedly(InvokeCb<0>("test_id", list)); |
| |
| auto compare_to_full = GetItemAttributesResponseBuilder::MakeBuilder( |
| Status::UIDS_CHANGED, 0xFFFF); |
| compare_to_full->AddAttributeEntry(Attribute::TITLE, "Test Song"); |
| compare_to_full->AddAttributeEntry(Attribute::ARTIST_NAME, "Test Artist"); |
| compare_to_full->AddAttributeEntry(Attribute::ALBUM_NAME, "Test Album"); |
| compare_to_full->AddAttributeEntry(Attribute::TRACK_NUMBER, "1"); |
| compare_to_full->AddAttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, "2"); |
| compare_to_full->AddAttributeEntry(Attribute::GENRE, "Test Genre"); |
| compare_to_full->AddAttributeEntry(Attribute::PLAYING_TIME, "1000"); |
| EXPECT_CALL(response_cb, |
| Call(1, true, matchPacket(std::move(compare_to_full)))) |
| .Times(1); |
| |
| auto request = TestBrowsePacket::Make( |
| get_item_attributes_request_all_attributes_invalid); |
| SendBrowseMessage(1, request); |
| } |
| |
| } // namespace avrcp |
| } // namespace bluetooth |
| |
| const stack_config_t* stack_config_get_interface(void) { |
| return &bluetooth::avrcp::interface; |
| } |