Removed the database lib from services as it is still not a service

This commit is contained in:
emeric
2023-11-26 17:38:44 +01:00
parent 74a222ed54
commit 1f282c0517
229 changed files with 670 additions and 670 deletions
+457
View File
@@ -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());
}
}
+26
View File
@@ -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()
+851
View File
@@ -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());
}
}
}
+232
View File
@@ -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);
}
}
+154
View File
@@ -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()};
};
+109
View File
@@ -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
+690
View File
@@ -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
}
+148
View File
@@ -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());
}
}
+137
View File
@@ -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());
}
}
+137
View File
@@ -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());
}
}
+178
View File
@@ -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);
}
}
+66
View File
@@ -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");
}
}
+48
View File
@@ -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());
}
}
+224
View File
@@ -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());
}
}