/*
* 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::Mock;
using ::testing::MockFunction;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
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);
// TODO (apanicke): Add an underlying message loop so we can test the playing
// state.
PlayStatus status1 = {0x1234, 0x5678, PlayState::PAUSED};
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 position changed
auto interim_response =
RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(true,
0x1234);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(interim_response))))
.Times(1);
auto request = RegisterNotificationRequestBuilder::MakeBuilder(
Event::PLAYBACK_POS_CHANGED, 0);
auto pkt = TestAvrcpPacket::Make();
request->Serialize(pkt);
SendMessage(1, pkt);
// Test the changed response for play position changed
auto changed_response =
RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(false,
0x5678);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(changed_response))))
.Times(1);
test_device->HandlePlayPosUpdate();
}
TEST_F(AvrcpDeviceTest, trackChangedBeforeInterimTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
// Pretend the device is active
EXPECT_CALL(a2dp_interface, active_peer())
.WillRepeatedly(Return(test_device->GetAddress()));
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};
MediaInterface::NowPlayingCallback interim_cb;
MediaInterface::NowPlayingCallback changed_cb;
EXPECT_CALL(interface, GetNowPlayingList(_))
.Times(2)
.WillOnce(SaveArg<0>(&interim_cb))
.WillOnce(SaveArg<0>(&changed_cb));
// Test that the changed response doesn't get sent before the interim
::testing::InSequence s;
auto interim_response =
RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(true, 0x01);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(interim_response))))
.Times(1);
auto changed_response =
RegisterNotificationResponseBuilder::MakeTrackChangedBuilder(false, 0x01);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(changed_response))))
.Times(1);
// Register for the update, sets interim_cb
auto request =
RegisterNotificationRequestBuilder::MakeBuilder(Event::TRACK_CHANGED, 0);
auto pkt = TestAvrcpPacket::Make();
request->Serialize(pkt);
SendMessage(1, pkt);
// Try to send track changed update, should fail and do nothing
test_device->HandleTrackUpdate();
// Send the interim response
interim_cb.Run("test_id", list);
// Try to send track changed update, should succeed
test_device->HandleTrackUpdate();
changed_cb.Run("test_id", list);
}
TEST_F(AvrcpDeviceTest, playStatusChangedBeforeInterimTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
// Pretend the device is active
EXPECT_CALL(a2dp_interface, active_peer())
.WillRepeatedly(Return(test_device->GetAddress()));
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
MediaInterface::PlayStatusCallback interim_cb;
MediaInterface::PlayStatusCallback changed_cb;
EXPECT_CALL(interface, GetPlayStatus(_))
.Times(2)
.WillOnce(SaveArg<0>(&interim_cb))
.WillOnce(SaveArg<0>(&changed_cb));
// Test that the changed response doesn't get sent before the interim
::testing::InSequence s;
auto interim_response =
RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
true, PlayState::PLAYING);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(interim_response))))
.Times(1);
auto changed_response =
RegisterNotificationResponseBuilder::MakePlaybackStatusBuilder(
false, PlayState::STOPPED);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(changed_response))))
.Times(1);
// Send the registration packet
auto request = RegisterNotificationRequestBuilder::MakeBuilder(
Event::PLAYBACK_STATUS_CHANGED, 0);
auto pkt = TestAvrcpPacket::Make();
request->Serialize(pkt);
SendMessage(1, pkt);
// Send a play status update, should be ignored since the interim response
// hasn't been sent yet.
test_device->HandlePlayStatusUpdate();
// Send the interim response.
PlayStatus status1 = {0x1234, 0x5678, PlayState::PLAYING};
interim_cb.Run(status1);
// Send the changed response, should succeed this time
test_device->HandlePlayStatusUpdate();
PlayStatus status2 = {0x1234, 0x5678, PlayState::STOPPED};
changed_cb.Run(status2);
}
TEST_F(AvrcpDeviceTest, playPositionChangedBeforeInterimTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
// Pretend the device is active
EXPECT_CALL(a2dp_interface, active_peer())
.WillRepeatedly(Return(test_device->GetAddress()));
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
MediaInterface::PlayStatusCallback interim_cb;
MediaInterface::PlayStatusCallback changed_cb;
EXPECT_CALL(interface, GetPlayStatus(_))
.Times(2)
.WillOnce(SaveArg<0>(&interim_cb))
.WillOnce(SaveArg<0>(&changed_cb));
// Test that the changed response doesn't get sent before the interim
::testing::InSequence s;
auto interim_response =
RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(true,
0x1234);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(interim_response))))
.Times(1);
auto changed_response =
RegisterNotificationResponseBuilder::MakePlaybackPositionBuilder(false,
0x5678);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(changed_response))))
.Times(1);
// Send the registration packet
auto request = RegisterNotificationRequestBuilder::MakeBuilder(
Event::PLAYBACK_POS_CHANGED, 0);
auto pkt = TestAvrcpPacket::Make();
request->Serialize(pkt);
SendMessage(1, pkt);
// Send a play position update, should be ignored since the notification
// isn't registered since no interim response has been sent.
test_device->HandlePlayPosUpdate();
// Run the interim callback for GetPlayStatus which should be pointing to the
// GetPlayStatus call made by the update.
PlayStatus status1 = {0x1234, 0x5678, PlayState::PAUSED};
interim_cb.Run(status1);
// Send a play position update, this one should succeed.
test_device->HandlePlayPosUpdate();
PlayStatus status2 = {0x5678, 0x9ABC, PlayState::STOPPED};
changed_cb.Run(status2);
}
TEST_F(AvrcpDeviceTest, nowPlayingChangedBeforeInterim) {
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};
MediaInterface::NowPlayingCallback interim_cb;
MediaInterface::NowPlayingCallback changed_cb;
EXPECT_CALL(interface, GetNowPlayingList(_))
.Times(2)
.WillOnce(SaveArg<0>(&interim_cb))
.WillOnce(SaveArg<0>(&changed_cb));
// Test that the changed response doesn't get sent before the interim
::testing::InSequence s;
auto interim_response =
RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(true);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(interim_response))))
.Times(1);
auto changed_response =
RegisterNotificationResponseBuilder::MakeNowPlayingBuilder(false);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(changed_response))))
.Times(1);
// Send the registration packet
auto request = RegisterNotificationRequestBuilder::MakeBuilder(
Event::NOW_PLAYING_CONTENT_CHANGED, 0);
auto pkt = TestAvrcpPacket::Make();
request->Serialize(pkt);
SendMessage(1, pkt);
// Send now playing changed, should fail since the interim response hasn't
// been sent
test_device->HandleNowPlayingUpdate();
// Send the data needed for the interim response
interim_cb.Run("test_id", list);
// Send now playing changed, should succeed
test_device->HandleNowPlayingUpdate();
changed_cb.Run("test_id", list);
}
TEST_F(AvrcpDeviceTest, addressPlayerChangedBeforeInterim) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
MediaInterface::MediaListCallback interim_cb;
MediaInterface::MediaListCallback changed_cb;
EXPECT_CALL(interface, GetMediaPlayerList(_))
.Times(2)
.WillOnce(SaveArg<0>(&interim_cb))
.WillOnce(SaveArg<0>(&changed_cb));
// Test that the changed response doesn't get sent before the interim
::testing::InSequence s;
auto interim_response =
RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(true, 0,
0);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(interim_response))))
.Times(1);
auto changed_response =
RegisterNotificationResponseBuilder::MakeAddressedPlayerBuilder(false, 0,
0);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(changed_response))))
.Times(1);
// TODO (apanicke): Remove this expectation once b/110957802 is fixed and
// we don't try to reject notifications that aren't registered.
auto rejected_response = RejectBuilder::MakeBuilder(
CommandPdu::REGISTER_NOTIFICATION, Status::ADDRESSED_PLAYER_CHANGED);
EXPECT_CALL(response_cb,
Call(_, false, matchPacket(std::move(rejected_response))))
.Times(4);
// Send the registration packet
auto request = RegisterNotificationRequestBuilder::MakeBuilder(
Event::ADDRESSED_PLAYER_CHANGED, 0);
auto pkt = TestAvrcpPacket::Make();
request->Serialize(pkt);
SendMessage(1, pkt);
// Send addressed player update, should fail since the interim response
// hasn't been sent
test_device->HandleAddressedPlayerUpdate();
// Send the data needed for the interim response
MediaPlayerInfo info = {0, "Test Player", true};
std::vector<MediaPlayerInfo> list = {info};
interim_cb.Run(0, list);
// Send addressed player update, should succeed
test_device->HandleAddressedPlayerUpdate();
changed_cb.Run(0, list);
}
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() + FolderItem::kHeaderSize() + 5);
device.RegisterInterfaces(&interface, &a2dp_interface, nullptr);
FolderInfo info0 = {"test_id0", true, "Test Folder0"};
FolderInfo info1 = {"test_id1", true, "Test Folder1"};
FolderInfo info2 = {"test_id2", true, "Truncated folder"};
// Used to ensure that adding an item that would fit in the MTU fails if
// adding a large item failed.
FolderInfo small_info = {"test_id2", true, "Small"};
ListItem item0 = {ListItem::FOLDER, info0, SongInfo()};
ListItem item1 = {ListItem::FOLDER, info1, SongInfo()};
ListItem item2 = {ListItem::FOLDER, info2, SongInfo()};
ListItem item3 = {ListItem::FOLDER, small_info, SongInfo()};
std::vector<ListItem> list0 = {item0, item1, item2, item3};
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);
MediaPlayerInfo info = {0, "Test Player", true};
std::vector<MediaPlayerInfo> list = {info};
EXPECT_CALL(interface, GetMediaPlayerList(_))
.WillRepeatedly(InvokeCb<0>(0, list));
auto set_addr_player_rej_rsp = RejectBuilder::MakeBuilder(
CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PLAYER_ID);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(set_addr_player_rej_rsp))))
.Times(1);
auto player_id_1_request =
TestAvrcpPacket::Make(set_addressed_player_id_1_request);
SendMessage(1, player_id_1_request);
auto set_addr_player_rsp =
SetAddressedPlayerResponseBuilder::MakeBuilder(Status::NO_ERROR);
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);
}
TEST_F(AvrcpDeviceTest, invalidRegisterNotificationTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto reg_notif_rej_rsp = RejectBuilder::MakeBuilder(
CommandPdu::REGISTER_NOTIFICATION, Status::INVALID_PARAMETER);
EXPECT_CALL(response_cb,
Call(1, false, matchPacket(std::move(reg_notif_rej_rsp))))
.Times(1);
auto reg_notif_request = TestAvrcpPacket::Make(register_notification_invalid);
SendMessage(1, reg_notif_request);
}
TEST_F(AvrcpDeviceTest, invalidVendorPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = RejectBuilder::MakeBuilder(static_cast<CommandPdu>(0), Status::INVALID_COMMAND);
EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestAvrcpPacket::Make(short_vendor_packet);
SendMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidCapabilitiesPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = RejectBuilder::MakeBuilder(CommandPdu::GET_CAPABILITIES, Status::INVALID_PARAMETER);
EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestAvrcpPacket::Make(short_get_capabilities_request);
SendMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidGetElementAttributesPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = RejectBuilder::MakeBuilder(CommandPdu::GET_ELEMENT_ATTRIBUTES, Status::INVALID_PARAMETER);
EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestAvrcpPacket::Make(short_get_element_attributes_request);
SendMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidPlayItemPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = RejectBuilder::MakeBuilder(CommandPdu::PLAY_ITEM, Status::INVALID_PARAMETER);
EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestAvrcpPacket::Make(short_play_item_request);
SendMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidSetAddressedPlayerPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = RejectBuilder::MakeBuilder(CommandPdu::SET_ADDRESSED_PLAYER, Status::INVALID_PARAMETER);
EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestAvrcpPacket::Make(short_set_addressed_player_request);
SendMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidBrowsePacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = GeneralRejectBuilder::MakeBuilder(Status::INVALID_COMMAND);
EXPECT_CALL(response_cb, Call(1, false, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestBrowsePacket::Make(short_browse_packet);
SendBrowseMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidGetFolderItemsPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = GetFolderItemsResponseBuilder::MakePlayerListBuilder(Status::INVALID_PARAMETER, 0x0000, 0xFFFF);
EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestBrowsePacket::Make(short_get_folder_items_request);
SendBrowseMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidGetTotalNumberOfItemsPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = GetTotalNumberOfItemsResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0x0000, 0xFFFF);
EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestBrowsePacket::Make(short_get_total_number_of_items_request);
SendBrowseMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidChangePathPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = ChangePathResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0);
EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestBrowsePacket::Make(short_change_path_request);
SendBrowseMessage(1, short_packet);
}
TEST_F(AvrcpDeviceTest, invalidGetItemAttributesPacketTest) {
MockMediaInterface interface;
NiceMock<MockA2dpInterface> a2dp_interface;
test_device->RegisterInterfaces(&interface, &a2dp_interface, nullptr);
auto rsp = GetItemAttributesResponseBuilder::MakeBuilder(Status::INVALID_PARAMETER, 0xFFFF);
EXPECT_CALL(response_cb, Call(1, true, matchPacket(std::move(rsp)))).Times(1);
auto short_packet = TestBrowsePacket::Make(short_get_item_attributes_request);
SendBrowseMessage(1, short_packet);
}
} // namespace avrcp
} // namespace bluetooth
const stack_config_t* stack_config_get_interface(void) {
return &bluetooth::avrcp::interface;
}