/* * 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 #include #include #include #include #include #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 caption_manager; /// Mock player with which to exercise CaptionManager. std::shared_ptr m_player; /// Mock parser with which to exercise CaptionManager. std::shared_ptr m_parser; /// Mock presenter with which to exercise CaptionManager. std::shared_ptr> m_presenter; /// An implementation of the timing adapter factory with which to exercise CaptionManager, which returns mocks. std::shared_ptr m_timingFactory; }; void CaptionManagerTest::SetUp() { avsCommon::utils::logger::getConsoleLogger()->setLevel(avsCommon::utils::logger::Level::DEBUG9); m_player = MockMediaPlayer::create(); m_parser = std::make_shared>(); m_presenter = std::make_shared>(); m_timingFactory = std::make_shared(); 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 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(false, 0))); std::vector 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 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(false, 0))); std::vector 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 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(true, 20))) .WillOnce(Return(std::pair(false, 0))); std::vector 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 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(true, 9))) .WillOnce(Return(std::pair(true, 9))) .WillOnce(Return(std::pair(false, 0))); std::vector 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 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(false, 0))); std::vector 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 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(true, 12))) .WillOnce(Return(std::pair(false, 0))); EXPECT_CALL(*mockTimingAdapter, queueForDisplay(expectedCaptionFrame, _)).Times(1); std::vector 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