From 4dfae6bf22bdde106baae3c7b9a9dda0b5c465ab Mon Sep 17 00:00:00 2001 From: Kai Blaschke Date: Thu, 27 Oct 2022 12:11:28 +0200 Subject: [PATCH] Add test project for playlist library, implemented tests for existing code and fixed a few issues found by testing. --- src/playlist/CMakeLists.txt | 5 + src/playlist/Playlist.cpp | 16 +- src/playlist/Playlist.hpp | 32 +++- src/playlist/PlaylistCWrapper.cpp | 12 +- src/playlist/PlaylistCWrapper.h | 2 +- src/playlist/playlist.h | 2 +- tests/CMakeLists.txt | 1 + tests/playlist/APITest.cpp | 207 +++++++++++++++++++++ tests/playlist/CMakeLists.txt | 23 +++ tests/playlist/ItemTest.cpp | 25 +++ tests/playlist/PlaylistCWrapperMock.cpp | 1 + tests/playlist/PlaylistCWrapperMock.h | 22 +++ tests/playlist/PlaylistTest.cpp | 230 ++++++++++++++++++++++++ 13 files changed, 564 insertions(+), 14 deletions(-) create mode 100644 tests/playlist/APITest.cpp create mode 100644 tests/playlist/CMakeLists.txt create mode 100644 tests/playlist/ItemTest.cpp create mode 100644 tests/playlist/PlaylistCWrapperMock.cpp create mode 100644 tests/playlist/PlaylistCWrapperMock.h create mode 100644 tests/playlist/PlaylistTest.cpp diff --git a/src/playlist/CMakeLists.txt b/src/playlist/CMakeLists.txt index cb8dd6497..98e8c5452 100644 --- a/src/playlist/CMakeLists.txt +++ b/src/playlist/CMakeLists.txt @@ -9,6 +9,11 @@ add_library(projectM_playlist STATIC playlist.h ) +target_include_directories(projectM_playlist + PUBLIC + $ + ) + target_link_libraries(projectM_playlist PUBLIC projectM::API diff --git a/src/playlist/Playlist.cpp b/src/playlist/Playlist.cpp index 693ca340a..1a546fbf7 100644 --- a/src/playlist/Playlist.cpp +++ b/src/playlist/Playlist.cpp @@ -7,16 +7,17 @@ namespace Playlist { uint32_t Playlist::Size() const { - return 0; + return m_items.size(); } void Playlist::Clear() { + m_items.clear(); } -const std::vector& Playlist::Items() +const std::vector& Playlist::Items() const { return m_items; } @@ -24,6 +25,11 @@ const std::vector& Playlist::Items() bool Playlist::AddItem(const std::string& filename, uint32_t index, bool allowDuplicates) { + if (filename.empty()) + { + return false; + } + if (!allowDuplicates) { if (std::find(m_items.begin(), m_items.end(), filename) != m_items.end()) @@ -63,5 +69,11 @@ void Playlist::Shuffle(bool enabled) m_shuffle = enabled; } + +auto Playlist::Shuffle() -> bool +{ + return m_shuffle; +} + } // namespace Playlist } // namespace ProjectM diff --git a/src/playlist/Playlist.hpp b/src/playlist/Playlist.hpp index 056269a5f..1e83a9aa9 100644 --- a/src/playlist/Playlist.hpp +++ b/src/playlist/Playlist.hpp @@ -3,6 +3,7 @@ #include "Item.hpp" #include +#include #include #include @@ -18,25 +19,38 @@ namespace Playlist { class Playlist { public: + /** + * Short-hand constant which can be used in AddItem() to add new presets at the end of the playlist. + */ + static constexpr auto InsertAtEnd = std::numeric_limits::max(); + + /** + * Destructor. + */ + virtual ~Playlist() = default; + /** * @brief Returns the number of items in the current playlist. * @return The number of items in the current playlist. */ - uint32_t Size() const; + virtual uint32_t Size() const; /** * @brief Clears the current playlist. */ - void Clear(); + virtual void Clear(); /** * @brief Returns the playlist items. * @return A vector with items in the current playlist. */ - const std::vector& Items(); + virtual const std::vector& Items() const; /** * @brief Adds a preset file to the playlist. + * + * Use Playlist::InsertAtEnd as index to always insert an item at the end of the playlist. + * * @param filename The file path and name to add. * @param index The index to insert the preset at. If larger than the playlist size, it's added * to the end of the playlist. @@ -44,7 +58,7 @@ public: * (including the path) are not added if already present. * @return True if the preset was added, false if it already existed. */ - auto AddItem(const std::string& filename, uint32_t index, bool allowDuplicates) -> bool; + virtual auto AddItem(const std::string& filename, uint32_t index, bool allowDuplicates) -> bool; /** * @brief Removed a playlist item at the given playlist index. @@ -52,13 +66,19 @@ public: * @return True if an item was removed, false if the index was out of bounds and no item was * removed.. */ - auto RemoveItem(uint32_t index) -> bool; + virtual auto RemoveItem(uint32_t index) -> bool; /** * @brief Enables or disabled shuffle mode. * @param enabled True to enable shuffle mode, false to disable. */ - void Shuffle(bool enabled); + virtual void Shuffle(bool enabled); + + /** + * @brief Returns the enable state of shuffle mode. + * @return True if shuffle is enabled, false if not. + */ + virtual auto Shuffle() -> bool; private: std::vector m_items; //!< Items in the current playlist. diff --git a/src/playlist/PlaylistCWrapper.cpp b/src/playlist/PlaylistCWrapper.cpp index 03b46feef..593e99c28 100644 --- a/src/playlist/PlaylistCWrapper.cpp +++ b/src/playlist/PlaylistCWrapper.cpp @@ -2,6 +2,8 @@ #include +using ProjectM::Playlist::Playlist; + PlaylistCWrapper::PlaylistCWrapper(projectm_handle projectMInstance) { } @@ -19,12 +21,13 @@ auto playlist_handle_to_instance(projectm_playlist_handle instance) -> PlaylistC } -void projectm_playlist_free_string_array(const char** array) +void projectm_playlist_free_string_array(char** array) { int index{0}; while (array[index] != nullptr) { delete[] array[index]; + index++; } delete[] array; } @@ -87,6 +90,7 @@ auto projectm_playlist_items(projectm_playlist_handle instance) -> char** auto filename = item.Filename(); array[index] = new char[filename.length() + 1]{}; filename.copy(array[index], filename.length()); + index++; } return array; @@ -107,7 +111,7 @@ auto projectm_playlist_add_preset(projectm_playlist_handle instance, const char* { auto* playlist = playlist_handle_to_instance(instance); - return playlist->AddItem(filename, std::numeric_limits::max(), allow_duplicates); + return playlist->AddItem(filename, Playlist::InsertAtEnd, allow_duplicates); } @@ -139,7 +143,7 @@ uint32_t projectm_playlist_add_presets(projectm_playlist_handle instance, const continue; } - if (playlist->AddItem(filenames[index], std::numeric_limits::max(), allow_duplicates)) + if (playlist->AddItem(filenames[index], Playlist::InsertAtEnd, allow_duplicates)) { addCount++; } @@ -168,7 +172,7 @@ auto projectm_playlist_insert_presets(projectm_playlist_handle instance, const c continue; } - if (playlist->AddItem(filenames[filenameIndex], index + filenameIndex, allow_duplicates)) + if (playlist->AddItem(filenames[filenameIndex], index + addCount, allow_duplicates)) { addCount++; } diff --git a/src/playlist/PlaylistCWrapper.h b/src/playlist/PlaylistCWrapper.h index 54de4df82..8157ffc30 100644 --- a/src/playlist/PlaylistCWrapper.h +++ b/src/playlist/PlaylistCWrapper.h @@ -17,7 +17,7 @@ public: * @brief Reconnects the playlist instance to another projectM instance, or disconnects it. * @param projectMInstance A pointer to an existing projectM instance or nullptr to disconnect. */ - void Connect(projectm_handle projectMInstance); + virtual void Connect(projectm_handle projectMInstance); private: projectm_handle m_projectMInstance{nullptr}; //!< The projectM instance handle this instance is connected to. diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 05e951f41..20ac95b68 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -17,7 +17,7 @@ typedef struct projectm_playlist* projectm_playlist_handle; //!< A pointer to th * * @param array The pointer to the array of strings that should be freed. */ -void projectm_playlist_free_string_array(const char** array); +void projectm_playlist_free_string_array(char** array); /** * @brief Creates a playlist manager for the given projectM instance diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1ac844f1f..2ee70688c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(libprojectM) +add_subdirectory(playlist) \ No newline at end of file diff --git a/tests/playlist/APITest.cpp b/tests/playlist/APITest.cpp new file mode 100644 index 000000000..cb5794ae2 --- /dev/null +++ b/tests/playlist/APITest.cpp @@ -0,0 +1,207 @@ +#include "PlaylistCWrapperMock.h" + +#include + +#include + +using ::testing::Return; +using ::testing::ReturnRef; + +/** + * This suite only tests the API forwarding to the wrapper, not the actual playlist functionality! + * + * Also note that the playlist wrapper class should never be instantiated directly in production + * code. ALWAYS use projectm_playlist_create() to create the instance and only use the C API + * functions to access the functionality. The extreme use of reinterpret_cast<>() in this test suite + * should make that quite obvious. + */ +TEST(projectMPlaylist, APICreate) +{ + auto* playlistHandle = projectm_playlist_create(nullptr); + + ASSERT_NE(playlistHandle, nullptr); + + projectm_playlist_destroy(playlistHandle); +} + + +TEST(projectMPlaylist, APIConnect) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, Connect(nullptr)) + .Times(1); + + projectm_playlist_connect(reinterpret_cast(&mockPlaylist), nullptr); + + projectm_handle someHandle{reinterpret_cast(2537)}; + EXPECT_CALL(mockPlaylist, Connect(someHandle)).Times(1); + + projectm_playlist_connect(reinterpret_cast(&mockPlaylist), someHandle); +} + + +TEST(projectMPlaylist, APISize) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, Size()) + .Times(1) + .WillOnce(Return(2336)); + + ASSERT_EQ(projectm_playlist_size(reinterpret_cast(&mockPlaylist)), 2336); +} + + +TEST(projectMPlaylist, APIClear) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, Clear()) + .Times(1); + + projectm_playlist_clear(reinterpret_cast(&mockPlaylist)); +} + + +TEST(projectMPlaylist, APIItems) +{ + PlaylistCWrapperMock mockPlaylist; + + std::vector items{ + ProjectM::Playlist::Item("/some/file"), + ProjectM::Playlist::Item("/another/file")}; + + EXPECT_CALL(mockPlaylist, Items()) + .Times(1) + .WillOnce(ReturnRef(items)); + + auto* returnedItems = projectm_playlist_items(reinterpret_cast(&mockPlaylist)); + ASSERT_NE(returnedItems, nullptr); + ASSERT_NE(*returnedItems, nullptr); + EXPECT_STREQ(*returnedItems, items.at(0).Filename().c_str()); + ASSERT_NE(*(returnedItems + 1), nullptr); + EXPECT_STREQ(*(returnedItems + 1), items.at(1).Filename().c_str()); + EXPECT_EQ(*(returnedItems + 2), nullptr); + + projectm_playlist_free_string_array(returnedItems); +} + + +TEST(projectMPlaylist, APIAddPath) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_EQ(projectm_playlist_add_path(reinterpret_cast(&mockPlaylist), "", true, false), 0); +} + + +TEST(projectMPlaylist, APIAddPreset) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, AddItem("/some/file", ProjectM::Playlist::Playlist::InsertAtEnd, false)) + .Times(1) + .WillOnce(Return(true)); + + EXPECT_TRUE(projectm_playlist_add_preset(reinterpret_cast(&mockPlaylist), "/some/file", false)); +} + + +TEST(projectMPlaylist, APIInsertPreset) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, AddItem("/some/file", 34, true)) + .Times(1) + .WillOnce(Return(true)); + + EXPECT_TRUE(projectm_playlist_insert_preset(reinterpret_cast(&mockPlaylist), "/some/file", 34, true)); +} + + +TEST(projectMPlaylist, APIAddPresets) +{ + PlaylistCWrapperMock mockPlaylist; + + const char firstFile[]{"/some/file"}; + const char secondFile[]{"/another/file"}; + const char thirdFile[]{"/another/file"}; + const char* presetList[]{firstFile, secondFile, thirdFile}; + + EXPECT_CALL(mockPlaylist, AddItem("/some/file", ProjectM::Playlist::Playlist::InsertAtEnd, false)) + .Times(1) + .WillOnce(Return(true)); + EXPECT_CALL(mockPlaylist, AddItem("/another/file", ProjectM::Playlist::Playlist::InsertAtEnd, false)) + .Times(2) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + + EXPECT_EQ(projectm_playlist_add_presets(reinterpret_cast(&mockPlaylist), presetList, 3, false), 2); +} + + +TEST(projectMPlaylist, APIInsertPresets) +{ + PlaylistCWrapperMock mockPlaylist; + + const char firstFile[]{"/some/file"}; + const char secondFile[]{"/some/file"}; + const char thirdFile[]{"/another/file"}; + const char* presetList[]{firstFile, secondFile, thirdFile}; + + EXPECT_CALL(mockPlaylist, AddItem("/some/file", 34, false)) + .Times(1) + .WillOnce(Return(true)); + EXPECT_CALL(mockPlaylist, AddItem("/some/file", 35, false)) + .Times(1) + .WillOnce(Return(false)); + EXPECT_CALL(mockPlaylist, AddItem("/another/file", 35, false)) // Index not incremented! + .Times(1) + .WillOnce(Return(true)); + + EXPECT_EQ(projectm_playlist_insert_presets(reinterpret_cast(&mockPlaylist), presetList, 3, 34, false), 2); +} + + +TEST(projectMPlaylist, APIRemovePreset) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, RemoveItem(0)) + .Times(2) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + + EXPECT_TRUE(projectm_playlist_remove_preset(reinterpret_cast(&mockPlaylist), 0)); + EXPECT_FALSE(projectm_playlist_remove_preset(reinterpret_cast(&mockPlaylist), 0)); +} + + +TEST(projectMPlaylist, APIRemovePresets) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, RemoveItem(0)) + .Times(3) + .WillOnce(Return(true)) + .WillOnce(Return(true)) + .WillOnce(Return(false)); + + EXPECT_EQ(projectm_playlist_remove_presets(reinterpret_cast(&mockPlaylist), 0, 3), 2); +} + + +TEST(projectMPlaylist, APISetShuffle) +{ + PlaylistCWrapperMock mockPlaylist; + + EXPECT_CALL(mockPlaylist, Shuffle(true)) + .Times(1); + EXPECT_CALL(mockPlaylist, Shuffle(false)) + .Times(1); + + projectm_playlist_set_shuffle(reinterpret_cast(&mockPlaylist), true); + projectm_playlist_set_shuffle(reinterpret_cast(&mockPlaylist), false); +} + diff --git a/tests/playlist/CMakeLists.txt b/tests/playlist/CMakeLists.txt new file mode 100644 index 000000000..32f1754d6 --- /dev/null +++ b/tests/playlist/CMakeLists.txt @@ -0,0 +1,23 @@ +if(NOT TARGET projectM_playlist) + return() +endif() + +find_package(GTest 1.10 REQUIRED NO_MODULE) + +add_executable(projectM-playlist-unittest + APITest.cpp + ItemTest.cpp + PlaylistCWrapperMock.cpp + PlaylistCWrapperMock.h + PlaylistTest.cpp + ) + +target_link_libraries(projectM-playlist-unittest + PRIVATE + projectM_playlist + GTest::gmock + GTest::gtest + GTest::gtest_main + ) + +add_test(NAME projectM-playlist-unittest COMMAND projectM-playlist-unittest) diff --git a/tests/playlist/ItemTest.cpp b/tests/playlist/ItemTest.cpp new file mode 100644 index 000000000..4226b3845 --- /dev/null +++ b/tests/playlist/ItemTest.cpp @@ -0,0 +1,25 @@ +#include + +#include + +TEST(projectMPlaylist, ItemCreate) +{ + ASSERT_NO_THROW(ProjectM::Playlist::Item item("/some/file")); +} + + +TEST(projectMPlaylist, ItemGetFilename) +{ + ProjectM::Playlist::Item item("/some/file"); + + ASSERT_EQ(item.Filename(), "/some/file"); +} + + +TEST(projectMPlaylist, ItemFilenameEquality) +{ + ProjectM::Playlist::Item item("/some/file"); + + EXPECT_TRUE(item == "/some/file"); + EXPECT_FALSE(item == "/some/other/file"); +} diff --git a/tests/playlist/PlaylistCWrapperMock.cpp b/tests/playlist/PlaylistCWrapperMock.cpp new file mode 100644 index 000000000..c98ada727 --- /dev/null +++ b/tests/playlist/PlaylistCWrapperMock.cpp @@ -0,0 +1 @@ +#include "PlaylistCWrapperMock.h" diff --git a/tests/playlist/PlaylistCWrapperMock.h b/tests/playlist/PlaylistCWrapperMock.h new file mode 100644 index 000000000..a9c79b297 --- /dev/null +++ b/tests/playlist/PlaylistCWrapperMock.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include + +class PlaylistCWrapperMock : public PlaylistCWrapper +{ +public: + PlaylistCWrapperMock() : PlaylistCWrapper(nullptr) {}; + + // PlaylistCWrapper members + MOCK_METHOD(void, Connect, (projectm_handle)); + + // Playlist members + MOCK_METHOD(uint32_t, Size, (), (const)); + MOCK_METHOD(void, Clear, ()); + MOCK_METHOD(const std::vector&, Items, (), (const)); + MOCK_METHOD(bool, AddItem, (const std::string&, uint32_t, bool)); + MOCK_METHOD(bool, RemoveItem, (uint32_t)); + MOCK_METHOD(void, Shuffle, (bool)); +}; diff --git a/tests/playlist/PlaylistTest.cpp b/tests/playlist/PlaylistTest.cpp new file mode 100644 index 000000000..a6fc9a51d --- /dev/null +++ b/tests/playlist/PlaylistTest.cpp @@ -0,0 +1,230 @@ +#include + +#include + +using ProjectM::Playlist::Playlist; + +TEST(projectMPlaylist, PlaylistCreate) +{ + ASSERT_NO_THROW(Playlist playlist); +} + + +TEST(projectMPlaylist, PlaylistSize) +{ + Playlist playlist; + + EXPECT_EQ(playlist.Size(), 0); + + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + + EXPECT_EQ(playlist.Size(), 1); +} + + +TEST(projectMPlaylist, PlaylistClear) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + + EXPECT_EQ(playlist.Size(), 1); + + playlist.Clear(); + + EXPECT_EQ(playlist.Size(), 0); +} + + +TEST(projectMPlaylist, PlaylistItems) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 2); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 2); + EXPECT_EQ(items.at(0).Filename(), "/some/file"); + EXPECT_EQ(items.at(1).Filename(), "/some/other/file"); +} + + +TEST(projectMPlaylist, PlaylistAddItemEmptyFilename) +{ + Playlist playlist; + EXPECT_FALSE(playlist.AddItem("", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 0); +} + + +TEST(projectMPlaylist, PlaylistAddItemAtEnd) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/yet/another/file", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 3); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 3); + EXPECT_EQ(items.at(2).Filename(), "/yet/another/file"); +} + + +TEST(projectMPlaylist, PlaylistAddItemAtFront) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", 0, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", 0, false)); + EXPECT_TRUE(playlist.AddItem("/yet/another/file", 0, false)); + + ASSERT_EQ(playlist.Size(), 3); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 3); + EXPECT_EQ(items.at(0).Filename(), "/yet/another/file"); + EXPECT_EQ(items.at(1).Filename(), "/some/other/file"); + EXPECT_EQ(items.at(2).Filename(), "/some/file"); +} + + +TEST(projectMPlaylist, PlaylistAddItemInMiddle) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", 0, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/yet/another/file", 1, false)); + + ASSERT_EQ(playlist.Size(), 3); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 3); + EXPECT_EQ(items.at(0).Filename(), "/some/file"); + EXPECT_EQ(items.at(1).Filename(), "/yet/another/file"); + EXPECT_EQ(items.at(2).Filename(), "/some/other/file"); +} + + +TEST(projectMPlaylist, PlaylistAddItemDuplicates) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, true)); + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, true)); + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, true)); + + ASSERT_EQ(playlist.Size(), 3); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 3); + EXPECT_EQ(items.at(2).Filename(), "/some/file"); +} + + +TEST(projectMPlaylist, PlaylistAddItemNoDuplicates) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_FALSE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_FALSE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 1); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 1); + EXPECT_EQ(items.at(0).Filename(), "/some/file"); +} + + +TEST(projectMPlaylist, PlaylistRemoveItemFromEnd) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/yet/another/file", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 3); + + EXPECT_TRUE(playlist.RemoveItem(2)); + + ASSERT_EQ(playlist.Size(), 2); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 2); + EXPECT_EQ(items.at(0).Filename(), "/some/file"); + EXPECT_EQ(items.at(1).Filename(), "/some/other/file"); +} + + +TEST(projectMPlaylist, PlaylistRemoveItemFromFront) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/yet/another/file", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 3); + + EXPECT_TRUE(playlist.RemoveItem(0)); + + ASSERT_EQ(playlist.Size(), 2); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 2); + EXPECT_EQ(items.at(0).Filename(), "/some/other/file"); + EXPECT_EQ(items.at(1).Filename(), "/yet/another/file"); +} + + +TEST(projectMPlaylist, PlaylistRemoveItemFromMiddle) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/yet/another/file", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 3); + + EXPECT_TRUE(playlist.RemoveItem(1)); + + ASSERT_EQ(playlist.Size(), 2); + + const auto& items = playlist.Items(); + ASSERT_EQ(items.size(), 2); + EXPECT_EQ(items.at(0).Filename(), "/some/file"); + EXPECT_EQ(items.at(1).Filename(), "/yet/another/file"); +} + + +TEST(projectMPlaylist, PlaylistRemoveItemIndexOutOfBounds) +{ + Playlist playlist; + EXPECT_TRUE(playlist.AddItem("/some/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/some/other/file", Playlist::InsertAtEnd, false)); + EXPECT_TRUE(playlist.AddItem("/yet/another/file", Playlist::InsertAtEnd, false)); + + ASSERT_EQ(playlist.Size(), 3); + + EXPECT_FALSE(playlist.RemoveItem(100)); + + ASSERT_EQ(playlist.Size(), 3); +} + + +TEST(projectMPlaylist, PlaylistShuffleEnableDisable) +{ + Playlist playlist; + + EXPECT_FALSE(playlist.Shuffle()); + + playlist.Shuffle(true); + + EXPECT_TRUE(playlist.Shuffle()); + + playlist.Shuffle(false); + + EXPECT_FALSE(playlist.Shuffle()); +} +