371 lines
14 KiB
C++
371 lines
14 KiB
C++
/*
|
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
|
* You may not use this file except in compliance with the License.
|
|
* A copy of the License is located at
|
|
*
|
|
* http://aws.amazon.com/apache2.0/
|
|
*
|
|
* or in the "license" file accompanying this file. This file 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.
|
|
*/
|
|
|
|
/// @file CaptionManagerTest.cpp
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <gmock/gmock.h>
|
|
|
|
#include <AVSCommon/Utils/Logger/Logger.h>
|
|
#include <AVSCommon/Utils/MediaPlayer/MockMediaPlayer.h>
|
|
#include <Captions/CaptionManager.h>
|
|
#include <Captions/CaptionLine.h>
|
|
|
|
#include "MockCaptionParser.h"
|
|
#include "MockCaptionPresenter.h"
|
|
#include "TestTimingAdapterFactory.cpp"
|
|
|
|
namespace alexaClientSDK {
|
|
namespace captions {
|
|
namespace test {
|
|
|
|
using namespace ::testing;
|
|
using namespace avsCommon;
|
|
using namespace avsCommon::avs;
|
|
using namespace avsCommon::utils;
|
|
using namespace avsCommon::utils::mediaPlayer;
|
|
using namespace avsCommon::utils::mediaPlayer::test;
|
|
|
|
/**
|
|
* Test rig.
|
|
*/
|
|
class CaptionManagerTest : public ::testing::Test {
|
|
public:
|
|
void SetUp() override;
|
|
|
|
void TearDown() override;
|
|
|
|
/// The system under test.
|
|
std::shared_ptr<CaptionManager> caption_manager;
|
|
|
|
/// Mock player with which to exercise CaptionManager.
|
|
std::shared_ptr<MockMediaPlayer> m_player;
|
|
|
|
/// Mock parser with which to exercise CaptionManager.
|
|
std::shared_ptr<MockCaptionParser> m_parser;
|
|
|
|
/// Mock presenter with which to exercise CaptionManager.
|
|
std::shared_ptr<NiceMock<MockCaptionPresenter>> m_presenter;
|
|
|
|
/// An implementation of the timing adapter factory with which to exercise CaptionManager, which returns mocks.
|
|
std::shared_ptr<TestTimingAdapterFactory> m_timingFactory;
|
|
};
|
|
|
|
void CaptionManagerTest::SetUp() {
|
|
avsCommon::utils::logger::getConsoleLogger()->setLevel(avsCommon::utils::logger::Level::DEBUG9);
|
|
|
|
m_player = MockMediaPlayer::create();
|
|
|
|
m_parser = std::make_shared<NiceMock<MockCaptionParser>>();
|
|
|
|
m_presenter = std::make_shared<NiceMock<MockCaptionPresenter>>();
|
|
|
|
m_timingFactory = std::make_shared<TestTimingAdapterFactory>();
|
|
|
|
caption_manager = CaptionManager::create(m_parser, m_timingFactory);
|
|
|
|
caption_manager->addMediaPlayer(m_player);
|
|
|
|
caption_manager->setCaptionPresenter(m_presenter);
|
|
}
|
|
|
|
void CaptionManagerTest::TearDown() {
|
|
if (m_player) {
|
|
m_player->shutdown();
|
|
}
|
|
if (caption_manager) {
|
|
caption_manager->shutdown();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sanity test to ensure the TestTimingAdapterFactory is returning the expected result.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_testTestTimingAdapterFactory) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
ASSERT_EQ(mockTimingAdapter, m_timingFactory->getTimingAdapter(nullptr));
|
|
}
|
|
|
|
/**
|
|
* Test that CaptionManager::setMediaPlayers() adds a media player that is bound to media events.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_testSetMediaPlayerBindsMediaPlayer) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
auto sourceID1 = m_player->setSource("http://fake.url", std::chrono::milliseconds(0));
|
|
|
|
// CaptionManager::setMediaPlayers() has already been called in CaptionManagerTest::SetUp().
|
|
// in order to check this, the timing adapter needs to be pre-loaded.
|
|
caption_manager->onParsed(CaptionFrame(sourceID1));
|
|
|
|
EXPECT_CALL(*mockTimingAdapter, pause()).Times(1);
|
|
|
|
// trigger the finished event from the media player
|
|
m_player->mockPause(sourceID1);
|
|
}
|
|
|
|
/**
|
|
* Test that create fails with null arguments
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_createWithNullArgs) {
|
|
auto manager = CaptionManager::create(nullptr, nullptr);
|
|
ASSERT_FALSE(manager);
|
|
}
|
|
|
|
/**
|
|
* Test that create succeeds with a null TimingAdapterFactory.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_createWithNullTimingAdapterFactory) {
|
|
auto manager = CaptionManager::create(m_parser, nullptr);
|
|
ASSERT_NE(nullptr, manager);
|
|
}
|
|
|
|
/**
|
|
* Test that create fails with a null Parser.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_createWithNullParser) {
|
|
auto manager = CaptionManager::create(nullptr, m_timingFactory);
|
|
ASSERT_FALSE(manager);
|
|
}
|
|
|
|
/**
|
|
* Test that the source ID is maintained from onParsed() to queueForDisplay().
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_sourceIdDoesNotChange) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
int sourceID1 = 1;
|
|
|
|
auto expectedCaptionFrame = CaptionFrame(sourceID1);
|
|
EXPECT_CALL(*mockTimingAdapter.get(), queueForDisplay(expectedCaptionFrame, _)).Times(1);
|
|
|
|
caption_manager->onParsed(CaptionFrame(sourceID1));
|
|
}
|
|
|
|
/**
|
|
* Test the media focus behavior for a single media player instance.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_singleMediaPlayerPause) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
std::vector<CaptionLine> expectedLines;
|
|
CaptionLine expectedLine1 = CaptionLine("The time is 2:17 PM.", {TextStyle()});
|
|
expectedLines.emplace_back(expectedLine1);
|
|
auto expectedCaptionFrame =
|
|
CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), expectedLines);
|
|
EXPECT_CALL(*mockTimingAdapter.get(), queueForDisplay(expectedCaptionFrame, _)).Times(1);
|
|
EXPECT_CALL(*m_presenter, getWrapIndex(_)).Times(1).WillOnce(Return(std::pair<bool, uint32_t>(false, 0)));
|
|
|
|
std::vector<CaptionLine> lines;
|
|
CaptionLine line = CaptionLine("The time is 2:17 PM.", {});
|
|
lines.emplace_back(line);
|
|
auto captionFrame = CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), lines);
|
|
caption_manager->onParsed(captionFrame);
|
|
}
|
|
|
|
/**
|
|
* Tests the splitting behavior when the caption is all spaces.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_splitCaptionFrameWhitespaceOnly) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
std::vector<CaptionLine> expectedLines;
|
|
CaptionLine expectedLine1 = CaptionLine(" ", {TextStyle()});
|
|
expectedLines.emplace_back(expectedLine1);
|
|
auto expectedCaptionFrame =
|
|
CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), expectedLines);
|
|
EXPECT_CALL(*mockTimingAdapter, queueForDisplay(expectedCaptionFrame, _)).Times(1);
|
|
EXPECT_CALL(*m_presenter, getWrapIndex(_)).Times(1).WillOnce(Return(std::pair<bool, uint32_t>(false, 0)));
|
|
|
|
std::vector<CaptionLine> lines;
|
|
CaptionLine line = CaptionLine(" ", {});
|
|
lines.emplace_back(line);
|
|
auto captionFrame = CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), lines);
|
|
caption_manager->onParsed(captionFrame);
|
|
}
|
|
|
|
/**
|
|
* Tests the splitting behavior when the caption is all spaces after a line wrap.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_splitCaptionFrameWhitespaceAfterLineWrap) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
std::vector<CaptionLine> expectedLines;
|
|
CaptionLine expectedLine1 = CaptionLine("The time is 2:17 PM.", {TextStyle()});
|
|
expectedLines.emplace_back(expectedLine1);
|
|
auto expectedCaptionFrame =
|
|
CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), expectedLines);
|
|
EXPECT_CALL(*mockTimingAdapter, queueForDisplay(expectedCaptionFrame, _)).Times(1);
|
|
EXPECT_CALL(*m_presenter, getWrapIndex(_))
|
|
.Times(2)
|
|
.WillOnce(Return(std::pair<bool, uint32_t>(true, 20)))
|
|
.WillOnce(Return(std::pair<bool, uint32_t>(false, 0)));
|
|
std::vector<CaptionLine> lines;
|
|
CaptionLine line = CaptionLine("The time is 2:17 PM. ", {});
|
|
lines.emplace_back(line);
|
|
auto captionFrame = CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), lines);
|
|
caption_manager->onParsed(captionFrame);
|
|
}
|
|
|
|
/**
|
|
* Tests the splitting behavior when the a no whitespace is present at before the requested wrap index.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_splitCaptionFrameNoWhitespaceBeforeWrapIndex) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
std::vector<CaptionLine> expectedLines;
|
|
CaptionLine expectedLine1 = CaptionLine("Thiscapti", {TextStyle()});
|
|
CaptionLine expectedLine2 = CaptionLine("onhasnosp", {TextStyle()});
|
|
CaptionLine expectedLine3 = CaptionLine("aces", {TextStyle()});
|
|
expectedLines.emplace_back(expectedLine1);
|
|
expectedLines.emplace_back(expectedLine2);
|
|
expectedLines.emplace_back(expectedLine3);
|
|
auto expectedCaptionFrame =
|
|
CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), expectedLines);
|
|
EXPECT_CALL(*mockTimingAdapter, queueForDisplay(expectedCaptionFrame, _)).Times(1);
|
|
EXPECT_CALL(*m_presenter, getWrapIndex(_))
|
|
.Times(3)
|
|
.WillOnce(Return(std::pair<bool, uint32_t>(true, 9)))
|
|
.WillOnce(Return(std::pair<bool, uint32_t>(true, 9)))
|
|
.WillOnce(Return(std::pair<bool, uint32_t>(false, 0)));
|
|
std::vector<CaptionLine> lines;
|
|
CaptionLine line = CaptionLine("Thiscaptionhasnospaces", {});
|
|
lines.emplace_back(line);
|
|
auto captionFrame = CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), lines);
|
|
caption_manager->onParsed(captionFrame);
|
|
}
|
|
|
|
/**
|
|
* Tests the splitting behavior when no split is needed.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_splitCaptionFrameFalseWillNotSplitLine) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
std::vector<CaptionLine> expectedLines;
|
|
CaptionLine expectedLine1 = CaptionLine("The time is 2:17 PM.", {TextStyle()});
|
|
expectedLines.emplace_back(expectedLine1);
|
|
auto expectedCaptionFrame =
|
|
CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), expectedLines);
|
|
EXPECT_CALL(*mockTimingAdapter, queueForDisplay(expectedCaptionFrame, _)).Times(1);
|
|
EXPECT_CALL(*m_presenter, getWrapIndex(_)).Times(1).WillOnce(Return(std::pair<bool, uint32_t>(false, 0)));
|
|
|
|
std::vector<CaptionLine> lines;
|
|
CaptionLine line = CaptionLine("The time is 2:17 PM.", {});
|
|
lines.emplace_back(line);
|
|
auto captionFrame = CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), lines);
|
|
caption_manager->onParsed(captionFrame);
|
|
}
|
|
|
|
/**
|
|
* Tests the splitting of a caption frame at a character index that happens to fall on a space character ('0x20').
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_splitCaptionFrameAtSpaceIndex) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
std::vector<CaptionLine> expectedLines;
|
|
|
|
CaptionLine expectedLine1 = CaptionLine("The time is", {TextStyle()});
|
|
CaptionLine expectedLine2 = CaptionLine("2:17 PM.", {TextStyle()});
|
|
expectedLines.emplace_back(expectedLine1);
|
|
expectedLines.emplace_back(expectedLine2);
|
|
auto expectedCaptionFrame =
|
|
CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), expectedLines);
|
|
EXPECT_CALL(*m_presenter, getWrapIndex(_))
|
|
.Times(2)
|
|
.WillOnce(Return(std::pair<bool, uint32_t>(true, 12)))
|
|
.WillOnce(Return(std::pair<bool, uint32_t>(false, 0)));
|
|
EXPECT_CALL(*mockTimingAdapter, queueForDisplay(expectedCaptionFrame, _)).Times(1);
|
|
|
|
std::vector<CaptionLine> lines;
|
|
CaptionLine line1 = CaptionLine("The time is 2:17 PM.", {});
|
|
lines.emplace_back(line1);
|
|
auto captionFrame = CaptionFrame(1, std::chrono::milliseconds(1), std::chrono::milliseconds(0), lines);
|
|
caption_manager->onParsed(captionFrame);
|
|
}
|
|
|
|
/**
|
|
* Test that CaptionManager::addMediaPlayer() does not add the same media player twice.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_testAddDuplicateMediaPlayerFails) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
|
|
EXPECT_CALL(*mockTimingAdapter, pause()).Times(1);
|
|
|
|
// Re-add the player added in Setup() (a duplicate add).
|
|
caption_manager->addMediaPlayer(m_player);
|
|
|
|
// test that the media player is still bound
|
|
auto sourceID2 = m_player->setSource("http://fake.url.com", std::chrono::milliseconds(0));
|
|
|
|
caption_manager->onParsed(CaptionFrame(sourceID2));
|
|
|
|
// trigger the finished event from the media player
|
|
m_player->mockPause(sourceID2);
|
|
}
|
|
|
|
/**
|
|
* Test that CaptionManager::addMediaPlayer() adds a media player that is bound to media events.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_testAddMediaPlayerBindsMediaPlayer) {
|
|
auto playerToAdd = MockMediaPlayer::create();
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
auto sourceID1 = playerToAdd->setSource("http://fake.url", std::chrono::milliseconds(0));
|
|
|
|
EXPECT_CALL(*mockTimingAdapter, pause()).Times(2);
|
|
|
|
caption_manager->addMediaPlayer(playerToAdd);
|
|
|
|
// in order to check this, the timing adapter needs to be pre-loaded.
|
|
caption_manager->onParsed(CaptionFrame(sourceID1));
|
|
|
|
// trigger the finished event from the media player
|
|
playerToAdd->mockPause(sourceID1);
|
|
|
|
// test that the other media players are also still bound
|
|
auto sourceID2 = m_player->setSource("http://fake.url.com", std::chrono::milliseconds(0));
|
|
|
|
caption_manager->onParsed(CaptionFrame(sourceID2));
|
|
|
|
// trigger the finished event from the media player
|
|
m_player->mockPause(sourceID2);
|
|
}
|
|
|
|
/**
|
|
* Test that CaptionManager::removeMediaPlayer() removes a media player bound to media events.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_testRemoveMediaPlayerUnbindsMediaPlayer) {
|
|
auto mockTimingAdapter = m_timingFactory->getMockTimingAdapter();
|
|
auto sourceID1 = m_player->setSource("http://fake.url", std::chrono::milliseconds(0));
|
|
|
|
caption_manager->removeMediaPlayer(m_player);
|
|
|
|
// in order to check this, the timing adapter needs to be pre-loaded.
|
|
caption_manager->onParsed(CaptionFrame(sourceID1));
|
|
|
|
// no calls expected now that the media player was removed
|
|
EXPECT_CALL(*mockTimingAdapter, pause()).Times(0);
|
|
|
|
// trigger the finished event from the media player
|
|
m_player->mockPause(sourceID1);
|
|
}
|
|
|
|
/**
|
|
* Tests that the caption manager is enabled after construction when
|
|
* captions are enabled.
|
|
*/
|
|
TEST_F(CaptionManagerTest, test_isEnabled) {
|
|
#ifdef ENABLE_CAPTIONS
|
|
ASSERT_TRUE(caption_manager->isEnabled());
|
|
#else
|
|
ASSERT_FALSE(caption_manager->isEnabled());
|
|
#endif
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace captions
|
|
} // namespace alexaClientSDK
|