mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-05 10:15:46 +00:00
Add next/previous/last functions and playback history recording.
This commit is contained in:
@ -34,6 +34,7 @@ bool Playlist::Empty() const
|
||||
|
||||
void Playlist::Clear()
|
||||
{
|
||||
m_presetHistory.clear();
|
||||
m_items.clear();
|
||||
}
|
||||
|
||||
@ -59,6 +60,7 @@ bool Playlist::AddItem(const std::string& filename, uint32_t index, bool allowDu
|
||||
}
|
||||
}
|
||||
|
||||
m_presetHistory.clear();
|
||||
if (index >= m_items.size())
|
||||
{
|
||||
m_items.emplace_back(filename);
|
||||
@ -76,6 +78,7 @@ auto Playlist::AddPath(const std::string& path, uint32_t index, bool recursive,
|
||||
{
|
||||
uint32_t presetsAdded{0};
|
||||
|
||||
m_presetHistory.clear();
|
||||
if (recursive)
|
||||
{
|
||||
for (const auto& entry : recursive_directory_iterator(path))
|
||||
@ -124,6 +127,7 @@ auto Playlist::RemoveItem(uint32_t index) -> bool
|
||||
return false;
|
||||
}
|
||||
|
||||
m_presetHistory.clear();
|
||||
m_items.erase(m_items.cbegin() + index);
|
||||
|
||||
return true;
|
||||
@ -145,6 +149,8 @@ auto Playlist::Shuffle() const -> bool
|
||||
void Playlist::Sort(uint32_t startIndex, uint32_t count,
|
||||
Playlist::SortPredicate predicate, Playlist::SortOrder order)
|
||||
{
|
||||
m_presetHistory.clear();
|
||||
|
||||
std::sort(m_items.begin() + startIndex,
|
||||
m_items.begin() + startIndex + count,
|
||||
[predicate, order](const Item& left, const Item& right) {
|
||||
@ -187,6 +193,8 @@ auto Playlist::NextPresetIndex() -> size_t
|
||||
throw PlaylistEmptyException();
|
||||
}
|
||||
|
||||
AddCurrentPresetIndexToHistory();
|
||||
|
||||
if (m_shuffle)
|
||||
{
|
||||
std::uniform_int_distribution<size_t> randomDistribution(0, m_items.size());
|
||||
@ -205,6 +213,58 @@ auto Playlist::NextPresetIndex() -> size_t
|
||||
}
|
||||
|
||||
|
||||
auto Playlist::PreviousPresetIndex() -> size_t
|
||||
{
|
||||
if (m_items.empty())
|
||||
{
|
||||
throw PlaylistEmptyException();
|
||||
}
|
||||
|
||||
AddCurrentPresetIndexToHistory();
|
||||
|
||||
if (m_shuffle)
|
||||
{
|
||||
std::uniform_int_distribution<size_t> randomDistribution(0, m_items.size());
|
||||
m_currentPosition = randomDistribution(m_randomGenerator);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_currentPosition == 0)
|
||||
{
|
||||
m_currentPosition = m_items.size() -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentPosition--;
|
||||
}
|
||||
}
|
||||
|
||||
return m_currentPosition;
|
||||
}
|
||||
|
||||
auto Playlist::LastPresetIndex() -> size_t
|
||||
{
|
||||
if (m_items.empty())
|
||||
{
|
||||
throw PlaylistEmptyException();
|
||||
}
|
||||
|
||||
if (!m_presetHistory.empty())
|
||||
{
|
||||
m_currentPosition = m_presetHistory.back();
|
||||
m_presetHistory.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentPosition = PreviousPresetIndex();
|
||||
// Remove added history item again to prevent ping-pong behavior
|
||||
m_presetHistory.pop_back();
|
||||
}
|
||||
|
||||
return m_currentPosition;
|
||||
}
|
||||
|
||||
|
||||
auto Playlist::PresetIndex() const -> size_t
|
||||
{
|
||||
if (m_items.empty())
|
||||
@ -223,6 +283,13 @@ auto Playlist::SetPresetIndex(size_t presetIndex) -> size_t
|
||||
throw PlaylistEmptyException();
|
||||
}
|
||||
|
||||
AddCurrentPresetIndexToHistory();
|
||||
|
||||
if (presetIndex == m_currentPosition)
|
||||
{
|
||||
return m_currentPosition;
|
||||
}
|
||||
|
||||
m_currentPosition = presetIndex;
|
||||
|
||||
if (m_currentPosition >= m_items.size())
|
||||
@ -234,5 +301,30 @@ auto Playlist::SetPresetIndex(size_t presetIndex) -> size_t
|
||||
}
|
||||
|
||||
|
||||
void Playlist::AddCurrentPresetIndexToHistory()
|
||||
{
|
||||
// No duplicate entries.
|
||||
if (!m_presetHistory.empty() && m_currentPosition == m_presetHistory.back())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_presetHistory.push_back(m_currentPosition);
|
||||
if (m_presetHistory.size() > MaxHistoryItems)
|
||||
{
|
||||
m_presetHistory.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Playlist::RemoveLastHistoryEntry()
|
||||
{
|
||||
if (!m_presetHistory.empty())
|
||||
{
|
||||
m_presetHistory.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace Playlist
|
||||
} // namespace ProjectM
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -39,6 +40,11 @@ public:
|
||||
*/
|
||||
static constexpr auto InsertAtEnd = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
/**
|
||||
* Maximum number of items in the playback history.
|
||||
*/
|
||||
static constexpr size_t MaxHistoryItems = 1000;
|
||||
|
||||
/**
|
||||
* Sort predicate.
|
||||
*/
|
||||
@ -172,6 +178,28 @@ public:
|
||||
*/
|
||||
virtual auto NextPresetIndex() -> size_t;
|
||||
|
||||
/**
|
||||
* @brief Returns the previous preset index in the playlist.
|
||||
*
|
||||
* Each call will either decrement the current index, or select a random preset, depending on
|
||||
* the shuffle setting.
|
||||
*
|
||||
* @throws PlaylistEmptyException Thrown if the playlist is currently empty.
|
||||
* @return The index of the previous playlist item.
|
||||
*/
|
||||
virtual auto PreviousPresetIndex() -> size_t;
|
||||
|
||||
/**
|
||||
* @brief Returns the last preset index that has been played.
|
||||
*
|
||||
* Each call will pop the last history item. If the history is empty, it will internally call
|
||||
* PreviousPresetIndex(), but not add a history item.
|
||||
*
|
||||
* @throws PlaylistEmptyException Thrown if the playlist is currently empty.
|
||||
* @return The index of the last (or previous) playlist item.
|
||||
*/
|
||||
virtual auto LastPresetIndex() -> size_t;
|
||||
|
||||
/**
|
||||
* @brief Returns the current playlist/preset index without changing the position.
|
||||
* @throws PlaylistEmptyException Thrown if the playlist is currently empty.
|
||||
@ -191,10 +219,22 @@ public:
|
||||
*/
|
||||
virtual auto SetPresetIndex(size_t presetIndex) -> size_t;
|
||||
|
||||
/**
|
||||
* @brief Removes the newest entry in the playback history.
|
||||
* Useful if the last playlist item failed to load, so it won't get selected again.
|
||||
*/
|
||||
virtual void RemoveLastHistoryEntry();
|
||||
|
||||
private:
|
||||
std::vector<Item> m_items; //!< Items in the current playlist.
|
||||
bool m_shuffle{false}; //!< True if shuffle mode is enabled, false to play presets in order.
|
||||
size_t m_currentPosition{0}; //!< Current playlist position.
|
||||
/**
|
||||
* @brief Adds a preset to the history and trims the list if it gets too long.
|
||||
*/
|
||||
void AddCurrentPresetIndexToHistory();
|
||||
|
||||
std::vector<Item> m_items; //!< Items in the current playlist.
|
||||
bool m_shuffle{false}; //!< True if shuffle mode is enabled, false to play presets in order.
|
||||
size_t m_currentPosition{0}; //!< Current playlist position.
|
||||
std::list<size_t> m_presetHistory; //!< The playback history.
|
||||
|
||||
std::default_random_engine m_randomGenerator;
|
||||
};
|
||||
|
||||
@ -59,6 +59,11 @@ void PlaylistCWrapper::OnPresetSwitchFailed(const char* presetFilename, const ch
|
||||
|
||||
auto* playlist = reinterpret_cast<PlaylistCWrapper*>(userData);
|
||||
|
||||
// ToDo: Add different retry behavior for set/next/previous/last calls.
|
||||
|
||||
// Don't go back to a broken preset.
|
||||
playlist->RemoveLastHistoryEntry();
|
||||
|
||||
// Preset switch may fail due to broken presets, retry a few times before giving up.
|
||||
if (playlist->m_presetSwitchFailedCount < playlist->m_presetSwitchRetryCount)
|
||||
{
|
||||
@ -419,10 +424,57 @@ auto projectm_playlist_set_position(projectm_playlist_handle instance, uint32_t
|
||||
{
|
||||
auto newIndex = playlist->SetPresetIndex(new_position);
|
||||
playlist->PlayPresetIndex(newIndex, hard_cut, true);
|
||||
return newIndex;
|
||||
return playlist->PresetIndex();
|
||||
}
|
||||
catch (ProjectM::Playlist::PlaylistEmptyException&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t projectm_playlist_play_next(projectm_playlist_handle instance, bool hard_cut)
|
||||
{
|
||||
auto* playlist = playlist_handle_to_instance(instance);
|
||||
try
|
||||
{
|
||||
auto newIndex = playlist->NextPresetIndex();
|
||||
playlist->PlayPresetIndex(newIndex, hard_cut, true);
|
||||
return playlist->PresetIndex();
|
||||
}
|
||||
catch (ProjectM::Playlist::PlaylistEmptyException&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t projectm_playlist_play_previous(projectm_playlist_handle instance, bool hard_cut)
|
||||
{
|
||||
auto* playlist = playlist_handle_to_instance(instance);
|
||||
try
|
||||
{
|
||||
auto newIndex = playlist->PreviousPresetIndex();
|
||||
playlist->PlayPresetIndex(newIndex, hard_cut, true);
|
||||
return playlist->PresetIndex();
|
||||
}
|
||||
catch (ProjectM::Playlist::PlaylistEmptyException&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t projectm_playlist_play_last(projectm_playlist_handle instance, bool hard_cut)
|
||||
{
|
||||
auto* playlist = playlist_handle_to_instance(instance);
|
||||
try
|
||||
{
|
||||
auto newIndex = playlist->LastPresetIndex();
|
||||
playlist->PlayPresetIndex(newIndex, hard_cut, true);
|
||||
return playlist->PresetIndex();
|
||||
}
|
||||
catch (ProjectM::Playlist::PlaylistEmptyException&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -373,6 +373,52 @@ uint32_t projectm_playlist_get_position(projectm_playlist_handle instance);
|
||||
uint32_t projectm_playlist_set_position(projectm_playlist_handle instance, uint32_t new_position,
|
||||
bool hard_cut);
|
||||
|
||||
/**
|
||||
* @brief Plays the next playlist item and returns the index of the new preset.
|
||||
*
|
||||
* If shuffle is on, it will select a random preset, otherwise the next in the playlist. If the
|
||||
* end of the playlist is reached in continuous mode, it will wrap back to 0.
|
||||
*
|
||||
* The old playlist item is added to the history.
|
||||
*
|
||||
* @param instance The playlist manager instance.
|
||||
* @param hard_cut If true, the preset transition is instant. If true, a smooth transition is played.
|
||||
* @return The new playlist position. If the playlist is empty, 0 will be returned.
|
||||
*/
|
||||
uint32_t projectm_playlist_play_next(projectm_playlist_handle instance, bool hard_cut);
|
||||
|
||||
/**
|
||||
* @brief Plays the previous playlist item and returns the index of the new preset.
|
||||
*
|
||||
* If shuffle is on, it will select a random preset, otherwise the next in the playlist. If the
|
||||
* end of the playlist is reached in continuous mode, it will wrap back to 0.
|
||||
*
|
||||
* The old playlist item is added to the history.
|
||||
*
|
||||
* @param instance The playlist manager instance.
|
||||
* @param hard_cut If true, the preset transition is instant. If true, a smooth transition is played.
|
||||
* @return The new playlist position. If the playlist is empty, 0 will be returned.
|
||||
*/
|
||||
uint32_t projectm_playlist_play_previous(projectm_playlist_handle instance, bool hard_cut);
|
||||
|
||||
/**
|
||||
* @brief Plays the last preset played in the history and returns the index of the preset.
|
||||
*
|
||||
* The history keeps track of the last 1000 presets and will go back in the history. The
|
||||
* playback history will be cleared whenever the playlist items are changed.
|
||||
*
|
||||
* If the history is empty, this call behaves identical to projectm_playlist_play_previous(),
|
||||
* but the item is not added to the history.
|
||||
*
|
||||
* Presets which failed to load are not recorded in the history and thus will be skipped when
|
||||
* calling this method.
|
||||
*
|
||||
* @param instance The playlist manager instance.
|
||||
* @param hard_cut If true, the preset transition is instant. If true, a smooth transition is played.
|
||||
* @return The new playlist position. If the playlist is empty, 0 will be returned.
|
||||
*/
|
||||
uint32_t projectm_playlist_play_last(projectm_playlist_handle instance, bool hard_cut);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
// extern "C"
|
||||
|
||||
@ -372,6 +372,9 @@ TEST(projectMPlaylistAPI, SetPosition)
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PlayPresetIndex(512, false, true))
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(512));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_set_position(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), 256, true), 512);
|
||||
EXPECT_EQ(projectm_playlist_set_position(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), 256, false), 512);
|
||||
@ -389,3 +392,118 @@ TEST(projectMPlaylistAPI, SetPositionException)
|
||||
EXPECT_EQ(projectm_playlist_set_position(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), 256, true), 0);
|
||||
EXPECT_EQ(projectm_playlist_set_position(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), 256, false), 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, PlayNext)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, NextPresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(512));
|
||||
EXPECT_CALL(mockPlaylist, PlayPresetIndex(512, true, true))
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PlayPresetIndex(512, false, true))
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(512));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_play_next(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), true), 512);
|
||||
EXPECT_EQ(projectm_playlist_play_next(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), false), 512);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, PlayNextException)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, NextPresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Throw(ProjectM::Playlist::PlaylistEmptyException()));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_play_next(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), true), 0);
|
||||
EXPECT_EQ(projectm_playlist_play_next(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), false), 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, PlayPrevious)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, PreviousPresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(512));
|
||||
EXPECT_CALL(mockPlaylist, PlayPresetIndex(512, true, true))
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PlayPresetIndex(512, false, true))
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(512));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_play_previous(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), true), 512);
|
||||
EXPECT_EQ(projectm_playlist_play_previous(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), false), 512);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, PlayPreviousException)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, PreviousPresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Throw(ProjectM::Playlist::PlaylistEmptyException()));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_play_previous(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), true), 0);
|
||||
EXPECT_EQ(projectm_playlist_play_previous(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), false), 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, PlayLast)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, PreviousPresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(512));
|
||||
EXPECT_CALL(mockPlaylist, PlayPresetIndex(512, true, true))
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PlayPresetIndex(512, false, true))
|
||||
.Times(1);
|
||||
EXPECT_CALL(mockPlaylist, PresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(512));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_play_previous(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), true), 512);
|
||||
EXPECT_EQ(projectm_playlist_play_previous(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), false), 512);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, PlayLastException)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, LastPresetIndex())
|
||||
.Times(2)
|
||||
.WillRepeatedly(Throw(ProjectM::Playlist::PlaylistEmptyException()));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_play_last(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), true), 0);
|
||||
EXPECT_EQ(projectm_playlist_play_last(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), false), 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, SetPresetSwitchFailedCallback)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
projectm_playlist_preset_switch_failed_event dummyCallback = [](const char* preset_filename,
|
||||
const char* message,
|
||||
void* user_data) {};
|
||||
void* dummyData{reinterpret_cast<void*>(348564)};
|
||||
|
||||
EXPECT_CALL(mockPlaylist, SetPresetSwitchFailedCallback(dummyCallback, dummyData))
|
||||
.Times(1);
|
||||
|
||||
projectm_playlist_set_preset_switch_failed_event_callback(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), dummyCallback, dummyData);
|
||||
}
|
||||
@ -7,7 +7,8 @@
|
||||
class PlaylistCWrapperMock : public PlaylistCWrapper
|
||||
{
|
||||
public:
|
||||
PlaylistCWrapperMock() : PlaylistCWrapper(nullptr) {};
|
||||
PlaylistCWrapperMock()
|
||||
: PlaylistCWrapper(nullptr){};
|
||||
|
||||
// PlaylistCWrapper members
|
||||
MOCK_METHOD(void, Connect, (projectm_handle));
|
||||
@ -17,14 +18,19 @@ public:
|
||||
MOCK_METHOD(bool, Empty, (), (const));
|
||||
MOCK_METHOD(void, Clear, ());
|
||||
MOCK_METHOD(const std::vector<ProjectM::Playlist::Item>&, Items, (), (const));
|
||||
MOCK_METHOD(bool, AddItem, (const std::string&, uint32_t, bool));
|
||||
MOCK_METHOD(uint32_t, AddPath, (const std::string&, uint32_t, bool, bool));
|
||||
MOCK_METHOD(bool, AddItem, (const std::string&, uint32_t, bool) );
|
||||
MOCK_METHOD(uint32_t, AddPath, (const std::string&, uint32_t, bool, bool) );
|
||||
MOCK_METHOD(bool, RemoveItem, (uint32_t));
|
||||
MOCK_METHOD(void, SetShuffle, (bool));
|
||||
MOCK_METHOD(void, SetShuffle, (bool) );
|
||||
MOCK_METHOD(void, Sort, (uint32_t, uint32_t, SortPredicate, SortOrder));
|
||||
MOCK_METHOD(uint32_t, RetryCount, ());
|
||||
MOCK_METHOD(void, SetRetryCount, (uint32_t));
|
||||
MOCK_METHOD(size_t, NextPresetIndex, (), ());
|
||||
MOCK_METHOD(size_t, PreviousPresetIndex, (), ());
|
||||
MOCK_METHOD(size_t, LastPresetIndex, (), ());
|
||||
MOCK_METHOD(size_t, PresetIndex, (), (const));
|
||||
MOCK_METHOD(size_t, SetPresetIndex, (size_t));
|
||||
MOCK_METHOD(void, PlayPresetIndex, (size_t, bool, bool));
|
||||
MOCK_METHOD(void, PlayPresetIndex, (size_t, bool, bool) );
|
||||
MOCK_METHOD(void, RemoveLastHistoryEntry, ());
|
||||
MOCK_METHOD(void, SetPresetSwitchFailedCallback, (projectm_playlist_preset_switch_failed_event, void*));
|
||||
};
|
||||
|
||||
@ -459,6 +459,101 @@ TEST(projectMPlaylistPlaylist, NextPresetIndexSequential)
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, PreviousPresetIndexEmptyPlaylist)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
EXPECT_THROW(playlist.PreviousPresetIndex(), ProjectM::Playlist::PlaylistEmptyException);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, PreviousPresetIndexShuffle)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
playlist.SetShuffle(true);
|
||||
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetZ.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetA.milk", Playlist::InsertAtEnd, false));
|
||||
|
||||
// Shuffle 100 times, this will have an (almost) 100% chance that both presets were played.
|
||||
std::set<size_t> playlistIndices;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
EXPECT_NO_THROW(playlistIndices.insert(playlist.PreviousPresetIndex()));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(playlistIndices.find(0) != playlistIndices.end());
|
||||
EXPECT_TRUE(playlistIndices.find(1) != playlistIndices.end());
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, PreviousPresetIndexSequential)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
playlist.SetShuffle(false);
|
||||
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetZ.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetA.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/other/PresetC.milk", Playlist::InsertAtEnd, false));
|
||||
|
||||
EXPECT_EQ(playlist.PreviousPresetIndex(), 2);
|
||||
EXPECT_EQ(playlist.PreviousPresetIndex(), 1);
|
||||
EXPECT_EQ(playlist.PreviousPresetIndex(), 0);
|
||||
EXPECT_EQ(playlist.PreviousPresetIndex(), 2);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, LastPresetIndex)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
playlist.SetShuffle(false);
|
||||
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetZ.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetA.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/other/PresetC.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/the/last/Preset.milk", Playlist::InsertAtEnd, false));
|
||||
|
||||
EXPECT_EQ(playlist.SetPresetIndex(1), 1);
|
||||
EXPECT_EQ(playlist.SetPresetIndex(2), 2);
|
||||
EXPECT_EQ(playlist.SetPresetIndex(1), 1);
|
||||
EXPECT_EQ(playlist.SetPresetIndex(1), 1);
|
||||
EXPECT_EQ(playlist.SetPresetIndex(0), 0);
|
||||
|
||||
EXPECT_EQ(playlist.PresetIndex(), 0);
|
||||
|
||||
// Index 1 should only be added once here, even if played twice.
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 1);
|
||||
EXPECT_EQ(playlist.PresetIndex(), 1);
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 2);
|
||||
EXPECT_EQ(playlist.PresetIndex(), 2);
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 1);
|
||||
EXPECT_EQ(playlist.PresetIndex(), 1);
|
||||
|
||||
// Starting index 0 is always be in the history.
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 0);
|
||||
EXPECT_EQ(playlist.PresetIndex(), 0);
|
||||
|
||||
// History empty, wrap back to last item.
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 3);
|
||||
EXPECT_EQ(playlist.PresetIndex(), 3);
|
||||
|
||||
// History should stell be empty, go back one item.
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 2);
|
||||
EXPECT_EQ(playlist.PresetIndex(), 2);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, LastPresetIndexEmptyPlaylist)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
EXPECT_THROW(playlist.LastPresetIndex(), ProjectM::Playlist::PlaylistEmptyException);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, SetPresetIndex)
|
||||
{
|
||||
Playlist playlist;
|
||||
@ -489,7 +584,7 @@ TEST(projectMPlaylistPlaylist, SetPresetIndexException)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
EXPECT_THROW(playlist.SetPresetIndex(0), ProjectM::Playlist::PlaylistEmptyException);;
|
||||
EXPECT_THROW(playlist.SetPresetIndex(0), ProjectM::Playlist::PlaylistEmptyException);
|
||||
}
|
||||
|
||||
|
||||
@ -511,5 +606,24 @@ TEST(projectMPlaylistPlaylist, PresetIndexException)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
EXPECT_THROW(playlist.PresetIndex(), ProjectM::Playlist::PlaylistEmptyException);;
|
||||
EXPECT_THROW(playlist.PresetIndex(), ProjectM::Playlist::PlaylistEmptyException);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, RemoveLastHistoryEntry)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetZ.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/PresetA.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/other/PresetC.milk", Playlist::InsertAtEnd, false));
|
||||
|
||||
EXPECT_EQ(playlist.SetPresetIndex(1), 1);
|
||||
EXPECT_EQ(playlist.SetPresetIndex(2), 2);
|
||||
|
||||
// History: 0,1
|
||||
playlist.RemoveLastHistoryEntry();
|
||||
// History: 0
|
||||
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user