JD2022-TU1/main/unittests/engine/musicband/Brick.cpp

1159 lines
No EOL
50 KiB
C++

// ----------------------------------------------------------------------------
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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<ConductorBrickMock>* brickInstance = new ::testing::StrictMock<ConductorBrickMock>();
// 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