/*
* 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 .
*/
#include
#include
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Database.hpp"
#include "database/TrackList.hpp"
#include "database/Release.hpp"
#include "database/Track.hpp"
using namespace Database;
class ScopedFileDeleter final
{
public:
ScopedFileDeleter(const boost::filesystem::path& path) : _path {path} {}
~ScopedFileDeleter() { boost::filesystem::remove(_path); }
private:
boost::filesystem::path _path;
};
#define CHECK(PRED) \
{ \
if (!(PRED)) \
{ \
std::string msg {"Predicate '" + std::string {#PRED} + "' at " + __FUNCTION__ + "@l." + std::to_string(__LINE__)}; \
throw std::runtime_error(msg.c_str()); \
} \
}
static
void
testRemoveDefaultEntries(Session& session)
{
{
auto transaction {session.createUniqueTransaction()};
auto clusterTypes {ClusterType::getAll(session)};
for (auto& clusterType : clusterTypes)
clusterType.remove();
}
}
static
void
testSingleTrack(Session& session)
{
IdType trackId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrackFile")};
CHECK(track);
CHECK(IdIsValid(track.id()));
trackId = track.id();
}
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::getById(session, trackId)};
CHECK(track);
CHECK(Track::getAll(session).size() == 1);
track.remove();
}
}
static
void
testSingleArtist(Session& session)
{
IdType artistId {};
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::create(session, "MyArtist")};
CHECK(artist);
artistId = artist.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Artist::getAll(session).size() == 1);
auto artists {Artist::getAllOrphans(session)};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
}
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::getById(session, artistId)};
CHECK(artist);
artist.remove();
}
}
static
void
testSingleRelease(Session& session)
{
IdType releaseId {};
{
auto transaction {session.createUniqueTransaction()};
auto release {Release::create(session, "MyRelease")};
CHECK(release);
releaseId = release.id();
}
{
auto transaction {session.createSharedTransaction()};
auto releases {Release::getAllOrphans(session)};
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
releases = Release::getAll(session);
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
}
{
auto transaction {session.createUniqueTransaction()};
auto release {Release::getById(session, releaseId)};
CHECK(release);
release.remove();
}
}
static
void
testSingleCluster(Session& session)
{
IdType clusterTypeId {};
IdType clusterId {};
{
auto transaction {session.createUniqueTransaction()};
auto clusterType {ClusterType::create(session, "MyType")};
CHECK(clusterType);
auto cluster {Cluster::create(session, clusterType, "MyCluster")};
CHECK(cluster);
clusterTypeId = clusterType.id();
clusterId = cluster.id();
}
{
auto transaction {session.createSharedTransaction()};
auto clusters {Cluster::getAll(session)};
CHECK(clusters.size() == 1);
CHECK(clusters.front().id() == clusterId);
CHECK(clusters.front()->getType().id() == clusterTypeId);
clusters = Cluster::getAllOrphans(session);
CHECK(clusters.size() == 1);
CHECK(clusters.front().id() == clusterId);
auto clusterTypes {ClusterType::getAll(session)};
CHECK(clusterTypes.size() == 1);
CHECK(clusterTypes.front().id() == clusterTypeId);
clusterTypes = ClusterType::getAllOrphans(session);
CHECK(clusterTypes.empty());
}
{
auto transaction {session.createUniqueTransaction()};
auto cluster {Cluster::getById(session, clusterId)};
CHECK(cluster);
cluster.remove();
auto clusterTypes {ClusterType::getAllOrphans(session)};
CHECK(clusterTypes.size() == 1);
}
{
auto transaction {session.createUniqueTransaction()};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
CHECK(clusterType);
clusterType.remove();
}
}
static
void
testSingleTrackSingleArtist(Session& session)
{
IdType trackId {};
IdType artistId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "dummy")};
CHECK(track);
auto artist {Artist::create(session, "dummy")};
CHECK(artist);
auto trackArtistLink {TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist)};
trackId = track.id();
artistId = artist.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Artist::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto track {Track::getById(session, trackId)};
CHECK(track);
auto artists {track->getArtists()};
CHECK(artists.size() == 1);
auto artist {artists.front()};
CHECK(artist.id() == artistId);
CHECK(artist->getReleaseCount() == 0);
CHECK(track->getArtistLinks().size() == 1);
auto artistLink {track->getArtistLinks().front()};
CHECK(artistLink->getTrack().id() == trackId);
CHECK(artistLink->getArtist().id() == artistId);
CHECK(track->getArtists(TrackArtistLink::Type::Artist).size() == 1);
CHECK(track->getArtists(TrackArtistLink::Type::ReleaseArtist).empty());
}
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::getById(session, artistId)};
CHECK(artist);
auto tracks {artist->getTracks()};
CHECK(tracks.size() == 1);
auto track {tracks.front()};
CHECK(track.id() == trackId);
CHECK(artist->getTracks(TrackArtistLink::Type::ReleaseArtist).empty());
CHECK(artist->getTracks(TrackArtistLink::Type::Artist).size() == 1);
track.remove();
artist.remove();
}
}
static
void
testSingleTrackSingleArtistMultiRoles(Session& session)
{
IdType trackId {};
IdType artistId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrack")};
auto artist {Artist::create(session, "MyArtist")};
TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist);
TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::ReleaseArtist);
TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Writer);
trackId = track.id();
artistId = artist.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Artist::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto track {Track::getById(session, trackId)};
CHECK(track);
auto artists {track->getArtists(TrackArtistLink::Type::Artist)};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
artists = track->getArtists(TrackArtistLink::Type::ReleaseArtist);
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
CHECK(track->getArtistLinks().size() == 3);
auto artist {Artist::getById(session, artistId)};
CHECK(artist);
CHECK(artist->getTracks().size() == 1);
CHECK(artist->getTracks(TrackArtistLink::Type::ReleaseArtist).size() == 1);
CHECK(artist->getTracks(TrackArtistLink::Type::Artist).size() == 1);
CHECK(artist->getTracks(TrackArtistLink::Type::Writer).size() == 1);
}
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::getById(session, artistId)};
auto track {Track::getById(session, trackId)};
track.remove();
artist.remove();
}
}
static
void
testSingleTrackMultiArtists(Session& session)
{
IdType trackId {};
IdType artist1Id {};
IdType artist2Id {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "dummy")};
auto artist1 {Artist::create(session, "artist1")};
auto artist2 {Artist::create(session, "artist2")};
TrackArtistLink::create(session, track, artist1, TrackArtistLink::Type::Artist);
TrackArtistLink::create(session, track, artist2, TrackArtistLink::Type::Artist);
trackId = track.id();
artist1Id = artist1.id();
artist2Id = artist2.id();
CHECK(artist1Id != artist2Id);
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Artist::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto track {Track::getById(session, trackId)};
CHECK(track);
auto artists {track->getArtists()};
CHECK(artists.size() == 2);
CHECK((artists[0].id() == artist1Id && artists[1].id() == artist2Id)
|| (artists[0].id() == artist2Id && artists[1].id() == artist1Id));
CHECK(track->getArtists(TrackArtistLink::Type::Artist).size() == 2);
CHECK(track->getArtists(TrackArtistLink::Type::ReleaseArtist).empty());
CHECK(Artist::getAll(session).size() == 2);
}
{
auto transaction {session.createUniqueTransaction()};
auto artist1 {Artist::getById(session, artist1Id)};
CHECK(artist1);
auto tracks {artist1->getTracks()};
CHECK(tracks.size() == 1);
auto track {tracks.front()};
CHECK(track.id() == trackId);
auto artist2 {Artist::getById(session, artist2Id)};
CHECK(artist2);
CHECK(artist2->getTracks().front() == track);
CHECK(artist1->getTracks(TrackArtistLink::Type::ReleaseArtist).empty());
CHECK(artist1->getTracks(TrackArtistLink::Type::Artist).size() == 1);
CHECK(artist2->getTracks(TrackArtistLink::Type::ReleaseArtist).empty());
CHECK(artist2->getTracks(TrackArtistLink::Type::Artist).size() == 1);
track.remove();
artist1.remove();
artist2.remove();
}
}
static
void
testSingleTrackSingleRelease(Session& session)
{
IdType trackId {};
IdType releaseId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "dummy")};
CHECK(track);
auto release {Release::create(session, "dummy")};
CHECK(release);
track.modify()->setRelease(release);
trackId = track.id();
releaseId = release.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Release::getAllOrphans(session).empty());
auto release {Release::getById(session, releaseId)};
CHECK(release);
CHECK(release->getTracks().size() == 1);
CHECK(release->getTracks().front().id() == trackId);
CHECK(release->getTracksCount() == 1);
}
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::getById(session, trackId)};
CHECK(track);
CHECK(track->getRelease());
CHECK(track->getRelease().id() == releaseId);
track.remove();
}
{
auto transaction {session.createUniqueTransaction()};
CHECK(Release::getAllOrphans(session).size() == 1);
auto release {Release::getById(session, releaseId)};
CHECK(release);
CHECK(release->getTracks().empty());
release.remove();
}
}
static
void
testSingleTrackSingleCluster(Session& session)
{
IdType trackId {};
IdType clusterId {};
IdType clusterTypeId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "dummy")};
auto clusterType {ClusterType::create(session, "MyType")};
auto cluster {Cluster::create(session, clusterType, "MyCluster")};
cluster.modify()->addTrack(track);
trackId = track.id();
clusterTypeId = clusterType.id();
clusterId = cluster.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Cluster::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto tracks {Track::getByFilter(session, {clusterId})};
CHECK(tracks.size() == 1);
CHECK(tracks.front().id() == trackId);
tracks = Track::getByFilter(session, {});
CHECK(tracks.size() == 1);
CHECK(tracks.front().id() == trackId);
}
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::getById(session, trackId)};
auto cluster {Cluster::getById(session, clusterId)};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
track.remove();
cluster.remove();
clusterType.remove();
}
}
static
void
testSingleTrackSingleReleaseSingleCluster(Session& session)
{
IdType trackId {};
IdType releaseId {};
IdType clusterId {};
IdType clusterTypeId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrackFile")};
auto release {Release::create(session, "MyRelease")};
auto clusterType {ClusterType::create(session, "MyType")};
auto cluster {Cluster::create(session, clusterType, "MyCluster")};
track.modify()->setRelease(release);
cluster.modify()->addTrack(track);
trackId = track.id();
releaseId = release.id();
clusterTypeId = clusterType.id();
clusterId = cluster.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Cluster::getAllOrphans(session).empty());
CHECK(Release::getAllOrphans(session).empty());
}
{
auto transaction {session.createUniqueTransaction()};
auto releases {Release::getByFilter(session, {clusterId})};
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
releases = Release::getByFilter(session, {clusterId});
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
}
{
auto transaction {session.createSharedTransaction()};
auto cluster {Cluster::getById(session, clusterId)};
CHECK(cluster->getReleasesCount() == 1);
CHECK(cluster->getTracksCount() == 1);
}
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::getById(session, trackId)};
auto release {Release::getById(session, releaseId)};
auto cluster {Cluster::getById(session, clusterId)};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
track.remove();
release.remove();
cluster.remove();
clusterType.remove();
}
}
static
void
testSingleTrackSingleArtistMultiClusters(Session& session)
{
IdType trackId {};
IdType artistId {};
IdType cluster1Id {};
IdType cluster2Id {};
IdType clusterTypeId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrackFile")};
auto artist {Artist::create(session, "MyArtist")};
auto clusterType {ClusterType::create(session, "MyType")};
auto cluster1 {Cluster::create(session, clusterType, "MyCluster1")};
auto cluster2 {Cluster::create(session, clusterType, "MyCluster2")};
auto trackArtistLink {TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist)};
cluster1.modify()->addTrack(track);
trackId = track.id();
artistId = artist.id();
clusterTypeId = clusterType.id();
cluster1Id = cluster1.id();
cluster2Id = cluster2.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Cluster::getAllOrphans(session).empty());
CHECK(Release::getAllOrphans(session).empty());
CHECK(Artist::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto artists {Artist::getByFilter(session, {cluster1Id})};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
artists = Artist::getByFilter(session, {});
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
artists = Artist::getByFilter(session, {cluster2Id});
CHECK(artists.empty());
auto cluster2 {Cluster::getById(session, cluster2Id)};
auto track {Track::getById(session, trackId)};
cluster2.modify()->addTrack(track);
}
{
auto transaction {session.createSharedTransaction()};
auto artists {Artist::getByFilter(session, {cluster1Id})};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
artists = Artist::getByFilter(session, {cluster2Id});
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
artists = Artist::getByFilter(session, {cluster1Id, cluster2Id});
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
}
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::getById(session, trackId)};
auto artist {Artist::getById(session, artistId)};
auto cluster1 {Cluster::getById(session, cluster1Id)};
auto cluster2 {Cluster::getById(session, cluster2Id)};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
track.remove();
artist.remove();
cluster1.remove();
cluster2.remove();
clusterType.remove();
}
}
static
void
testSingleTrackSingleArtistMultiRolesMultiClusters(Session& session)
{
IdType trackId {};
IdType artistId {};
IdType clusterId {};
IdType clusterTypeId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrackFile")};
auto artist {Artist::create(session, "MyArtist")};
auto clusterType {ClusterType::create(session, "MyType")};
auto cluster {Cluster::create(session, clusterType, "MyCluster")};
TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist);
TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::ReleaseArtist);
cluster.modify()->addTrack(track);
trackId = track.id();
artistId = artist.id();
clusterTypeId = clusterType.id();
clusterId = cluster.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Cluster::getAllOrphans(session).empty());
CHECK(Release::getAllOrphans(session).empty());
CHECK(Artist::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto artists {Artist::getByFilter(session, {clusterId})};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
}
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::getById(session, trackId)};
auto artist {Artist::getById(session, artistId)};
auto cluster {Cluster::getById(session, clusterId)};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
track.remove();
artist.remove();
cluster.remove();
clusterType.remove();
}
}
static
void
testMultiTracksSingleArtistMultiClusters(Session& session)
{
const std::size_t nbTracks {10};
const std::size_t nbClusters {5};
IdType artistId {};
IdType clusterTypeId {};
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::create(session, "MyArtist")};
auto clusterType {ClusterType::create(session, "MyType")};
std::vector clusters;
for (std::size_t i {}; i < nbClusters; ++i)
clusters.push_back(Cluster::create(session, clusterType, "MyCluster" + std::to_string(i)));
for (std::size_t i {}; i < nbTracks; ++i)
{
auto track {Track::create(session, "MyTrackFile")};
TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist);
for (const auto& cluster : clusters)
cluster.modify()->addTrack(track);
}
artistId = artist.id();
clusterTypeId = clusterType.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Cluster::getAllOrphans(session).empty());
CHECK(Artist::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
std::vector clusters {Cluster::getAll(session)};
CHECK(clusters.size() == nbClusters);
std::set clusterIds;
std::transform(std::cbegin(clusters), std::cend(clusters), std::inserter(clusterIds, std::begin(clusterIds)), [](const Cluster::pointer& cluster) { return cluster.id(); });
auto artists {Artist::getByFilter(session, clusterIds)};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
}
{
auto transaction {session.createUniqueTransaction()};
std::vector clusters {Cluster::getAll(session)};
for (auto& cluster : clusters)
cluster.remove();
std::vector tracks {Track::getAll(session)};
for (auto& track : tracks)
track.remove();
auto artist {Artist::getById(session, artistId)};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
artist.remove();
clusterType.remove();
}
}
static
void
testMultiTracksSingleArtistSingleRelease(Session& session)
{
const std::size_t nbTracks {10};
IdType artistId {};
IdType releaseId {};
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::create(session, "MyArtist")};
auto release {Release::create(session, "MyRelease")};
for (std::size_t i {}; i < nbTracks; ++i)
{
auto track {Track::create(session, "MyTrackFile")};
TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist);
track.modify()->setRelease(release);
}
artistId = artist.id();
releaseId = release.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Release::getAllOrphans(session).empty());
CHECK(Artist::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto artist {Artist::getById(session, artistId)};
CHECK(artist);
CHECK(artist->getReleaseCount() == 1);
CHECK(artist->getReleases().size() == 1);
CHECK(artist->getReleases().front().id() == releaseId);
auto release {Release::getById(session, releaseId)};
CHECK(release);
CHECK(release->getTracks().size() == nbTracks);
}
{
auto transaction {session.createUniqueTransaction()};
std::vector tracks {Track::getAll(session)};
for (auto& track : tracks)
track.remove();
auto artist {Artist::getById(session, artistId)};
auto release {Release::getById(session, releaseId)};
artist.remove();
release.remove();
}
}
static
void
testSingleTrackSingleReleaseSingleArtist(Session& session)
{
IdType trackId {};
IdType releaseId {};
IdType artistId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "dummy")};
auto release {Release::create(session, "dummy")};
auto artist {Artist::create(session, "dummy")};
auto trackArtistLink {TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist)};
track.modify()->setRelease(release);
trackId = track.id();
releaseId = release.id();
artistId = artist.id();
}
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::getById(session, artistId)};
CHECK(artist);
auto releases {artist->getReleases()};
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
CHECK(artist->getReleaseCount() == 1);
auto release {Release::getById(session, releaseId)};
CHECK(release);
auto artists {release->getArtists()};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
auto track {Track::getById(session, trackId)};
track.remove();
artist.remove();
release.remove();
}
}
static
void
testSingleTrackSingleReleaseSingleArtistSingleCluster(Session& session)
{
IdType trackId {};
IdType releaseId {};
IdType artistId {};
IdType clusterId {};
IdType clusterTypeId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrackFile")};
auto release {Release::create(session, "MyRelease")};
auto artist {Artist::create(session, "MyArtist")};
auto clusterType {ClusterType::create(session, "MyType")};
auto cluster {Cluster::create(session, clusterType, "MyCluster")};
auto trackArtistLink {TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist)};
track.modify()->setRelease(release);
cluster.modify()->addTrack(track);
trackId = track.id();
releaseId = release.id();
artistId = artist.id();
clusterId = cluster.id();
clusterTypeId = clusterType.id();
}
{
auto transaction {session.createSharedTransaction()};
CHECK(Cluster::getAllOrphans(session).empty());
CHECK(Artist::getAllOrphans(session).empty());
CHECK(Release::getAllOrphans(session).empty());
}
{
auto transaction {session.createSharedTransaction()};
auto artists {Artist::getByFilter(session, {clusterId})};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
auto artist {Artist::getById(session, artistId)};
auto releases {artist->getReleases()};
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
releases = artist->getReleases({clusterId});
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
}
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::getById(session, artistId)};
auto release {Release::getById(session, releaseId)};
auto track {Track::getById(session, trackId)};
auto cluster {Cluster::getById(session, clusterId)};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
track.remove();
artist.remove();
release.remove();
cluster.remove();
clusterType.remove();
}
}
static
void
testSingleTrackSingleReleaseSingleArtistMultiClusters(Session& session)
{
IdType trackId {};
IdType releaseId {};
IdType artistId {};
IdType cluster1Id {};
IdType cluster2Id {};
IdType clusterTypeId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrackFile")};
auto release {Release::create(session, "MyRelease")};
auto artist {Artist::create(session, "MyArtist")};
auto clusterType {ClusterType::create(session, "MyType")};
auto cluster1 {Cluster::create(session, clusterType, "MyCluster1")};
auto cluster2 {Cluster::create(session, clusterType, "MyCluster2")};
auto trackArtistLink {TrackArtistLink::create(session, track, artist, TrackArtistLink::Type::Artist)};
track.modify()->setRelease(release);
cluster1.modify()->addTrack(track);
cluster2.modify()->addTrack(track);
trackId = track.id();
releaseId = release.id();
artistId = artist.id();
cluster1Id = cluster1.id();
cluster2Id = cluster2.id();
clusterTypeId = clusterType.id();
}
{
auto transaction {session.createSharedTransaction()};
auto artist {Artist::getById(session, artistId)};
auto releases {artist->getReleases()};
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
releases = artist->getReleases({cluster1Id, cluster2Id});
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
}
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::getById(session, artistId)};
auto release {Release::getById(session, releaseId)};
auto track {Track::getById(session, trackId)};
auto cluster1 {Cluster::getById(session, cluster1Id)};
auto cluster2 {Cluster::getById(session, cluster1Id)};
auto clusterType {ClusterType::getById(session, clusterTypeId)};
track.remove();
artist.remove();
release.remove();
cluster1.remove();
cluster2.remove();
clusterType.remove();
}
}
static
void
testSingleUser(Session& session)
{
IdType userId {};
{
auto transaction {session.createUniqueTransaction()};
auto user {User::create(session)};
CHECK(user);
userId = user.id();
}
{
auto transaction {session.createSharedTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
CHECK(user->getPlayedTrackList(session)->getCount() == 0);
CHECK(user->getPlayedTrackList(session)->getTopTracks(1).empty());
CHECK(user->getPlayedTrackList(session)->getTopArtists(1).empty());
CHECK(user->getPlayedTrackList(session)->getTopReleases(1).empty());
CHECK(user->getQueuedTrackList(session)->getCount() == 0);
}
{
auto transaction {session.createUniqueTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
user.remove();
}
}
static
void
testSingleStarredArtist(Session& session)
{
IdType artistId {};
IdType userId {};
{
auto transaction {session.createUniqueTransaction()};
auto artist {Artist::create(session, "MyArtist")};
CHECK(artist);
auto user {User::create(session)};
CHECK(user);
artistId = artist.id();
userId = user.id();
}
{
auto transaction {session.createSharedTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto artist {Artist::getById(session, artistId)};
CHECK(artist);
user.modify()->starArtist(artist);
}
{
auto transaction {session.createSharedTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto artists {user->getStarredArtists()};
CHECK(artists.size() == 1);
CHECK(artists.front().id() == artistId);
auto artist {Artist::getById(session, artistId)};
CHECK(user->hasStarredArtist(artist));
}
{
auto transaction {session.createUniqueTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto artist {Artist::getById(session, artistId)};
CHECK(artist);
user.remove();
artist.remove();
}
}
static
void
testSingleStarredRelease(Session& session)
{
IdType releaseId {};
IdType userId {};
{
auto transaction {session.createUniqueTransaction()};
auto release {Release::create(session, "MyRelease")};
CHECK(release);
auto user {User::create(session)};
CHECK(user);
releaseId = release.id();
userId = user.id();
}
{
auto transaction {session.createUniqueTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto release {Release::getById(session, releaseId)};
CHECK(release);
user.modify()->starRelease(release);
}
{
auto transaction {session.createSharedTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto releases {user->getStarredReleases()};
CHECK(releases.size() == 1);
CHECK(releases.front().id() == releaseId);
auto release {Release::getById(session, releaseId)};
CHECK(user->hasStarredRelease(release));
}
{
auto transaction {session.createUniqueTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto release {Release::getById(session, releaseId)};
CHECK(release);
user.remove();
release.remove();
}
}
static
void
testSingleStarredTrack(Session& session)
{
IdType trackId {};
IdType userId {};
{
auto transaction {session.createUniqueTransaction()};
auto track {Track::create(session, "MyTrackFile")};
CHECK(track);
auto user {User::create(session)};
CHECK(user);
trackId = track.id();
userId = user.id();
}
{
auto transaction {session.createUniqueTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto track {Track::getById(session, trackId)};
CHECK(track);
user.modify()->starTrack(track);
}
{
auto transaction {session.createSharedTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto tracks {user->getStarredTracks()};
CHECK(tracks.size() == 1);
CHECK(tracks.front().id() == trackId);
auto track {Track::getById(session, trackId)};
CHECK(user->hasStarredTrack(track));
}
{
auto transaction {session.createUniqueTransaction()};
auto user {User::getById(session, userId)};
CHECK(user);
auto track {Track::getById(session, trackId)};
CHECK(track);
user.remove();
track.remove();
}
}
static
void
testDatabaseEmpty(Session& session)
{
auto uniqueTransaction {session.createUniqueTransaction()};
CHECK(Artist::getAll(session).empty());
CHECK(Cluster::getAll(session).empty());
CHECK(ClusterType::getAll(session).empty());
CHECK(Release::getAll(session).empty());
CHECK(Track::getAll(session).empty());
}
int main(int argc, char* argv[])
{
try
{
const boost::filesystem::path tmpFile {boost::filesystem::temp_directory_path() / boost::filesystem::unique_path()};
ScopedFileDeleter tmpFileDeleter {tmpFile};
std::cout << "Database test file: '" << tmpFile.string() << "'" << std::endl;
for (std::size_t i = 0; i < 2; ++i)
{
Database::Database db {tmpFile};
std::unique_ptr session {db.createSession()};
auto runTest = [&session](const std::string& name, std::function testFunc)
{
std::cout << "Running test '" << name << "'..." << std::endl;
testFunc(*session);
testDatabaseEmpty(*session);
std::cout << "Running test '" << name << "': SUCCESS" << std::endl;
};
#define RUN_TEST(test) runTest(#test, test)
// Special test to remove any default created entries
RUN_TEST(testRemoveDefaultEntries);
RUN_TEST(testSingleTrack);
RUN_TEST(testSingleArtist);
RUN_TEST(testSingleRelease);
RUN_TEST(testSingleCluster);
RUN_TEST(testSingleTrackSingleArtist);
RUN_TEST(testSingleTrackSingleArtistMultiRoles);
RUN_TEST(testSingleTrackMultiArtists);
RUN_TEST(testSingleTrackSingleRelease);
RUN_TEST(testSingleTrackSingleCluster);
RUN_TEST(testSingleTrackSingleReleaseSingleCluster);
RUN_TEST(testSingleTrackSingleArtistMultiClusters);
RUN_TEST(testSingleTrackSingleArtistMultiRolesMultiClusters);
RUN_TEST(testMultiTracksSingleArtistMultiClusters);
RUN_TEST(testMultiTracksSingleArtistSingleRelease);
RUN_TEST(testSingleTrackSingleReleaseSingleArtist);
RUN_TEST(testSingleTrackSingleReleaseSingleArtistSingleCluster);
RUN_TEST(testSingleTrackSingleReleaseSingleArtistMultiClusters);
RUN_TEST(testSingleUser);
RUN_TEST(testSingleStarredArtist);
RUN_TEST(testSingleStarredRelease);
RUN_TEST(testSingleStarredTrack);
}
}
catch (std::exception& e)
{
std::cerr << "Caught exception: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}