// ---------------------------------------------------------------------------- // Unit test for the class engine/musicband/Brick // ---------------------------------------------------------------------------- #include "precompiled_unittests_engine.h" #include "engine/musicband/Brick.h" #include "musicband/ConductorBrickMock.h" using ::testing::Return; using ::testing::AnyNumber; using ::testing::_; namespace ITF { class Brick_PrivateMembersAccessor { public: Brick_PrivateMembersAccessor(const Brick& _source) : m_source(_source) {} MusicScoreType getMusicScoreType() const { return m_source.m_score; } FBeat computeLocalTime(const MusicScoreTime &_time) const { return m_source.computeLocalTime(_time); } bool isActiveAt(const FBeat _localTime) const { return m_source.isActiveAt(_localTime); } bool isStartedAt(const FBeat _localTime) const { return m_source.isStartedAt(_localTime); } private: const Brick& m_source; }; ITF_ASSERT_STATIC(Brick::BrickState_Count == 9, "New state added, please check and update unit tests"); // test state of the class after the construction TEST(Brick, test_Construction) { // arrange BrickDescriptor expectedBrickDescriptor; MusicScoreType expectedMusicScoreType(MusicScoreType_Menu); Brick::BrickState expectedState(Brick::BrickState_NotCreated); ConductorBrick* brickInstance = new ConductorBrickMock(); // act Brick brick(expectedBrickDescriptor, expectedMusicScoreType, brickInstance); Brick_PrivateMembersAccessor testMemberAccessor(brick); // assert EXPECT_EQ(expectedBrickDescriptor, brick.getDescriptor()); EXPECT_EQ(expectedMusicScoreType, testMemberAccessor.getMusicScoreType()); EXPECT_EQ(expectedState, brick.getState()); EXPECT_TRUE(brick.containsConductorBrick(brickInstance)); EXPECT_FALSE(brick.isDestroyable()); } // Test internal function computeLocalTime TEST(Brick, test_computeLocalTime) { BrickDescriptor brickDescriptor; brickDescriptor.m_absoluteStartBeat = 4; // starts at beat 4 in conductor time brickDescriptor.m_localStartBeat = 2; // starts at beat 2 in song time brickDescriptor.m_duration = 5; // brick duration is 5 beats MusicScoreTime t; t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(3.f); // current metronome beat time // Absolute Beat: 01234567890123 // Music time: -----MMMMMMMMM // music time starts at absolute beat 5 // Brick time: ----BBBBB----- // brick (absolute) time starts at beat 4 // Brick local beat: --012345678901 // brick will play beat 2 content at conductor time 4 // Current time: -----A--o----- // A - absolute start beat, o - reference local beat // Brick local time: --------6----- FBeat expectedLocalTime(6.0f); // act / assert Brick brick(brickDescriptor, MusicScoreType_Menu, nullptr); Brick_PrivateMembersAccessor privateMembersAccessor(brick); EXPECT_EQ(expectedLocalTime.toFloat(), privateMembersAccessor.computeLocalTime(t).toFloat()); } // Test internal function isActive // uses the following timing setup: // Absolute Beat: 01234567890123 // Music time: -----MMMMMMMMM // music time starts at absolute beat 5 // Brick time: ----BBBBB----- // brick (absolute) time starts at beat 4 // Brick local beat: --012345678901 // brick will play beat 2 content at conductor time 4 TEST(Brick, test_isActive) { BrickDescriptor brickDescriptor; brickDescriptor.m_absoluteStartBeat = IBeat(4); // starts at beat 4 in conductor time brickDescriptor.m_localStartBeat = IBeat(2); // starts at beat 2 in song time brickDescriptor.m_duration = IBeat(5); // brick duration is 5 beats brickDescriptor.m_prefetchDuration = IBeat(2); // prefetch will be started 2 beats before start (beat 2 in conductor time) // discard will be started 2 beats after end (beat 11 in conductor time) MusicScoreTime t; FBeat localBrickTime; Brick brick(brickDescriptor, MusicScoreType_Menu, nullptr); Brick_PrivateMembersAccessor privateMembersAccessor(brick); // Absolute beat time = 1, expected => inactive t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(-4.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isActiveAt(localBrickTime)); // Absolute beat time = 2, expected => active t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(-3.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_TRUE(privateMembersAccessor.isActiveAt(localBrickTime)); // Absolute beat time = 4, expected => active t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(-1.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_TRUE(privateMembersAccessor.isActiveAt(localBrickTime)); // Absolute beat time = 8, expected => active t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(3.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_TRUE(privateMembersAccessor.isActiveAt(localBrickTime)); // Absolute beat time = 10, expected => active t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(5.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_TRUE(privateMembersAccessor.isActiveAt(localBrickTime)); // Absolute beat time = 11, expected => inactive t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(6.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isActiveAt(localBrickTime)); } // Test internal function isStarted // uses the following timing setup: // Absolute Beat: 01234567890123 // Music time: -----MMMMMMMMM // music time starts at absolute beat 5 // Brick time: ----BBBBB----- // brick (absolute) time starts at beat 4 // Brick local beat: --012345678901 // brick will play beat 2 content at conductor time 4 TEST(Brick, test_isStarted) { BrickDescriptor brickDescriptor; brickDescriptor.m_absoluteStartBeat = 4; // starts at beat 4 in conductor time brickDescriptor.m_localStartBeat = 2; // starts at beat 2 in song time brickDescriptor.m_duration = 5; // brick duration is 5 beats brickDescriptor.m_prefetchDuration = 2; // prefetch will be started 2 beats before start (beat 2 in conductor time) // discard will be started 2 beats after end (beat 11 in conductor time) MusicScoreTime t; FBeat localBrickTime; Brick brick(brickDescriptor, MusicScoreType_Menu, nullptr); Brick_PrivateMembersAccessor privateMembersAccessor(brick); // Absolute beat time = 1, expected => not started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(-4.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isStartedAt(localBrickTime)); // Absolute beat time = 2, expected => not started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(-3.f); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isStartedAt(localBrickTime)); // Absolute beat time = 3, expected => not started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(-2); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isStartedAt(localBrickTime)); // Absolute beat time = 4, expected => started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(-1); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_TRUE(privateMembersAccessor.isStartedAt(localBrickTime)); // Absolute beat time = 8, expected => started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(3); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_TRUE(privateMembersAccessor.isStartedAt(localBrickTime)); // Absolute beat time = 9, expected => not started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(4); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isStartedAt(localBrickTime)); // Absolute beat time = 10, expected => not started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(5); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isStartedAt(localBrickTime)); // Absolute beat time = 11, expected => not started t.m_referenceAbsoluteStartBeat = IBeat(5); // local beat time starts at this offset in conductor time t.m_referenceLocalBeat = FBeat(6); // current metronome beat time localBrickTime = privateMembersAccessor.computeLocalTime(t); EXPECT_FALSE(privateMembersAccessor.isStartedAt(localBrickTime)); } // Test 'cancel prepare' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Canceling -> NotCreated TEST(Brick, test_CancelPrepareScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Canceling EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, allowCancel()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, cancelBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Canceling, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Canceling -> NotCreated EXPECT_CALL(*brickInstance, isBrickCanceled()).Times(1).WillRepeatedly(Return(true)); brick.update(t); EXPECT_EQ(Brick::BrickState_NotCreated, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); } // Test 'cancel prepare' scenario for the brick which cannot cancel // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Discarding -> NotCreated TEST(Brick, test_CancelPrepareScenario_CancelNotAllowed) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Try Canceling => Fails EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, allowCancel()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Discarding EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Discarding -> NotCreated EXPECT_CALL(*brickInstance, isBrickDiscarded()).Times(1).WillRepeatedly(Return(true)); brick.update(t); EXPECT_EQ(Brick::BrickState_NotCreated, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); } // Test 'Discard Ready' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Discarding -> NotCreated TEST(Brick, test_DiscardReadyScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Discarding EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Discarding -> NotCreated EXPECT_CALL(*brickInstance, isBrickDiscarded()).Times(1).WillRepeatedly(Return(true)); brick.update(t); EXPECT_EQ(Brick::BrickState_NotCreated, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); } // Test 'Discard Started' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Ready -> Discarding -> NotCreated TEST(Brick, test_DiscardStartedScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 4; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Ready EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, stopBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Discarding EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Discarding -> NotCreated EXPECT_CALL(*brickInstance, isBrickDiscarded()).Times(1).WillRepeatedly(Return(true)); brick.update(t); EXPECT_EQ(Brick::BrickState_NotCreated, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); } // Test 'Seek started brick' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Seeking -> Started TEST(Brick, test_SeekInStartedBrickScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Seeking EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, seekBrick(_)).Times(1); EXPECT_CALL(*brickInstance, isBrickSeekFinished()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); t.m_referenceLocalBeat = FBeat(5); brick.seek(t); EXPECT_EQ(Brick::BrickState_Seeking, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Seeking -> Started EXPECT_CALL(*brickInstance, isBrickSeekFinished()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Seek started brick to discard' scenario // (seek to time where the brick is not started anymore) // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Ready -> Discarding TEST(Brick, test_SeekInStartedBrickToDiscardScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Ready EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, stopBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); t.m_referenceLocalBeat = FBeat(13); brick.seek(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Discarding EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Seek ready brick' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Discarding (-> Preparing -> Ready) TEST(Brick, test_SeekInReadyBrickScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Discarding (on seek) EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, isBrickDiscarded()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); t.m_referenceLocalBeat = FBeat(6); brick.seek(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Seek preparing cancelable brick' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Canceling (-> Preparing -> Ready) TEST(Brick, test_SeekInPreparingBrickScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Canceling (on seek) EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, allowCancel()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, cancelBrick()).Times(1); EXPECT_CALL(*brickInstance, isBrickCanceled()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); t.m_referenceLocalBeat = FBeat(6); brick.seek(t); EXPECT_EQ(Brick::BrickState_Canceling, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Error during Preparing' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Error -> Discarding (-> NotCreated) TEST(Brick, test_ErrorDuringPreparingScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Error EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, brickHasError()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Error, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Error -> Discarding EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Error while Ready' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Error -> Discarding (-> NotCreated) TEST(Brick, test_ErrorWhileReadyScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Error EXPECT_CALL(*brickInstance, brickHasError()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Error, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Error -> Discarding EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Error while Started' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Error -> Discarding (-> NotCreated) TEST(Brick, test_ErrorWhileStartedScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Error EXPECT_CALL(*brickInstance, brickHasError()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Error, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Error -> Discarding EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Error while Seeking' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Seeking -> Error -> Discarding (-> NotCreated) TEST(Brick, test_ErrorWhileSeekingScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Seeking EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, seekBrick(_)).Times(1); EXPECT_CALL(*brickInstance, isBrickSeekFinished()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); t.m_referenceLocalBeat = FBeat(5); brick.seek(t); EXPECT_EQ(Brick::BrickState_Seeking, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Seeking -> Error EXPECT_CALL(*brickInstance, isBrickSeekFinished()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, brickHasError()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Error, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Error -> Discarding EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Error at Seek' scenario // (error detected when the seek command is issued) // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Error -> Discarding (-> NotCreated) TEST(Brick, test_ErrorAtSeekScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Error EXPECT_CALL(*brickInstance, brickHasError()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); t.m_referenceLocalBeat = FBeat(5); brick.seek(t); EXPECT_EQ(Brick::BrickState_Error, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Error -> Discarding EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Starving' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Starving -> Started (-> ...) TEST(Brick, test_StarvingScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Starving EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, isBrickStarving()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Starving, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Starving -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, isBrickStarving()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Discard Starving' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Starving -> Started -> Ready -> Discarding -> NotCreated TEST(Brick, test_DiscardStarvingScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Starving EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, isBrickStarving()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Starving, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Starving -> Started (because disabled) EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Ready EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, stopBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Discarding EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Discarding -> NotCreated EXPECT_CALL(*brickInstance, isBrickDiscarded()).Times(1).WillRepeatedly(Return(true)); brick.update(t); EXPECT_EQ(Brick::BrickState_NotCreated, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); } // Test 'Seek Starving brick' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Starving -> Seeking -> Started TEST(Brick, test_SeekInStarvingBrickScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Starving EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, isBrickStarving()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Starving, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Starving -> Seeking EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, seekBrick(_)).Times(1); EXPECT_CALL(*brickInstance, isBrickSeekFinished()).Times(1).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); t.m_referenceLocalBeat = FBeat(5); brick.seek(t); EXPECT_EQ(Brick::BrickState_Seeking, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Seeking -> Started EXPECT_CALL(*brickInstance, isBrickSeekFinished()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } // Test 'Error while Starving' scenario // The brick should pass through the following states: // NotCreated -> Preparing -> Ready -> Started -> Starving -> Error -> Discarding (-> NotCreated) TEST(Brick, test_ErrorWhileStarvingScenario) { // arrange BrickDescriptor brickDescriptor; brickDescriptor.m_localStartBeat = 2; brickDescriptor.m_prefetchDuration = 2; brickDescriptor.m_duration = 10; MusicScoreType musicScoreType(MusicScoreType_Menu); ::testing::StrictMock* brickInstance = new ::testing::StrictMock(); // act / assert MusicScoreTime t; Brick brick(brickDescriptor, musicScoreType, brickInstance); // NotCreated -> Preparing EXPECT_CALL(*brickInstance, prepareBrick(brickDescriptor, musicScoreType, &brick)).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Preparing, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Preparing -> Ready EXPECT_CALL(*brickInstance, isBrickReady()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Ready, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Ready -> Started EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, startBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Started, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Started -> Starving EXPECT_CALL(*brickInstance, brickHasError()).Times(AnyNumber()).WillRepeatedly(Return(false)); EXPECT_CALL(*brickInstance, isBrickStarving()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Starving, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Starving -> Error EXPECT_CALL(*brickInstance, brickHasError()).Times(1).WillRepeatedly(Return(true)); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.update(t); EXPECT_EQ(Brick::BrickState_Error, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // Error -> Discarding EXPECT_CALL(*brickInstance, discardBrick()).Times(1); EXPECT_CALL(*brickInstance, updateBrick(_)).Times(1); brick.disable(); brick.update(t); EXPECT_EQ(Brick::BrickState_Discarding, brick.getState()); ::testing::Mock::VerifyAndClear(brickInstance); // ignore the rest of the lifetime... } } // namespace ITF