mirror of
https://github.com/projectM-visualizer/projectm.git
synced 2026-02-04 20:55:46 +00:00
Add glob pattern filtering to playlist library.
Syntax is very similar to .gitignore glob syntax, with a few exceptions to simplify use.
This commit is contained in:
@ -506,4 +506,66 @@ TEST(projectMPlaylistAPI, SetPresetSwitchFailedCallback)
|
||||
.Times(1);
|
||||
|
||||
projectm_playlist_set_preset_switch_failed_event_callback(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), dummyCallback, dummyData);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, SetFilter)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, Filter())
|
||||
.Times(1)
|
||||
.WillOnce(ReturnRef(filter));
|
||||
|
||||
const char firstFilter[]{"-/some/BadPreset.milk"};
|
||||
const char secondFilter[]{"+/another/AwesomePreset.milk"};
|
||||
const char thirdFilter[]{"-/unwanted/Preset.milk"};
|
||||
const char* filterList[]{firstFilter, secondFilter, thirdFilter};
|
||||
|
||||
projectm_playlist_set_filter(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), filterList, 3);
|
||||
|
||||
const auto& internalFilterList = filter.List();
|
||||
ASSERT_EQ(internalFilterList.size(), 3);
|
||||
EXPECT_EQ(internalFilterList.at(0), "-/some/BadPreset.milk");
|
||||
EXPECT_EQ(internalFilterList.at(1), "+/another/AwesomePreset.milk");
|
||||
EXPECT_EQ(internalFilterList.at(2), "-/unwanted/Preset.milk");
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, GetFilter)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-/some/BadPreset.milk",
|
||||
"+/another/AwesomePreset.milk",
|
||||
"-/unwanted/Preset.milk"});
|
||||
|
||||
EXPECT_CALL(mockPlaylist, Filter())
|
||||
.Times(1)
|
||||
.WillOnce(ReturnRef(filter));
|
||||
|
||||
size_t count{};
|
||||
auto filterList = projectm_playlist_get_filter(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist), &count);
|
||||
|
||||
ASSERT_EQ(count, 3);
|
||||
ASSERT_NE(filterList, nullptr);
|
||||
EXPECT_STREQ(filterList[0], "-/some/BadPreset.milk");
|
||||
EXPECT_STREQ(filterList[1], "+/another/AwesomePreset.milk");
|
||||
EXPECT_STREQ(filterList[2], "-/unwanted/Preset.milk");
|
||||
|
||||
projectm_playlist_free_string_array(filterList);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistAPI, ApplyFilter)
|
||||
{
|
||||
PlaylistCWrapperMock mockPlaylist;
|
||||
|
||||
EXPECT_CALL(mockPlaylist, ApplyFilter())
|
||||
.Times(1)
|
||||
.WillOnce(Return(5));
|
||||
|
||||
EXPECT_EQ(projectm_playlist_apply_filter(reinterpret_cast<projectm_playlist_handle>(&mockPlaylist)), 5);
|
||||
}
|
||||
@ -7,11 +7,10 @@ find_package(GTest 1.10 REQUIRED NO_MODULE)
|
||||
add_executable(projectM-playlist-unittest
|
||||
APITest.cpp
|
||||
ItemTest.cpp
|
||||
PlaylistCWrapperMock.cpp
|
||||
PlaylistCWrapperMock.h
|
||||
PlaylistTest.cpp
|
||||
ProjectMAPIMocks.cpp
|
||||
)
|
||||
FilterTest.cpp)
|
||||
|
||||
target_compile_definitions(projectM-playlist-unittest
|
||||
PRIVATE
|
||||
|
||||
180
tests/playlist/FilterTest.cpp
Normal file
180
tests/playlist/FilterTest.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
#include <Filter.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(projectMPlaylistFilter, List)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-TestString.milk",
|
||||
"+AnotherTestString*"});
|
||||
|
||||
const auto& filters = filter.List();
|
||||
ASSERT_EQ(filters.size(), 2);
|
||||
|
||||
EXPECT_EQ(filters.at(0), "-TestString.milk");
|
||||
EXPECT_EQ(filters.at(1), "+AnotherTestString*");
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, ExactMatchExclude)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-TestString.milk"});
|
||||
|
||||
EXPECT_FALSE(filter.Passes("TestString.milk"));
|
||||
EXPECT_TRUE(filter.Passes("Teststring.milk"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, ExactMatchExcludePath)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-/path/to/TestString.milk"});
|
||||
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestString.milk"));
|
||||
EXPECT_TRUE(filter.Passes("/path/to/Teststring.milk"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, SingleCharacterExclude)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-/path/to/TestStr?ng.milk"});
|
||||
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestString.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestStrung.milk"));
|
||||
EXPECT_TRUE(filter.Passes("/path/to/TestStr/ng.milk"));
|
||||
EXPECT_TRUE(filter.Passes("/path/to/Teststring.milk"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, MultiCharacterExclude)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-/path/to/Test*.milk"});
|
||||
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestString.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestFile.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestALotOfAdditional.Characters.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/to/Test.milk"));
|
||||
EXPECT_TRUE(filter.Passes("/path/to/Test/String.milk"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, MultiCharacterExcludeExamples)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-a"});
|
||||
EXPECT_FALSE(filter.Passes("a"));
|
||||
EXPECT_FALSE(filter.Passes("x/a"));
|
||||
EXPECT_FALSE(filter.Passes("x/y/a"));
|
||||
EXPECT_TRUE(filter.Passes("b"));
|
||||
EXPECT_TRUE(filter.Passes("x/b"));
|
||||
EXPECT_TRUE(filter.Passes("a/a/b"));
|
||||
|
||||
filter.SetList({"-/*"});
|
||||
EXPECT_FALSE(filter.Passes("a"));
|
||||
EXPECT_FALSE(filter.Passes("b"));
|
||||
EXPECT_TRUE(filter.Passes("x/a"));
|
||||
EXPECT_TRUE(filter.Passes("x/b"));
|
||||
EXPECT_TRUE(filter.Passes("x/y/a"));
|
||||
|
||||
filter.SetList({"-/a"});
|
||||
EXPECT_FALSE(filter.Passes("a"));
|
||||
EXPECT_FALSE(filter.Passes("/a"));
|
||||
EXPECT_FALSE(filter.Passes("./a"));
|
||||
EXPECT_TRUE(filter.Passes("x/a"));
|
||||
EXPECT_TRUE(filter.Passes("x/y/a"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, PathGlobExclude)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-**/Test.milk"});
|
||||
|
||||
EXPECT_FALSE(filter.Passes("/path/to/Test.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/Test.milk"));
|
||||
EXPECT_FALSE(filter.Passes("Test.milk"));
|
||||
EXPECT_FALSE(filter.Passes("\\path\\to\\path\\to\\path\\to/path/to/path/to/Test.milk"));
|
||||
EXPECT_TRUE(filter.Passes("/path/to/Test/.milk"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, PathGlobExcludeExamples)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-**/a"});
|
||||
EXPECT_FALSE(filter.Passes("a"));
|
||||
EXPECT_FALSE(filter.Passes("x/a"));
|
||||
EXPECT_FALSE(filter.Passes("x/y/a"));
|
||||
EXPECT_TRUE(filter.Passes("b"));
|
||||
EXPECT_TRUE(filter.Passes("x/b"));
|
||||
|
||||
filter.SetList({"-a/**/b"});
|
||||
EXPECT_FALSE(filter.Passes("a/b"));
|
||||
EXPECT_FALSE(filter.Passes("a/x/b"));
|
||||
EXPECT_FALSE(filter.Passes("a/x/y/b"));
|
||||
EXPECT_TRUE(filter.Passes("x/a/b"));
|
||||
EXPECT_TRUE(filter.Passes("a/b/x"));
|
||||
|
||||
filter.SetList({"-a/**"});
|
||||
EXPECT_FALSE(filter.Passes("a/x"));
|
||||
EXPECT_FALSE(filter.Passes("a/y"));
|
||||
EXPECT_FALSE(filter.Passes("a/x/y"));
|
||||
EXPECT_TRUE(filter.Passes("a"));
|
||||
EXPECT_TRUE(filter.Passes("b/x"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, LargeGlobs)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a"});
|
||||
EXPECT_FALSE(filter.Passes("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
|
||||
EXPECT_TRUE(filter.Passes("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"));
|
||||
|
||||
filter.SetList({"-/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a/**/a"});
|
||||
EXPECT_FALSE(filter.Passes("/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a"));
|
||||
EXPECT_TRUE(filter.Passes("/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b/b"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, MultipleFilters)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-/path/to/Test*.milk",
|
||||
"/path/to/another\\Test*.milk",
|
||||
"+/path/to/yet/another\\Test*.milk",
|
||||
"-Test*.milk"});
|
||||
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestSome.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/to/another/TestSome.milk"));
|
||||
EXPECT_TRUE(filter.Passes("\\path\\to\\yet\\another\\TestCase.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/of/my/TestPreset.milk"));
|
||||
EXPECT_TRUE(filter.Passes("/another/something/completely/different"));
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistFilter, MatchEverything)
|
||||
{
|
||||
ProjectM::Playlist::Filter filter;
|
||||
|
||||
filter.SetList({"-/**"});
|
||||
|
||||
EXPECT_FALSE(filter.Passes("/path/to/TestSome.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/to/another/TestSome.milk"));
|
||||
EXPECT_FALSE(filter.Passes("\\path\\to\\yet\\another\\TestCase.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/path/of/my/TestPreset.milk"));
|
||||
EXPECT_FALSE(filter.Passes("/another/something/completely/different"));
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
#include "PlaylistCWrapperMock.h"
|
||||
@ -33,4 +33,6 @@ public:
|
||||
MOCK_METHOD(void, PlayPresetIndex, (size_t, bool, bool) );
|
||||
MOCK_METHOD(void, RemoveLastHistoryEntry, ());
|
||||
MOCK_METHOD(void, SetPresetSwitchFailedCallback, (projectm_playlist_preset_switch_failed_event, void*));
|
||||
MOCK_METHOD(class ProjectM::Playlist::Filter&, Filter, ());
|
||||
MOCK_METHOD(size_t, ApplyFilter, ());
|
||||
};
|
||||
|
||||
@ -627,3 +627,50 @@ TEST(projectMPlaylistPlaylist, RemoveLastHistoryEntry)
|
||||
|
||||
EXPECT_EQ(playlist.LastPresetIndex(), 0);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, AddItemWithFilter)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
playlist.Filter().SetList({"-/**/Preset*.milk"});
|
||||
|
||||
EXPECT_FALSE(playlist.AddItem("/some/PresetZ.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_FALSE(playlist.AddItem("/some/PresetA.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_FALSE(playlist.AddItem("/some/other/PresetC.milk", Playlist::InsertAtEnd, false));
|
||||
EXPECT_TRUE(playlist.AddItem("/some/MyFavorite.milk", Playlist::InsertAtEnd, false));
|
||||
|
||||
ASSERT_EQ(playlist.Size(), 1);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, AddPathWithFilter)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
playlist.Filter().SetList({"-**/presets/Test_*.milk"});
|
||||
|
||||
EXPECT_EQ(playlist.AddPath(PROJECTM_PLAYLIST_TEST_DATA_DIR "/presets", 0, true, false), 1);
|
||||
|
||||
ASSERT_EQ(playlist.Size(), 1);
|
||||
}
|
||||
|
||||
|
||||
TEST(projectMPlaylistPlaylist, ApplyFilter)
|
||||
{
|
||||
Playlist playlist;
|
||||
|
||||
// Remove Test_A on load
|
||||
playlist.Filter().SetList({"-Test_A.milk"});
|
||||
|
||||
EXPECT_EQ(playlist.AddPath(PROJECTM_PLAYLIST_TEST_DATA_DIR "/presets", 0, true, false), 3);
|
||||
ASSERT_EQ(playlist.Size(), 3);
|
||||
|
||||
// Apply new filter that only removes Test_B
|
||||
playlist.Filter().SetList({"-Test_B.milk"});
|
||||
|
||||
EXPECT_EQ(playlist.ApplyFilter(), 1);
|
||||
|
||||
// Test_A will not reappear.
|
||||
ASSERT_EQ(playlist.Size(), 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user