Removed the database lib from services as it is still not a service
This commit is contained in:
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, Artist)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_FALSE(Artist::exists(session, 35));
|
||||
EXPECT_FALSE(Artist::exists(session, 0));
|
||||
EXPECT_FALSE(Artist::exists(session, 1));
|
||||
EXPECT_EQ(Artist::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_TRUE(artist.get());
|
||||
EXPECT_FALSE(!artist.get());
|
||||
EXPECT_EQ(artist.get()->getId(), artist.getId());
|
||||
|
||||
EXPECT_TRUE(Artist::exists(session, artist.getId()));
|
||||
EXPECT_EQ(Artist::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
|
||||
artists = Artist::findOrphanIds(session);
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::find(session, Artist::FindParameters {}) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front()->getId(), artist.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
bool visited{};
|
||||
Artist::find(session, Artist::FindParameters{}, [&](const Artist::pointer& a)
|
||||
{
|
||||
visited = true;
|
||||
EXPECT_EQ(a->getId(), artist.getId());
|
||||
});
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_singleTrack)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track.get().modify()->setName("MyTrackName");
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ track->getArtists({TrackArtistLinkType::Artist}) };
|
||||
ASSERT_EQ(artists.size(), 1);
|
||||
EXPECT_EQ(artists.front()->getId(), artist.getId());
|
||||
|
||||
ASSERT_EQ(track->getArtistLinks().size(), 1);
|
||||
auto artistLink{ track->getArtistLinks().front() };
|
||||
EXPECT_EQ(artistLink->getTrack()->getId(), track.getId());
|
||||
EXPECT_EQ(artistLink->getArtist()->getId(), artist.getId());
|
||||
|
||||
ASSERT_EQ(track->getArtists({ TrackArtistLinkType::Artist }).size(), 1);
|
||||
EXPECT_TRUE(track->getArtists({ TrackArtistLinkType::ReleaseArtist }).empty());
|
||||
EXPECT_EQ(track->getArtists({}).size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ track->getArtistIds({TrackArtistLinkType::Artist}) };
|
||||
ASSERT_EQ(artists.size(), 1);
|
||||
EXPECT_EQ(artists.front(), artist.getId());
|
||||
|
||||
ASSERT_EQ(track->getArtistIds({ TrackArtistLinkType::Artist }).size(), 1);
|
||||
EXPECT_TRUE(track->getArtistIds({ TrackArtistLinkType::ReleaseArtist }).empty());
|
||||
EXPECT_EQ(track->getArtistIds({}).size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters{}.setName("MyTrackName").setArtistName("MyArtist")) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters{}.setName("MyTrackName").setArtistName("MyArtistFoo")) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters{}.setName("MyTrackNameFoo").setArtistName("MyArtist")) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setTrack(track->getId())) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_singleTracktMultiRoles)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::ReleaseArtist);
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Writer);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Artist)).results.size(), 1);
|
||||
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::ReleaseArtist)).results.size(), 1);
|
||||
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Writer)).results.size(), 1);
|
||||
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Composer)).results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ track->getArtists({TrackArtistLinkType::Artist}) };
|
||||
ASSERT_EQ(artists.size(), 1);
|
||||
EXPECT_EQ(artists.front()->getId(), artist.getId());
|
||||
|
||||
artists = track->getArtists({ TrackArtistLinkType::ReleaseArtist });
|
||||
ASSERT_EQ(artists.size(), 1);
|
||||
EXPECT_EQ(artists.front()->getId(), artist.getId());
|
||||
|
||||
EXPECT_EQ(track->getArtistLinks().size(), 3);
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist.getId())) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::ReleaseArtist }));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Artist }));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Writer }));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Composer }));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EnumSet<TrackArtistLinkType> types{ TrackArtistLink::findUsedTypes(session, artist.getId()) };
|
||||
EXPECT_TRUE(types.contains(TrackArtistLinkType::ReleaseArtist));
|
||||
EXPECT_TRUE(types.contains(TrackArtistLinkType::Artist));
|
||||
EXPECT_TRUE(types.contains(TrackArtistLinkType::Writer));
|
||||
EXPECT_FALSE(types.contains(TrackArtistLinkType::Composer));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_singleTrackMultiArtists)
|
||||
{
|
||||
ScopedTrack track{ session, "track" };
|
||||
ScopedArtist artist1{ session, "artist1" };
|
||||
ScopedArtist artist2{ session, "artist2" };
|
||||
ASSERT_NE(artist1.getId(), artist2.getId());
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackArtistLink::create(session, track.get(), artist1.get(), TrackArtistLinkType::Artist);
|
||||
TrackArtistLink::create(session, track.get(), artist2.get(), TrackArtistLinkType::Artist);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ track->getArtists({TrackArtistLinkType::Artist}) };
|
||||
ASSERT_EQ(artists.size(), 2);
|
||||
EXPECT_TRUE((artists[0]->getId() == artist1.getId() && artists[1]->getId() == artist2.getId())
|
||||
|| (artists[0]->getId() == artist2.getId() && artists[1]->getId() == artist1.getId()));
|
||||
|
||||
EXPECT_EQ(track->getArtists({}).size(), 2);
|
||||
EXPECT_EQ(track->getArtists({ TrackArtistLinkType::Artist }).size(), 2);
|
||||
EXPECT_TRUE(track->getArtists({ TrackArtistLinkType::ReleaseArtist }).empty());
|
||||
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}).results.size(), 2);
|
||||
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::Random)).results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist1->getId())) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track->getId());
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist2->getId()));
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track->getId());
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist1->getId(), { TrackArtistLinkType::ReleaseArtist }));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist1->getId(), { TrackArtistLinkType::Artist }));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist2->getId(), { TrackArtistLinkType::ReleaseArtist }));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist2->getId(), { TrackArtistLinkType::Artist }));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_findByName)
|
||||
{
|
||||
ScopedArtist artist{ session, "AAA" };
|
||||
ScopedTrack track{ session, "MyTrack" }; // filters does not work on orphans
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
artist.get().modify()->setSortName("ZZZ");
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "N" })).results.empty());
|
||||
|
||||
const auto artistsByAAA{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"A"})) };
|
||||
ASSERT_EQ(artistsByAAA.results.size(), 1);
|
||||
EXPECT_EQ(artistsByAAA.results.front(), artist.getId());
|
||||
|
||||
const auto artistsByZZZ{ Artist::Artist::findIds(session, Artist::FindParameters {}.setKeywords({"Z"})) };
|
||||
ASSERT_EQ(artistsByZZZ.results.size(), 1);
|
||||
EXPECT_EQ(artistsByZZZ.results.front(), artist.getId());
|
||||
|
||||
EXPECT_TRUE(Artist::find(session, "NNN").empty());
|
||||
EXPECT_EQ(Artist::find(session, "AAA").size(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_findByNameEscaped)
|
||||
{
|
||||
ScopedArtist artist1{ session, R"(MyArtist%)" };
|
||||
ScopedArtist artist2{ session, R"(%MyArtist)" };
|
||||
ScopedArtist artist3{ session, R"(%_MyArtist)" };
|
||||
|
||||
ScopedArtist artist4{ session, R"(MyArtist%foo)" };
|
||||
ScopedArtist artist5{ session, R"(foo%MyArtist)" };
|
||||
ScopedArtist artist6{ session, R"(%AMyArtist)" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
{
|
||||
const auto artists{ Artist::find(session, R"(MyArtist%)") };
|
||||
ASSERT_TRUE(artists.size() == 1);
|
||||
EXPECT_EQ(artists.front()->getId(), artist1.getId());
|
||||
EXPECT_TRUE(Artist::find(session, R"(MyArtistFoo)").empty());
|
||||
}
|
||||
{
|
||||
const auto artists{ Artist::find(session, R"(%MyArtist)") };
|
||||
ASSERT_TRUE(artists.size() == 1);
|
||||
EXPECT_EQ(artists.front()->getId(), artist2.getId());
|
||||
EXPECT_TRUE(Artist::find(session, R"(FooMyArtist)").empty());
|
||||
}
|
||||
{
|
||||
const auto artists{ Artist::find(session, R"(%_MyArtist)") };
|
||||
ASSERT_TRUE(artists.size() == 1);
|
||||
ASSERT_EQ(artists.front()->getId(), artist3.getId());
|
||||
EXPECT_TRUE(Artist::find(session, R"(%CMyArtist)").empty());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
{
|
||||
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist"})) };
|
||||
EXPECT_EQ(artists.results.size(), 6);
|
||||
}
|
||||
|
||||
{
|
||||
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist%"}).setSortMethod(ArtistSortMethod::ByName)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], artist1.getId());
|
||||
EXPECT_EQ(artists.results[1], artist4.getId());
|
||||
}
|
||||
|
||||
{
|
||||
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"%MyArtist"}).setSortMethod(ArtistSortMethod::ByName)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], artist2.getId());
|
||||
EXPECT_EQ(artists.results[1], artist5.getId());
|
||||
}
|
||||
|
||||
{
|
||||
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"_MyArtist"}).setSortMethod(ArtistSortMethod::ByName)) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results[0], artist3.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_sortMethod)
|
||||
{
|
||||
ScopedArtist artistA{ session, "artistA" };
|
||||
ScopedArtist artistB{ session, "artistB" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
artistA.get().modify()->setSortName("sortNameB");
|
||||
artistB.get().modify()->setSortName("sortNameA");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto allArtistsByName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::ByName)) };
|
||||
auto allArtistsBySortName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::BySortName)) };
|
||||
|
||||
ASSERT_EQ(allArtistsByName.results.size(), 2);
|
||||
EXPECT_EQ(allArtistsByName.results.front(), artistA.getId());
|
||||
EXPECT_EQ(allArtistsByName.results.back(), artistB.getId());
|
||||
|
||||
ASSERT_EQ(allArtistsBySortName.results.size(), 2);
|
||||
EXPECT_EQ(allArtistsBySortName.results.front(), artistB.getId());
|
||||
EXPECT_EQ(allArtistsBySortName.results.back(), artistA.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_nonReleaseTracks)
|
||||
{
|
||||
ScopedArtist artist{ session, "artist" };
|
||||
ScopedTrack track1{ session, "MyTrack1" };
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setNonRelease(true).setArtist(artist->getId())) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackArtistLink::create(session, track1.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
TrackArtistLink::create(session, track2.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
|
||||
track1.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist.getId()).setNonRelease(true)) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track2.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Artist_findByRelease)
|
||||
{
|
||||
ScopedArtist artist{ session, "artist" };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
add_executable(test-database
|
||||
Artist.cpp
|
||||
Cluster.cpp
|
||||
Common.cpp
|
||||
DatabaseTest.cpp
|
||||
Listen.cpp
|
||||
Release.cpp
|
||||
StarredArtist.cpp
|
||||
StarredRelease.cpp
|
||||
StarredTrack.cpp
|
||||
Track.cpp
|
||||
TrackBookmark.cpp
|
||||
TrackFeatures.cpp
|
||||
TrackList.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(test-database PRIVATE
|
||||
lmsdatabase
|
||||
GTest::GTest
|
||||
)
|
||||
|
||||
if (NOT CMAKE_CROSSCOMPILING)
|
||||
gtest_discover_tests(test-database)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, Cluster)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
EXPECT_EQ(Cluster::getCount(session), 0);
|
||||
EXPECT_EQ(ClusterType::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedClusterType clusterType{ session, "MyType" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
EXPECT_EQ(ClusterType::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
EXPECT_EQ(Cluster::getCount(session), 1);
|
||||
EXPECT_EQ(cluster->getType()->getId(), clusterType.getId());
|
||||
|
||||
{
|
||||
const auto clusters{ Cluster::findIds(session, Cluster::FindParameters {}) };
|
||||
ASSERT_EQ(clusters.results.size(), 1);
|
||||
EXPECT_EQ(clusters.results.front(), cluster.getId());
|
||||
}
|
||||
|
||||
{
|
||||
const auto clusters{ Cluster::findOrphanIds(session) };
|
||||
ASSERT_EQ(clusters.results.size(), 1);
|
||||
EXPECT_EQ(clusters.results.front(), cluster.getId());
|
||||
}
|
||||
|
||||
auto clusterTypes{ ClusterType::findIds(session) };
|
||||
ASSERT_EQ(clusterTypes.results.size(), 1);
|
||||
EXPECT_EQ(clusterTypes.results.front(), clusterType.getId());
|
||||
|
||||
clusterTypes = ClusterType::findUsed(session);
|
||||
ASSERT_EQ(clusterTypes.results.size(), 1);
|
||||
EXPECT_EQ(clusterTypes.results.front(), clusterType.getId());
|
||||
|
||||
clusterTypes = ClusterType::findOrphanIds(session);
|
||||
EXPECT_TRUE(clusterTypes.results.empty());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto clusterTypes{ ClusterType::findOrphanIds(session) };
|
||||
ASSERT_EQ(clusterTypes.results.size(), 1);
|
||||
EXPECT_EQ(clusterTypes.results.front(), clusterType.getId());
|
||||
|
||||
ASSERT_TRUE(ClusterType::findUsed(session).results.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Cluster_singleTrack)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Cluster::findOrphanIds(session).results.empty());
|
||||
auto clusterTypes{ ClusterType::findOrphanIds(session) };
|
||||
ASSERT_EQ(clusterTypes.results.size(), 1);
|
||||
EXPECT_EQ(clusterTypes.results.front(), clusterType.getId());
|
||||
}
|
||||
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "MyCluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "MyCluster2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto clusters{ Cluster::findOrphanIds(session) };
|
||||
EXPECT_EQ(clusters.results.size(), 2);
|
||||
EXPECT_TRUE(track->getClusters().empty());
|
||||
EXPECT_TRUE(track->getClusterIds().empty());
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster1.getId()), 0);
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster2.getId()), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
cluster1.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto clusters{ Cluster::findIds(session, Cluster::FindParameters {}.setTrack(track.getId())) };
|
||||
ASSERT_EQ(clusters.results.size(), 1);
|
||||
EXPECT_EQ(clusters.results.front(), cluster1.getId());
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster1.getId()), 1);
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster2.getId()), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto clusters{ Cluster::findOrphanIds(session) };
|
||||
ASSERT_EQ(clusters.results.size(), 1);
|
||||
EXPECT_EQ(clusters.results.front(), cluster2.getId());
|
||||
|
||||
EXPECT_TRUE(ClusterType::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setClusters({cluster1.getId()})) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setClusters({ cluster2.getId() }));
|
||||
EXPECT_TRUE(tracks.results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto clusters{ track->getClusters() };
|
||||
ASSERT_EQ(clusters.size(), 1);
|
||||
EXPECT_EQ(clusters.front()->getId(), cluster1.getId());
|
||||
|
||||
auto clusterIds{ track->getClusterIds() };
|
||||
ASSERT_EQ(clusterIds.size(), 1);
|
||||
EXPECT_EQ(clusterIds.front(), cluster1.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Cluster_singleTrackWithSeveralClusters)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "MyCluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "MyCluster2" };
|
||||
|
||||
const std::vector<ClusterId> clusterIds{ cluster1.getId(), cluster2.getId() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setClusters(clusterIds)) };
|
||||
EXPECT_TRUE(tracks.results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
cluster1.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setClusters(clusterIds)) };
|
||||
EXPECT_TRUE(tracks.results.empty());
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster1.getId()), 1);
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster2.getId()), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
cluster2.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setClusters(clusterIds)) };
|
||||
ASSERT_FALSE(tracks.results.empty());
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster1.getId()), 1);
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster2.getId()), 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Cluster_multiTracks)
|
||||
{
|
||||
std::list<ScopedTrack> tracks;
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
|
||||
for (std::size_t i{}; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
cluster.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Cluster::findOrphanIds(session).results.empty());
|
||||
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster.getId()), tracks.size());
|
||||
|
||||
for (TrackId trackId : cluster->getTracks().results)
|
||||
{
|
||||
auto it{ std::find_if(std::cbegin(tracks), std::cend(tracks), [&](const ScopedTrack& track) { return trackId == track.getId(); }) };
|
||||
EXPECT_TRUE(it != std::cend(tracks));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(DatabaseFixture, ClusterType_singleTrack)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Cluster::find(session, Cluster::FindParameters{}).results.empty());
|
||||
EXPECT_TRUE(Cluster::find(session, Cluster::FindParameters{}.setClusterTypeName("Foo")).results.empty());
|
||||
}
|
||||
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto clusters {Cluster::findIds(session, Cluster::FindParameters{}).results};
|
||||
ASSERT_EQ(clusters.size(), 1);
|
||||
EXPECT_EQ(clusters.front(), cluster.getId());
|
||||
|
||||
clusters = Cluster::findIds(session, Cluster::FindParameters{}.setClusterType(clusterType.getId())).results;
|
||||
ASSERT_EQ(clusters.size(), 1);
|
||||
EXPECT_EQ(clusters.front(), cluster.getId());
|
||||
|
||||
clusters = Cluster::findIds(session, Cluster::FindParameters{}.setClusterTypeName("Foo")).results;
|
||||
EXPECT_EQ(clusters.size(), 0);
|
||||
|
||||
clusters = Cluster::findIds(session, Cluster::FindParameters{}.setClusterTypeName("MyClusterType")).results;
|
||||
ASSERT_EQ(clusters.size(), 1);
|
||||
EXPECT_EQ(clusters.front(), cluster.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Cluster_singleTrackSingleReleaseSingleCluster)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Cluster::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
ScopedCluster unusedCluster{ session, clusterType.lockAndGet(), "MyClusterUnused" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ASSERT_EQ(Cluster::findOrphanIds(session).results.size(), 2);
|
||||
EXPECT_TRUE(Release::find(session, Release::FindParameters{}.setClusters({ unusedCluster.getId() })).results.empty());
|
||||
EXPECT_EQ(Release::find(session, Release::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(Cluster::computeReleaseCount(session, cluster.getId()), 0);
|
||||
EXPECT_EQ(Cluster::computeReleaseCount(session, unusedCluster.getId()), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track.get().modify()->setRelease(release.get());
|
||||
cluster.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
auto clusters{ Cluster::findOrphanIds(session) };
|
||||
ASSERT_EQ(clusters.results.size(), 1);
|
||||
EXPECT_EQ(clusters.results.front(), unusedCluster.getId());
|
||||
}
|
||||
EXPECT_EQ(Cluster::computeReleaseCount(session, cluster.getId()), 1);
|
||||
EXPECT_EQ(Cluster::computeReleaseCount(session, unusedCluster.getId()), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto clusters{ Cluster::findIds(session, Cluster::FindParameters{}.setRelease(release.getId())) };
|
||||
ASSERT_EQ(clusters.results.size(), 1);
|
||||
EXPECT_EQ(clusters.results.front(), cluster.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setClusters({unusedCluster.getId()})) };
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(Cluster::computeReleaseCount(session, cluster.getId()), 1);
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, cluster.getId()), 1);
|
||||
EXPECT_EQ(Cluster::computeReleaseCount(session, unusedCluster.getId()), 0);
|
||||
EXPECT_EQ(Cluster::computeTrackCount(session, unusedCluster.getId()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackSingleArtistMultiClusters)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedClusterType clusterType{ session, "MyType" };
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "Cluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "Cluster2" };
|
||||
ScopedCluster cluster3{ session, clusterType.lockAndGet(), "Cluster3" };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto trackArtistLink{ TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist) };
|
||||
cluster1.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(ClusterType::findOrphanIds(session).results.empty());
|
||||
EXPECT_EQ(Cluster::findOrphanIds(session).results.size(), 2);
|
||||
EXPECT_TRUE(Release::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getClusters().size(), 1);
|
||||
EXPECT_EQ(track->getClusterIds().size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster1.getId()})) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
|
||||
EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster2.getId() })).results.empty());
|
||||
EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster3.getId() })).results.empty());
|
||||
|
||||
cluster2.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster1.getId()})) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster2.getId() }));
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster1.getId() }));
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
|
||||
EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster3.getId() })).results.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackSingleArtistMultiRolesMultiClusters)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedClusterType clusterType{ session, "MyType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::ReleaseArtist);
|
||||
cluster.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Cluster::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Release::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultiTracksSingleArtistMultiClusters)
|
||||
{
|
||||
constexpr std::size_t nbTracks{ 10 };
|
||||
constexpr std::size_t nbClusters{ 5 };
|
||||
|
||||
std::list<ScopedTrack> tracks;
|
||||
std::list<ScopedCluster> clusters;
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedClusterType clusterType{ session, "MyType" };
|
||||
|
||||
for (std::size_t i{}; i < nbClusters; ++i)
|
||||
clusters.emplace_back(session, clusterType.lockAndGet(), "MyCluster" + std::to_string(i));
|
||||
|
||||
for (std::size_t i{}; i < nbTracks; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrackFile" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
TrackArtistLink::create(session, tracks.back().get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
|
||||
for (auto& cluster : clusters)
|
||||
cluster.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Cluster::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
std::vector<ClusterId> clusterIds;
|
||||
std::transform(std::cbegin(clusters), std::cend(clusters), std::back_inserter(clusterIds), [](const ScopedCluster& cluster) { return cluster.getId(); });
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(clusterIds)) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracksSingleClusterSimilarity)
|
||||
{
|
||||
std::list<ScopedTrack> tracks;
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyClusterType" };
|
||||
|
||||
for (std::size_t i{}; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
cluster.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.front().getId()}) };
|
||||
EXPECT_EQ(similarTracks.results.size(), tracks.size() - 1);
|
||||
for (const TrackId similarTrackId : similarTracks.results)
|
||||
{
|
||||
EXPECT_TRUE(std::find_if(std::next(std::cbegin(tracks), 1), std::cend(tracks), [&](const auto& track) { return similarTrackId == track.getId(); }) != std::cend(tracks));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracksMultipleClustersSimilarity)
|
||||
{
|
||||
std::list<ScopedTrack> tracks;
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "MyCluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "MyCluster2" };
|
||||
|
||||
for (std::size_t i{}; i < 5; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
cluster1.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i{ 5 }; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
cluster1.get().modify()->addTrack(tracks.back().get());
|
||||
cluster2.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.back().getId()}, Range {0, 4}) };
|
||||
EXPECT_EQ(similarTracks.results.size(), 4);
|
||||
for (const TrackId similarTrackId : similarTracks.results)
|
||||
EXPECT_TRUE(std::find_if(std::next(std::cbegin(tracks), 5), std::next(std::cend(tracks), -1), [&](const auto& track) { return similarTrackId == track.getId(); }) != std::cend(tracks));
|
||||
}
|
||||
|
||||
{
|
||||
auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.front().getId()}) };
|
||||
EXPECT_EQ(similarTracks.results.size(), tracks.size() - 1);
|
||||
for (const TrackId similarTrackId : similarTracks.results)
|
||||
EXPECT_TRUE(std::find_if(std::next(std::cbegin(tracks), 1), std::cend(tracks), [&](const auto& track) { return similarTrackId == track.getId(); }) != std::cend(tracks));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtistSingleCluster)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedClusterType clusterType{ session, "MyType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
track.get().modify()->setRelease(release.get());
|
||||
cluster.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_TRUE(Cluster::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(ClusterType::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Release::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist.getId());
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId()).setClusters({ cluster.getId() }));
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtistMultiClusters)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "MyCluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "MyCluster2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto trackArtistLink{ TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist) };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
cluster1.get().modify()->addTrack(track.get());
|
||||
cluster2.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId()).setClusters({ cluster1.getId(), cluster2.getId() }));
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListMultipleTrackSingleCluster)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MyTrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
std::list<ScopedTrack> tracks;
|
||||
|
||||
for (std::size_t i{}; i < 20; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
if (i < 5)
|
||||
session.create<TrackListEntry>(tracks.back().get(), trackList.get());
|
||||
|
||||
if (i < 10)
|
||||
cluster.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto similarTracks{ trackList->getSimilarTracks() };
|
||||
EXPECT_EQ(similarTracks.size(), 5);
|
||||
|
||||
for (auto similarTrack : similarTracks)
|
||||
EXPECT_TRUE(std::any_of(std::next(std::cbegin(tracks), 5), std::cend(tracks), [similarTrack](const ScopedTrack& track) { return track.getId() == similarTrack->getId(); }));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListMultipleTrackMultiClusters)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MyTrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "MyCluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "MyCluster2" };
|
||||
std::list<ScopedTrack> tracks;
|
||||
|
||||
for (std::size_t i{}; i < 20; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
if (i < 5)
|
||||
session.create<TrackListEntry>(tracks.back().get(), trackList.get());
|
||||
|
||||
if (i < 10)
|
||||
{
|
||||
cluster1.get().modify()->addTrack(tracks.back().get());
|
||||
cluster2.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
else if (i < 15)
|
||||
{
|
||||
cluster1.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
const auto similarTracks{ trackList->getSimilarTracks(0, 5) };
|
||||
ASSERT_EQ(similarTracks.size(), 5);
|
||||
|
||||
for (auto similarTrack : similarTracks)
|
||||
EXPECT_TRUE(std::any_of(std::next(std::cbegin(tracks), 5), std::next(std::cbegin(tracks), 10), [similarTrack](const ScopedTrack& track) { return track.getId() == similarTrack->getId(); }));
|
||||
}
|
||||
|
||||
{
|
||||
const auto similarTracks{ trackList->getSimilarTracks(5, 10) };
|
||||
ASSERT_EQ(similarTracks.size(), 5);
|
||||
|
||||
for (auto similarTrack : similarTracks)
|
||||
EXPECT_TRUE(std::any_of(std::next(std::cbegin(tracks), 10), std::next(std::cbegin(tracks), 15), [similarTrack](const ScopedTrack& track) { return track.getId() == similarTrack->getId(); }));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(trackList->getSimilarTracks(10, 10).empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracksMultipleArtistsMultiClusters)
|
||||
{
|
||||
ScopedArtist artist1{ session, "MyArtist1" };
|
||||
ScopedArtist artist2{ session, "MyArtist2" };
|
||||
ScopedArtist artist3{ session, "MyArtist3" };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "MyCluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "MyCluster2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(artist1->findSimilarArtistIds().results.empty());
|
||||
EXPECT_TRUE(artist2->findSimilarArtistIds().results.empty());
|
||||
EXPECT_TRUE(artist3->findSimilarArtistIds().results.empty());
|
||||
}
|
||||
|
||||
std::list<ScopedTrack> tracks;
|
||||
for (std::size_t i{}; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
if (i < 5)
|
||||
TrackArtistLink::create(session, tracks.back().get(), artist1.get(), TrackArtistLinkType::Artist);
|
||||
else
|
||||
{
|
||||
TrackArtistLink::create(session, tracks.back().get(), artist2.get(), TrackArtistLinkType::Artist);
|
||||
cluster2.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
cluster1.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(tracks.size()));
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
TrackArtistLink::create(session, tracks.back().get(), artist3.get(), TrackArtistLinkType::Artist);
|
||||
cluster2.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
auto artists{ artist1->findSimilarArtistIds() };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist}) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::ReleaseArtist}) };
|
||||
EXPECT_EQ(artists.results.empty(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}) };
|
||||
ASSERT_EQ(artists.results.size(), 1);
|
||||
EXPECT_EQ(artists.results.front(), artist2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Composer}) };
|
||||
EXPECT_TRUE(artists.results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto artists{ artist2->findSimilarArtistIds() };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], artist1.getId());
|
||||
EXPECT_EQ(artists.results[1], artist3.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracksMultipleReleasesMultiClusters)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
ScopedRelease release3{ session, "MyRelease3" };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster1{ session, clusterType.lockAndGet(), "MyCluster1" };
|
||||
ScopedCluster cluster2{ session, clusterType.lockAndGet(), "MyCluster2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(release1->getSimilarReleases().empty());
|
||||
EXPECT_TRUE(release2->getSimilarReleases().empty());
|
||||
EXPECT_TRUE(release3->getSimilarReleases().empty());
|
||||
}
|
||||
|
||||
std::list<ScopedTrack> tracks;
|
||||
for (std::size_t i{}; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
if (i < 5)
|
||||
tracks.back().get().modify()->setRelease(release1.get());
|
||||
else
|
||||
{
|
||||
tracks.back().get().modify()->setRelease(release2.get());
|
||||
cluster2.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
cluster1.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(tracks.size()));
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
tracks.back().get().modify()->setRelease(release3.get());
|
||||
cluster2.get().modify()->addTrack(tracks.back().get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
auto releases{ release1->getSimilarReleases() };
|
||||
ASSERT_EQ(releases.size(), 1);
|
||||
EXPECT_EQ(releases.front()->getId(), release2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto releases{ release2->getSimilarReleases() };
|
||||
ASSERT_EQ(releases.size(), 2);
|
||||
EXPECT_EQ(releases[0]->getId(), release1.getId());
|
||||
EXPECT_EQ(releases[1]->getId(), release3.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
#include "database/Artist.hpp"
|
||||
#include "database/Cluster.hpp"
|
||||
#include "database/Db.hpp"
|
||||
#include "database/Listen.hpp"
|
||||
#include "database/Release.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/StarredArtist.hpp"
|
||||
#include "database/StarredRelease.hpp"
|
||||
#include "database/StarredTrack.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackArtistLink.hpp"
|
||||
#include "database/TrackBookmark.hpp"
|
||||
#include "database/TrackList.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
TmpDatabase::TmpDatabase()
|
||||
: _tmpFile{ std::tmpnam(nullptr) }
|
||||
, _fileDeleter{ _tmpFile }
|
||||
, _db{ _tmpFile }
|
||||
{
|
||||
}
|
||||
|
||||
Database::Db& TmpDatabase::getDb()
|
||||
{
|
||||
return _db;
|
||||
}
|
||||
|
||||
DatabaseFixture::~DatabaseFixture()
|
||||
{
|
||||
testDatabaseEmpty();
|
||||
}
|
||||
|
||||
void DatabaseFixture::SetUpTestCase()
|
||||
{
|
||||
_tmpDb = std::make_unique<TmpDatabase>();
|
||||
{
|
||||
Database::Session s{ _tmpDb->getDb() };
|
||||
s.prepareTables();
|
||||
s.analyze();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseFixture::TearDownTestCase()
|
||||
{
|
||||
_tmpDb.reset();
|
||||
}
|
||||
|
||||
void DatabaseFixture::testDatabaseEmpty()
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
EXPECT_EQ(Artist::getCount(session), 0);
|
||||
EXPECT_EQ(Cluster::getCount(session), 0);
|
||||
EXPECT_EQ(ClusterType::getCount(session), 0);
|
||||
EXPECT_EQ(Listen::getCount(session), 0);
|
||||
EXPECT_EQ(Release::getCount(session), 0);
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 0);
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 0);
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 0);
|
||||
EXPECT_EQ(Track::getCount(session), 0);
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 0);
|
||||
EXPECT_EQ(TrackList::getCount(session), 0);
|
||||
EXPECT_EQ(User::getCount(session), 0);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRangeEmpty)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
RangeResults<int> results;
|
||||
results.range = Range{ 0, 0 };
|
||||
results.results = {};
|
||||
results.moreResults = false;
|
||||
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {0, 0}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 0);
|
||||
EXPECT_EQ(subRange.range, Range{});
|
||||
}
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {0, 1}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRangeForeach)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
struct TestCase
|
||||
{
|
||||
Range range;
|
||||
std::size_t subRangeSize;
|
||||
std::vector<Range> expectedSubRanges;
|
||||
};
|
||||
|
||||
TestCase testCases[]
|
||||
{
|
||||
{Range{0, 0}, 1, {}},
|
||||
{Range{1, 0}, 1, {}},
|
||||
{Range{1, 1}, 1, { Range{ 1,1 } }},
|
||||
{Range{1, 3}, 1, { Range{ 1,1 }, Range {2,1}, Range{3,1} }},
|
||||
{Range{0, 100}, 100, { Range{0,100} }},
|
||||
{Range{0, 50}, 100, { Range{0,50} }},
|
||||
{Range{100, 200}, 100, { Range{100,100}, Range{200,100} }},
|
||||
{Range{100, 101}, 100, { Range{100,100}, Range{200,1}}},
|
||||
{Range{1000, 10}, 100, { Range{1000,10} }},
|
||||
{Range{1, 100}, 50, { Range{1,50}, Range{51, 50} }},
|
||||
};
|
||||
|
||||
for (const TestCase& test : testCases)
|
||||
{
|
||||
std::vector<Range> subRanges;
|
||||
foreachSubRange(test.range, test.subRangeSize, [&](Range subRange)
|
||||
{
|
||||
subRanges.push_back(subRange);
|
||||
return true;
|
||||
});
|
||||
|
||||
EXPECT_EQ(subRanges, test.expectedSubRanges) << ", test index = " << std::distance(std::cbegin(testCases), &test);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_IdType)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
{
|
||||
const IdType id{};
|
||||
EXPECT_FALSE(id.isValid());
|
||||
}
|
||||
|
||||
{
|
||||
const IdType id{ 0 };
|
||||
EXPECT_TRUE(id.isValid());
|
||||
}
|
||||
|
||||
{
|
||||
const IdType id1{ 0 };
|
||||
const IdType id2{ 0 };
|
||||
EXPECT_EQ(id1, id2);
|
||||
}
|
||||
|
||||
{
|
||||
const IdType id1{ 0 };
|
||||
const IdType id2{ 1 };
|
||||
EXPECT_NE(id1, id2);
|
||||
EXPECT_LT(id1, id2);
|
||||
EXPECT_GT(id2, id1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRange)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
RangeResults<int> results;
|
||||
results.range = Range{ 0, 2 };
|
||||
results.results = { 5, 6 };
|
||||
results.moreResults = false;
|
||||
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {0, 1}) };
|
||||
EXPECT_TRUE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 1);
|
||||
EXPECT_EQ(subRange.results.front(), 5);
|
||||
}
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {1, 1}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 1);
|
||||
EXPECT_EQ(subRange.results.front(), 6);
|
||||
}
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {0, 2}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 2);
|
||||
EXPECT_EQ(subRange.results.front(), 5);
|
||||
EXPECT_EQ(subRange.results.back(), 6);
|
||||
}
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 2);
|
||||
EXPECT_EQ(subRange.results.front(), 5);
|
||||
EXPECT_EQ(subRange.results.back(), 6);
|
||||
EXPECT_EQ(subRange.range, results.range);
|
||||
}
|
||||
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {1, 0}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 1);
|
||||
EXPECT_EQ(subRange.results.front(), 6);
|
||||
const Range expectedRange{ 1, 1 };
|
||||
EXPECT_EQ(subRange.range, expectedRange);
|
||||
}
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {3, 2}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 0);
|
||||
const Range expectedRange{ 2, 0 };
|
||||
EXPECT_EQ(subRange.range, expectedRange);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "database/Artist.hpp"
|
||||
#include "database/Cluster.hpp"
|
||||
#include "database/Db.hpp"
|
||||
#include "database/Listen.hpp"
|
||||
#include "database/Release.hpp"
|
||||
#include "database/ScanSettings.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/TrackArtistLink.hpp"
|
||||
#include "database/TrackBookmark.hpp"
|
||||
#include "database/TrackFeatures.hpp"
|
||||
#include "database/TrackList.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
template <typename T>
|
||||
class ScopedEntity
|
||||
{
|
||||
public:
|
||||
using IdType = typename T::IdType;
|
||||
|
||||
template <typename... Args>
|
||||
ScopedEntity(Database::Session& session, Args&& ...args)
|
||||
: _session {session}
|
||||
{
|
||||
auto transaction {_session.createWriteTransaction()};
|
||||
|
||||
auto entity {_session.create<T>(std::forward<Args>(args)...)};
|
||||
EXPECT_TRUE(entity);
|
||||
_id = entity->getId();
|
||||
}
|
||||
|
||||
~ScopedEntity()
|
||||
{
|
||||
auto transaction {_session.createWriteTransaction()};
|
||||
|
||||
auto entity {T::find(_session, _id)};
|
||||
// could not be here due to "on delete cascade" constraints...
|
||||
if (entity)
|
||||
entity.remove();
|
||||
}
|
||||
|
||||
ScopedEntity(const ScopedEntity&) = delete;
|
||||
ScopedEntity(ScopedEntity&&) = delete;
|
||||
ScopedEntity& operator=(const ScopedEntity&) = delete;
|
||||
ScopedEntity& operator=(ScopedEntity&&) = delete;
|
||||
|
||||
typename T::pointer lockAndGet()
|
||||
{
|
||||
auto transaction {_session.createReadTransaction()};
|
||||
return get();
|
||||
}
|
||||
|
||||
typename T::pointer get()
|
||||
{
|
||||
_session.checkReadTransaction();
|
||||
|
||||
auto entity {T::find(_session, _id)};
|
||||
EXPECT_TRUE(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
typename T::pointer operator->()
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
IdType getId() const { return _id; }
|
||||
|
||||
private:
|
||||
Database::Session& _session;
|
||||
IdType _id {};
|
||||
};
|
||||
|
||||
using ScopedArtist = ScopedEntity<Database::Artist>;
|
||||
using ScopedCluster = ScopedEntity<Database::Cluster>;
|
||||
using ScopedClusterType = ScopedEntity<Database::ClusterType>;
|
||||
using ScopedRelease = ScopedEntity<Database::Release>;
|
||||
using ScopedTrack = ScopedEntity<Database::Track>;
|
||||
using ScopedTrackList = ScopedEntity<Database::TrackList>;
|
||||
using ScopedUser = ScopedEntity<Database::User>;
|
||||
|
||||
class ScopedFileDeleter final
|
||||
{
|
||||
public:
|
||||
ScopedFileDeleter(const std::filesystem::path& path) : _path {path} {}
|
||||
~ScopedFileDeleter() { std::filesystem::remove(_path); }
|
||||
|
||||
ScopedFileDeleter(const ScopedFileDeleter&) = delete;
|
||||
ScopedFileDeleter(ScopedFileDeleter&&) = delete;
|
||||
ScopedFileDeleter operator=(const ScopedFileDeleter&) = delete;
|
||||
ScopedFileDeleter operator=(ScopedFileDeleter&&) = delete;
|
||||
|
||||
private:
|
||||
const std::filesystem::path _path;
|
||||
};
|
||||
|
||||
class TmpDatabase final
|
||||
{
|
||||
public:
|
||||
TmpDatabase ();
|
||||
|
||||
Database::Db& getDb();
|
||||
|
||||
private:
|
||||
const std::filesystem::path _tmpFile;
|
||||
ScopedFileDeleter _fileDeleter;
|
||||
Database::Db _db;
|
||||
};
|
||||
|
||||
class DatabaseFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
~DatabaseFixture();
|
||||
|
||||
public:
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
private:
|
||||
void testDatabaseEmpty();
|
||||
|
||||
static inline std::unique_ptr<TmpDatabase> _tmpDb {};
|
||||
|
||||
public:
|
||||
Database::Session session {_tmpDb->getDb()};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, MultiTracksSingleArtistSingleRelease)
|
||||
{
|
||||
constexpr std::size_t nbTracks{ 10 };
|
||||
std::list<ScopedTrack> tracks;
|
||||
ScopedArtist artist{ session, "MyArtst" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
for (std::size_t i{}; i < nbTracks; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackArtistLink::create(session, tracks.back().get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
tracks.back().get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Release::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
const auto releaseTracks{ Track::find(session, Track::FindParameters {}.setRelease(release.getId())) };
|
||||
EXPECT_EQ(releaseTracks.results.size(), nbTracks);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtist)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto trackArtistLink{ TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist) };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
auto artists{ release->getArtists() };
|
||||
ASSERT_EQ(artists.size(), 1);
|
||||
ASSERT_EQ(artists.front()->getId(), artist.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleUser)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(User::find(session, User::FindParameters{}).results.empty());
|
||||
EXPECT_EQ(User::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(User::find(session, User::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(User::getCount(session), 1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, Release)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(Release::getCount(session), 0);
|
||||
EXPECT_EQ(Release::getCount(session, Release::FindParameters{}), 0);
|
||||
EXPECT_FALSE(Release::exists(session, 0));
|
||||
EXPECT_FALSE(Release::exists(session, 1));
|
||||
}
|
||||
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(Release::getCount(session), 1);
|
||||
EXPECT_EQ(Release::getCount(session, Release::FindParameters{}), 1);
|
||||
EXPECT_TRUE(Release::exists(session, release.getId()));
|
||||
|
||||
{
|
||||
const auto releases{ Release::findOrphanIds(session) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
}
|
||||
|
||||
{
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
EXPECT_EQ(release->getDuration(), std::chrono::seconds{ 0 });
|
||||
}
|
||||
|
||||
{
|
||||
const auto releases{ Release::find(session, Release::FindParameters {}) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front()->getId(), release.getId());
|
||||
}
|
||||
|
||||
{
|
||||
bool visited{};
|
||||
Release::find(session, Release::FindParameters{}, [&](const Release::pointer& r)
|
||||
{
|
||||
visited = true;
|
||||
EXPECT_EQ(r->getId(), release.getId());
|
||||
});
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_singleTrack)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track.get().modify()->setRelease(release.get());
|
||||
track.get().modify()->setName("MyTrackName");
|
||||
release.get().modify()->setName("MyReleaseName");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Release::findOrphanIds(session).results.empty());
|
||||
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release.getId())) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
ASSERT_TRUE(track->getRelease());
|
||||
EXPECT_EQ(track->getRelease()->getId(), release.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters{}.setName("MyTrackName").setReleaseName("MyReleaseName")) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters{}.setName("MyTrackName").setReleaseName("MyReleaseFoo")) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters{}.setName("MyTrackFoo").setReleaseName("MyReleaseName")) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release.getId())) };
|
||||
EXPECT_TRUE(tracks.results.empty());
|
||||
|
||||
auto releases{ Release::findOrphanIds(session) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_findByNameAndPath)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease" };
|
||||
ScopedRelease release2{ session, "MyRelease" };
|
||||
ScopedTrack track1{ session, "MyTrack" };
|
||||
ScopedTrack track2{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track1.get().modify()->setRelease(release1.get());
|
||||
track1.get().modify()->setPath("/tmp/foo/foo.mp3");
|
||||
|
||||
track2.get().modify()->setRelease(release2.get());
|
||||
track2.get().modify()->setPath("/tmp/bar/bar.mp3");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
{
|
||||
const auto releases{ Release::find(session, "MyRelease", "/tmp/foo") };
|
||||
ASSERT_EQ(releases.size(), 1);
|
||||
EXPECT_EQ(releases.front()->getId(), release1.getId());
|
||||
}
|
||||
|
||||
{
|
||||
const auto releases{ Release::find(session, "MyRelease", "/tmp/bar") };
|
||||
ASSERT_EQ(releases.size(), 1);
|
||||
EXPECT_EQ(releases.front()->getId(), release2.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MulitpleReleaseSearchByName)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease" };
|
||||
ScopedRelease release2{ session, "MyRelease%" };
|
||||
ScopedRelease release3{ session, "%MyRelease" };
|
||||
ScopedRelease release4{ session, "MyRelease%Foo" };
|
||||
ScopedRelease release5{ session, "Foo%MyRelease" };
|
||||
ScopedRelease release6{ session, "_yRelease" };
|
||||
|
||||
// filters does not work on orphans
|
||||
ScopedTrack track1{ session, "MyTrack" };
|
||||
ScopedTrack track2{ session, "MyTrack" };
|
||||
ScopedTrack track3{ session, "MyTrack" };
|
||||
ScopedTrack track4{ session, "MyTrack" };
|
||||
ScopedTrack track5{ session, "MyTrack" };
|
||||
ScopedTrack track6{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track1.get().modify()->setRelease(release1.get());
|
||||
track2.get().modify()->setRelease(release2.get());
|
||||
track3.get().modify()->setRelease(release3.get());
|
||||
track4.get().modify()->setRelease(release4.get());
|
||||
track5.get().modify()->setRelease(release5.get());
|
||||
track6.get().modify()->setRelease(release6.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"Release"})) };
|
||||
EXPECT_EQ(releases.results.size(), 6);
|
||||
}
|
||||
|
||||
{
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease"})) };
|
||||
ASSERT_EQ(releases.results.size(), 5);
|
||||
EXPECT_TRUE(std::none_of(std::cbegin(releases.results), std::cend(releases.results), [&](const ReleaseId releaseId) { return releaseId == release6.getId(); }));
|
||||
}
|
||||
{
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease%"})) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], release2.getId());
|
||||
EXPECT_EQ(releases.results[1], release4.getId());
|
||||
}
|
||||
{
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"%MyRelease"})) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], release3.getId());
|
||||
EXPECT_EQ(releases.results[1], release5.getId());
|
||||
}
|
||||
{
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"Foo%MyRelease"})) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results[0], release5.getId());
|
||||
}
|
||||
{
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease%Foo"})) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results[0], release4.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultiTracksSingleReleaseTotalDiscTrack)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_FALSE(release1->getTotalDisc());
|
||||
}
|
||||
|
||||
ScopedTrack track1{ session, "MyTrack" };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track1.get().modify()->setRelease(release1.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_FALSE(release1->getTotalDisc());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track1.get().modify()->setTotalTrack(36);
|
||||
release1.get().modify()->setTotalDisc(6);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
ASSERT_TRUE(track1->getTotalTrack());
|
||||
EXPECT_EQ(*track1->getTotalTrack(), 36);
|
||||
ASSERT_TRUE(release1->getTotalDisc());
|
||||
EXPECT_EQ(*release1->getTotalDisc(), 6);
|
||||
}
|
||||
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track2.get().modify()->setRelease(release1.get());
|
||||
track2.get().modify()->setTotalTrack(37);
|
||||
release1.get().modify()->setTotalDisc(67);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
ASSERT_TRUE(track1->getTotalTrack());
|
||||
EXPECT_EQ(*track1->getTotalTrack(), 36);
|
||||
ASSERT_TRUE(release1->getTotalDisc());
|
||||
EXPECT_EQ(*release1->getTotalDisc(), 67);
|
||||
}
|
||||
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_FALSE(release2->getTotalDisc());
|
||||
}
|
||||
|
||||
ScopedTrack track3{ session, "MyTrack3" };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track3.get().modify()->setRelease(release2.get());
|
||||
track3.get().modify()->setTotalTrack(7);
|
||||
release2.get().modify()->setTotalDisc(5);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
ASSERT_TRUE(track1->getTotalTrack());
|
||||
EXPECT_EQ(*track1->getTotalTrack(), 36);
|
||||
ASSERT_TRUE(release1->getTotalDisc());
|
||||
EXPECT_EQ(*release2->getTotalDisc(), 5);
|
||||
ASSERT_TRUE(track3->getTotalTrack());
|
||||
EXPECT_EQ(*track3->getTotalTrack(), 7);
|
||||
ASSERT_TRUE(release2->getTotalDisc());
|
||||
EXPECT_EQ(*release2->getTotalDisc(), 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultiTracksSingleReleaseFirstTrack)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
|
||||
ScopedTrack track1A{ session, "MyTrack1A" };
|
||||
ScopedTrack track1B{ session, "MyTrack1B" };
|
||||
ScopedTrack track2A{ session, "MyTrack2A" };
|
||||
ScopedTrack track2B{ session, "MyTrack2B" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_TRUE(Track::findIds(session, Track::FindParameters{}.setRelease(release1.getId())).results.empty());
|
||||
EXPECT_TRUE(Track::findIds(session, Track::FindParameters{}.setRelease(release2.getId())).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track1A.get().modify()->setRelease(release1.get());
|
||||
track1B.get().modify()->setRelease(release1.get());
|
||||
track2A.get().modify()->setRelease(release2.get());
|
||||
track2B.get().modify()->setRelease(release2.get());
|
||||
|
||||
track1A.get().modify()->setTrackNumber(1);
|
||||
track1B.get().modify()->setTrackNumber(2);
|
||||
|
||||
track2A.get().modify()->setDiscNumber(2);
|
||||
track2A.get().modify()->setTrackNumber(1);
|
||||
track2B.get().modify()->setTrackNumber(2);
|
||||
track2B.get().modify()->setDiscNumber(1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release1.getId()).setSortMethod(TrackSortMethod::Release)) };
|
||||
ASSERT_FALSE(tracks.results.empty());
|
||||
EXPECT_EQ(tracks.results.front(), track1A.getId());
|
||||
}
|
||||
|
||||
{
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release2.getId()).setSortMethod(TrackSortMethod::Release)) };
|
||||
ASSERT_FALSE(tracks.results.empty());
|
||||
EXPECT_EQ(tracks.results.front(), track2B.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultiTracksSingleReleaseDate)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
const Wt::WDate release1Date{ Wt::WDate {1994, 2, 3} };
|
||||
const Wt::WDate release1OriginalDate{ Wt::WDate {1993, 4, 5} };
|
||||
|
||||
ScopedTrack track1A{ session, "MyTrack1A" };
|
||||
ScopedTrack track1B{ session, "MyTrack1B" };
|
||||
ScopedTrack track2A{ session, "MyTrack2A" };
|
||||
ScopedTrack track2B{ session, "MyTrack2B" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(0, 3000))) };
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track1A.get().modify()->setRelease(release1.get());
|
||||
track1B.get().modify()->setRelease(release1.get());
|
||||
track2A.get().modify()->setRelease(release2.get());
|
||||
track2B.get().modify()->setRelease(release2.get());
|
||||
|
||||
|
||||
track1A.get().modify()->setDate(release1Date);
|
||||
track1B.get().modify()->setDate(release1Date);
|
||||
track1A.get().modify()->setOriginalDate(release1OriginalDate);
|
||||
track1B.get().modify()->setOriginalDate(release1OriginalDate);
|
||||
|
||||
EXPECT_EQ(release1.get()->getReleaseDate(), release1Date);
|
||||
EXPECT_EQ(release1.get()->getOriginalReleaseDate(), release1OriginalDate);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(1950, 2000))) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release1.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(1994, 1994)));
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release1.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(1993, 1993)));
|
||||
ASSERT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_writtenAfter)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setLastWriteTime(dateTime);
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setWrittenAfter(dateTime.addSecs(-1))) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) };
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_artist)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedArtist artist2{ session, "MyArtist2" };
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId(), {TrackArtistLinkType::Artist})) };
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist2.getId(), { TrackArtistLinkType::Artist }));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId(), {TrackArtistLinkType::Artist})) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Artist, TrackArtistLinkType::Mixer }));
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist2.getId(), { TrackArtistLinkType::Artist }));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist2.getId()));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::ReleaseArtist, TrackArtistLinkType::Artist }));
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId()));
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Composer }));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Composer, TrackArtistLinkType::Mixer }));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), {}, { TrackArtistLinkType::Artist }));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
|
||||
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), {}, { TrackArtistLinkType::Artist, TrackArtistLinkType::Composer }));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_getDiscCount)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release.get()->getDiscCount(), 0);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release.get()->getDiscCount(), 0);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setDiscNumber(5);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release.get()->getDiscCount(), 1);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track2.get().modify()->setRelease(release.get());
|
||||
track2.get().modify()->setDiscNumber(5);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release.get()->getDiscCount(), 1);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track2.get().modify()->setDiscNumber(6);
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release.get()->getDiscCount(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_releaseType)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release.get()->getPrimaryType(), std::nullopt);
|
||||
EXPECT_EQ(release.get()->getSecondaryTypes(), EnumSet<ReleaseTypeSecondary> {});
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
release.get().modify()->setPrimaryType({ ReleaseTypePrimary::Album });
|
||||
release.get().modify()->setSecondaryTypes({ ReleaseTypeSecondary::Compilation });
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release.get()->getPrimaryType(), ReleaseTypePrimary::Album);
|
||||
EXPECT_TRUE(release.get()->getSecondaryTypes().contains(ReleaseTypeSecondary::Compilation));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_sortMethod)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
const Wt::WDate release1Date{ Wt::WDate {2000, 2, 3} };
|
||||
const Wt::WDate release1OriginalDate{ Wt::WDate {1993, 4, 5} };
|
||||
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
const Wt::WDate release2Date{ Wt::WDate {1994, 2, 3} };
|
||||
|
||||
ScopedTrack track1{ session, "MyTrack1" };
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
|
||||
ASSERT_LT(release2Date, release1Date);
|
||||
ASSERT_GT(release2Date, release1OriginalDate);
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
track1.get().modify()->setRelease(release1.get());
|
||||
track1.get().modify()->setOriginalDate(release1OriginalDate);
|
||||
track1.get().modify()->setDate(release1Date);
|
||||
|
||||
track2.get().modify()->setRelease(release2.get());
|
||||
track2.get().modify()->setDate(release2Date);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Name)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results.front(), release1.getId());
|
||||
EXPECT_EQ(releases.results.back(), release2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Random)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Date)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results.front(), release2.getId());
|
||||
EXPECT_EQ(releases.results.back(), release1.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::OriginalDate)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results.front(), release1.getId());
|
||||
EXPECT_EQ(releases.results.back(), release2.getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::OriginalDateDesc)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results.front(), release2.getId());
|
||||
EXPECT_EQ(releases.results.back(), release1.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Release_meanBitrate)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
ScopedTrack track1{ session, "MyTrack1" };
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
ScopedTrack track3{ session, "MyTrack3" };
|
||||
|
||||
auto checkExpectedBitrate = [&](std::size_t bitrate)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(release1->getMeanBitrate(), bitrate);
|
||||
};
|
||||
|
||||
checkExpectedBitrate(0);
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track1.get().modify()->setBitrate(128);
|
||||
track1.get().modify()->setRelease(release1.get());
|
||||
}
|
||||
|
||||
checkExpectedBitrate(128);
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track2.get().modify()->setBitrate(256);
|
||||
track2.get().modify()->setRelease(release1.get());
|
||||
}
|
||||
checkExpectedBitrate(192);
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track3.get().modify()->setBitrate(0);
|
||||
track3.get().modify()->setRelease(release1.get());
|
||||
}
|
||||
checkExpectedBitrate(192); // 0 should not be taken into account
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
#include "database/StarredArtist.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
using ScopedStarredArtist = ScopedEntity<Database::StarredArtist>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist)
|
||||
{
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto starredArtist{ StarredArtist::find(session, artist->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredArtist);
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 0);
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
}
|
||||
|
||||
ScopedStarredArtist starredArtist{ session, artist.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotArtist->getId(), starredArtist->getId());
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotArtist, Artist::pointer{});
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::Internal);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotArtist->getId(), starredArtist->getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist_PendingDestroy)
|
||||
{
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredArtist starredArtist{ session, artist.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
|
||||
starredArtist.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist_dateTime)
|
||||
{
|
||||
ScopedArtist artist1{ session, "MyArtist1" };
|
||||
ScopedArtist artist2{ session, "MyArtist2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
ScopedStarredArtist starredArtist1{ session, artist1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
ScopedStarredArtist starredArtist2{ session, artist2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(artists.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
starredArtist1.get().modify()->setDateTime(dateTime);
|
||||
starredArtist2.get().modify()->setDateTime(dateTime.addSecs(-1));
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], starredArtist1->getArtist()->getId());
|
||||
EXPECT_EQ(artists.results[1], starredArtist2->getArtist()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
starredArtist1.get().modify()->setDateTime(dateTime);
|
||||
starredArtist2.get().modify()->setDateTime(dateTime.addSecs(1));
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], starredArtist2->getArtist()->getId());
|
||||
EXPECT_EQ(artists.results[1], starredArtist1->getArtist()->getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
#include "database/StarredRelease.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
using ScopedStarredRelease = ScopedEntity<Database::StarredRelease>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredRelease)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto starredRelease{ StarredRelease::find(session, release->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredRelease);
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 0);
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
}
|
||||
|
||||
ScopedStarredRelease starredRelease{ session, release.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredRelease::find(session, release->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotRelease->getId(), starredRelease->getId());
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredRelease::find(session, release->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotRelease, StarredRelease::pointer{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Starredrelease_PendingDestroy)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredRelease starredRelease{ session, release.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
|
||||
starredRelease.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredRelease_dateTime)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
ScopedStarredRelease starredRelease1{ session, release1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
ScopedStarredRelease starredRelease2{ session, release2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(releases.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
starredRelease1.get().modify()->setDateTime(dateTime);
|
||||
starredRelease2.get().modify()->setDateTime(dateTime.addSecs(-1));
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], starredRelease1->getRelease()->getId());
|
||||
EXPECT_EQ(releases.results[1], starredRelease2->getRelease()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
starredRelease1.get().modify()->setDateTime(dateTime);
|
||||
starredRelease2.get().modify()->setDateTime(dateTime.addSecs(1));
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], starredRelease2->getRelease()->getId());
|
||||
EXPECT_EQ(releases.results[1], starredRelease1->getRelease()->getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
#include "database/StarredTrack.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
using ScopedStarredTrack = ScopedEntity<Database::StarredTrack>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredTrack)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
|
||||
auto starredTrack{ StarredTrack::find(session, track->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredTrack);
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 0);
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
}
|
||||
|
||||
ScopedStarredTrack starredTrack{ session, track.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
|
||||
auto gotTrack{ StarredTrack::find(session, track->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotTrack->getId(), starredTrack->getId());
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredTrack::find(session, track->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotRelease, StarredTrack::pointer{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Starredtrack_PendingDestroy)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredTrack starredTrack{ session, track.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
starredTrack.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredTrack_dateTime)
|
||||
{
|
||||
ScopedTrack track1{ session, "MyTrack1" };
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
ScopedStarredTrack starredTrack1{ session, track1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
ScopedStarredTrack starredTrack2{ session, track2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(tracks.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
|
||||
starredTrack1.get().modify()->setDateTime(dateTime);
|
||||
starredTrack2.get().modify()->setDateTime(dateTime.addSecs(-1));
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], starredTrack1->getTrack()->getId());
|
||||
EXPECT_EQ(tracks.results[1], starredTrack2->getTrack()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
|
||||
starredTrack1.get().modify()->setDateTime(dateTime);
|
||||
starredTrack2.get().modify()->setDateTime(dateTime.addSecs(1));
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], starredTrack2->getTrack()->getId());
|
||||
EXPECT_EQ(tracks.results[1], starredTrack1->getTrack()->getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, Track)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(Track::find(session, Track::FindParameters{}).results.size(), 0);
|
||||
EXPECT_EQ(Track::findIds(session, Track::FindParameters{}).results.size(), 0);
|
||||
EXPECT_EQ(Track::getCount(session), 0);
|
||||
EXPECT_FALSE(Track::exists(session, 0));
|
||||
|
||||
{
|
||||
bool visited{};
|
||||
Track::find(session, Track::FindParameters{}, [&](const Track::pointer&) {visited = true;});
|
||||
EXPECT_FALSE(visited);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(Track::find(session, Track::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(Track::getCount(session), 1);
|
||||
EXPECT_TRUE(Track::exists(session, track.getId()));
|
||||
auto myTrack{ Track::find(session, track.getId()) };
|
||||
ASSERT_TRUE(myTrack);
|
||||
EXPECT_EQ(myTrack->getId(), track.getId());
|
||||
|
||||
{
|
||||
bool visited{};
|
||||
Track::find(session, Track::FindParameters{}, [&](const Track::pointer& t)
|
||||
{
|
||||
visited = true;
|
||||
EXPECT_EQ(t->getId(), track.getId());
|
||||
});
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracks)
|
||||
{
|
||||
ScopedTrack track1{ session, "MyTrackFile1" };
|
||||
ScopedTrack track2{ session, "MyTrackFile2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_TRUE(track1.getId() != track2.getId());
|
||||
EXPECT_TRUE(track1.get() != track2.get());
|
||||
EXPECT_FALSE(track1.get() == track2.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracksSearchByFilter)
|
||||
{
|
||||
ScopedTrack track1{ session, "" };
|
||||
ScopedTrack track2{ session, "" };
|
||||
ScopedTrack track3{ session, "" };
|
||||
ScopedTrack track4{ session, "" };
|
||||
ScopedTrack track5{ session, "" };
|
||||
ScopedTrack track6{ session, "" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track1.get().modify()->setName("MyTrack");
|
||||
track2.get().modify()->setName("MyTrack%");
|
||||
track3.get().modify()->setName("MyTrack%Foo");
|
||||
track4.get().modify()->setName("%MyTrack");
|
||||
track5.get().modify()->setName("Foo%MyTrack");
|
||||
track6.get().modify()->setName("M_Track");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"Track"})) };
|
||||
EXPECT_EQ(tracks.results.size(), 6);
|
||||
}
|
||||
{
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"MyTrack"})) };
|
||||
EXPECT_EQ(tracks.results.size(), 5);
|
||||
EXPECT_TRUE(std::none_of(std::cbegin(tracks.results), std::cend(tracks.results), [&](const TrackId trackId) { return trackId == track6.getId(); }));
|
||||
}
|
||||
{
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"MyTrack%"})) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], track2.getId());
|
||||
EXPECT_EQ(tracks.results[1], track3.getId());
|
||||
}
|
||||
{
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"%MyTrack"})) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], track4.getId());
|
||||
EXPECT_EQ(tracks.results[1], track5.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_date)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), std::nullopt);
|
||||
EXPECT_EQ(track->getOriginalYear(), std::nullopt);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setDate(Wt::WDate{ 1995, 5, 5 });
|
||||
track.get().modify()->setOriginalDate(Wt::WDate{ 1994, 2, 2 });
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), 1995);
|
||||
EXPECT_EQ(track->getOriginalYear(), 1994);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_writtenAfter)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setLastWriteTime(dateTime);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(-1))) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
#include "database/TrackBookmark.hpp"
|
||||
|
||||
using ScopedTrackBookmark = ScopedEntity<Database::TrackBookmark>;
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, TrackBookmark)
|
||||
{
|
||||
ScopedTrack track {session, "MyTrack"};
|
||||
ScopedUser user {session, "MyUser"};
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedTrackBookmark bookmark {session, user.lockAndGet(), track.lockAndGet()};
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
|
||||
bookmark.get().modify()->setComment("MyComment");
|
||||
bookmark.get().modify()->setOffset(std::chrono::milliseconds {5});
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 1);
|
||||
|
||||
const auto bookmarks {TrackBookmark::find(session, user.getId())};
|
||||
ASSERT_EQ(bookmarks.results.size(), 1);
|
||||
EXPECT_EQ(bookmarks.results.front(), bookmark.getId());
|
||||
}
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
|
||||
auto userBookmark {TrackBookmark::find(session, user.getId(), track.getId())};
|
||||
ASSERT_TRUE(userBookmark);
|
||||
EXPECT_EQ(userBookmark, bookmark.get());
|
||||
|
||||
EXPECT_EQ(userBookmark->getOffset(), std::chrono::milliseconds {5});
|
||||
EXPECT_EQ(userBookmark->getComment(), "MyComment");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
#include "database/TrackFeatures.hpp"
|
||||
|
||||
using ScopedTrackFeatures = ScopedEntity<Database::TrackFeatures>;
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, TrackFeatures)
|
||||
{
|
||||
ScopedTrack track {session, "MyTrack"};
|
||||
ScopedUser user {session, "MyUser"};
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
EXPECT_EQ(TrackFeatures::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedTrackFeatures trackFeatures {session, track.lockAndGet(), ""};
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
EXPECT_EQ(TrackFeatures::getCount(session), 1);
|
||||
|
||||
auto allTrackFeatures {TrackFeatures::find(session)};
|
||||
ASSERT_EQ(allTrackFeatures.results.size(), 1);
|
||||
EXPECT_EQ(allTrackFeatures.results.front(), trackFeatures.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Emeric Poupon
|
||||
*
|
||||
* This file is part of LMS.
|
||||
*
|
||||
* LMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* LMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackList)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackList::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedTrackList trackList{ session, "MytrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackList::getCount(session), 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListSingleTrack)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setTrackList(trackList2.getId()));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
session.create<TrackListEntry>(track.get(), trackList1.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setTrackList(trackList2.getId()));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackList_SortMethod)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::Name)) };
|
||||
ASSERT_EQ(trackLists.results.size(), 2);
|
||||
EXPECT_EQ(trackLists.results[0], trackList1.getId());
|
||||
EXPECT_EQ(trackLists.results[1], trackList2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,1} });
|
||||
trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,2} });
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) };
|
||||
ASSERT_EQ(trackLists.results.size(), 2);
|
||||
EXPECT_EQ(trackLists.results[0], trackList2.getId());
|
||||
EXPECT_EQ(trackLists.results[1], trackList1.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,2} });
|
||||
trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,1} });
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) };
|
||||
ASSERT_EQ(trackLists.results.size(), 2);
|
||||
EXPECT_EQ(trackLists.results[0], trackList1.getId());
|
||||
EXPECT_EQ(trackLists.results[1], trackList2.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListMultipleTrack)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MytrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
std::list<ScopedTrack> tracks;
|
||||
|
||||
for (std::size_t i{}; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(tracks.back().get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
ASSERT_EQ(trackList->getCount(), tracks.size());
|
||||
const auto trackIds{ trackList->getTrackIds() };
|
||||
ASSERT_EQ(trackIds.size(), tracks.size());
|
||||
|
||||
// Same order
|
||||
std::size_t i{};
|
||||
for (const ScopedTrack& track : tracks)
|
||||
EXPECT_EQ(track.getId(), trackIds[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListSingleTrackWithCluster)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
EXPECT_EQ(trackLists.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
session.create<TrackListEntry>(track.get(), trackList1.get());
|
||||
cluster.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
ASSERT_EQ(trackLists.results.size(), 1);
|
||||
EXPECT_EQ(trackLists.results.front(), trackList1.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackList_getEntries)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MyTrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track1{ session, "MyTrack" };
|
||||
ScopedTrack track2{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(track1.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries() };
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries.front()->getTrack()->getId(), track1.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(track2.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries() };
|
||||
ASSERT_EQ(entries.size(), 2);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track1.getId());
|
||||
EXPECT_EQ(entries[1]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries(Range {1, 1}) };
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user