public static void TestGetStarred2Async()
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random     = new RandomPopulator(dbContext);
                    var user       = random.AddUser();
                    var library    = random.AddLibrary();
                    var directory  = random.AddDirectory(library);
                    var trackFile  = random.AddFile(directory);
                    var genre      = random.AddGenre();
                    var artist     = random.AddArtist();
                    var album      = random.AddAlbum(artist);
                    var track      = random.AddTrack(trackFile, artist, album, genre: genre);
                    var artistStar = random.AddArtistStar(artist, user);
                    var albumStar  = random.AddAlbumStar(album, user);
                    var trackStar  = random.AddTrackStar(track, user);
                    dbContext.SaveChanges();

                    var result = RestApiQueries.GetStarred2Async(dbContext, user.UserId, null, "opus", CancellationToken.None).GetAwaiter().GetResult();

                    Assert.NotNull(result);
                    // TODO
                }
            }
            public static void GetGenresAsync_GenreHasAcessibleNonAccessControlledTrack_GenreIsReturned()
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random     = new RandomPopulator(dbContext);
                    var user       = random.AddUser();
                    var library    = random.AddLibrary(accessControlled: false);
                    var genre      = random.AddGenre();
                    var artist     = random.AddArtist();
                    var album      = random.AddAlbum(artist);
                    var directory  = random.AddDirectory(library);
                    var file       = random.AddFile(directory);
                    var track      = random.AddTrack(file, artist, album);
                    var trackGenre = random.AddTrackGenre(track, genre);
                    dbContext.SaveChanges();

                    var result = RestApiQueries.GetGenresAsync(dbContext, user.UserId, CancellationToken.None).GetAwaiter().GetResult();

                    var resultGenre = Assert.Single(result.genre);
                    Assert.Equal(genre.Name, resultGenre.Text.Single());
                }
            }
            public static void GetAlbumList2ByGenreAsync_LibraryIsSpecified_ReturnsExpectedAlbums()
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random          = new RandomPopulator(dbContext);
                    var user            = random.AddUser();
                    var library         = random.AddLibrary();
                    var otherLibrary    = random.AddLibrary();
                    var artist          = random.AddArtist();
                    var genre           = random.AddGenre();
                    var album           = random.AddAlbum(artist, genre: genre);
                    var directory       = random.AddDirectory(library);
                    var file            = random.AddFile(directory);
                    var track           = random.AddTrack(file, artist, album);
                    var trackGenre      = random.AddTrackGenre(track, genre);
                    var otherDirectory  = random.AddDirectory(otherLibrary);
                    var otherFile       = random.AddFile(otherDirectory);
                    var otherTrack      = random.AddTrack(otherFile, artist, album);
                    var otherTrackGenre = random.AddTrackGenre(otherTrack, genre);
                    dbContext.SaveChanges();

                    var result = RestApiQueries.GetAlbumList2ByGenreAsync(dbContext, user.UserId, library.LibraryId, 0, 10, genre.Name, CancellationToken.None).GetAwaiter().GetResult();

                    var resultAlbum = Assert.Single(result.album);
                    Assert.Equal("a" + album.AlbumId, resultAlbum.id);
                    Assert.Equal(1, resultAlbum.songCount);
                    Assert.Equal(Math.Round(track.Duration ?? 0), resultAlbum.duration);
                }
            }
            public static void GetAlbumList2ByGenreAsync_LibraryDoesNotExist_ThrowsDataNotFoundError()
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random     = new RandomPopulator(dbContext);
                    var user       = random.AddUser();
                    var library    = random.AddLibrary();
                    var artist     = random.AddArtist();
                    var genre      = random.AddGenre();
                    var album      = random.AddAlbum(artist, genre: genre);
                    var directory  = random.AddDirectory(library);
                    var file       = random.AddFile(directory);
                    var track      = random.AddTrack(file, artist, album);
                    var trackGenre = random.AddTrackGenre(track, genre);
                    dbContext.SaveChanges();

                    var ex = Assert.Throws <RestApiErrorException>(() => RestApiQueries.GetAlbumList2ByGenreAsync(dbContext, user.UserId, library.LibraryId + 1, 0, 10, genre.Name, CancellationToken.None).GetAwaiter().GetResult());

                    var expectedException = RestApiErrorException.DataNotFoundError();
                    Assert.Equal(expectedException.Message, ex.Message);
                    Assert.Equal(expectedException.Code, ex.Code);
                }
            }
            public static void GetGenresAsync_Always_ReturnsExpectedGenreDetails(string albumsTracksGenreNames)
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random      = new RandomPopulator(dbContext);
                    var user        = random.AddUser();
                    var library     = random.AddLibrary();
                    var artist      = random.AddArtist();
                    var genres      = new List <Genre>();
                    var trackGenres = new List <TrackGenre>();
                    foreach (string albumTracksGenreNames in albumsTracksGenreNames.Split(";"))
                    {
                        var directory = random.AddDirectory(library);
                        var album     = random.AddAlbum(artist);
                        foreach (string trackGenreNames in albumTracksGenreNames.Split(","))
                        {
                            var file  = random.AddFile(directory);
                            var track = random.AddTrack(file, artist, album);
                            foreach (string genreName in trackGenreNames.Split("/"))
                            {
                                var genre = genres.SingleOrDefault(g => g.Name == genreName);
                                if (genre == null)
                                {
                                    genre      = random.AddGenre();
                                    genre.Name = genreName;
                                    genres.Add(genre);
                                }
                                var trackGenre = random.AddTrackGenre(track, genre);
                                trackGenres.Add(trackGenre);
                            }
                        }
                    }
                    dbContext.SaveChanges();

                    var result = RestApiQueries.GetGenresAsync(dbContext, user.UserId, CancellationToken.None).GetAwaiter().GetResult();

                    Assert.Equal(genres.Count, result.genre.Length);
                    Assert.Equal(new SortedSet <string>(genres.Select(g => g.Name)),
                                 new SortedSet <string>(result.genre.Select(g => g.Text.Single())));
                    foreach (var resultGenre in result.genre)
                    {
                        string genreName   = resultGenre.Text.Single();
                        var    genreTracks = trackGenres.Where(rg => rg.Genre.Name == genreName).Select(tg => tg.Track);
                        var    genreAlbums = genreTracks.Select(t => t.Album).Distinct();

                        Assert.Equal(genreAlbums.Count(), resultGenre.albumCount);
                        Assert.Equal(genreTracks.Count(), resultGenre.songCount);
                    }
                }
            }
            public static void GetAlbumList2ByGenreAsync_VariousOffsetAndCount_ReturnsExpectedAlbumDetails(int albumCount, int count)
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random  = new RandomPopulator(dbContext);
                    var user    = random.AddUser();
                    var library = random.AddLibrary();
                    var artist  = random.AddArtist();
                    var genre   = random.AddGenre();
                    var albums  = new List <Album>();
                    var tracks  = new List <Track>();
                    for (int i = 0; i < albumCount; ++i)
                    {
                        var album = random.AddAlbum(artist, genre: genre);
                        albums.Add(album);
                        var directory = random.AddDirectory(library);
                        var file      = random.AddFile(directory);
                        var track     = random.AddTrack(file, artist, album);
                        tracks.Add(track);
                        var trackGenre = random.AddTrackGenre(track, genre);
                    }
                    dbContext.SaveChanges();

                    albums = albums
                             .OrderBy(a => a.SortTitle ?? a.Title, _stringComparer)
                             .ThenBy(a => a.AlbumId)
                             .ToList();

                    for (int i = 0; i <= albumCount; ++i)
                    {
                        var result = RestApiQueries.GetAlbumList2ByGenreAsync(dbContext, user.UserId, null, i, count, genre.Name, CancellationToken.None).GetAwaiter().GetResult();

                        Assert.Equal(albums.Skip(i).Take(count).Select(a => "a" + a.AlbumId).ToArray(),
                                     result.album.Select(a => a.id).ToArray());
                        foreach (var resultAlbum in result.album)
                        {
                            var album       = albums.Single(a => "a" + a.AlbumId == resultAlbum.id);
                            var albumTracks = tracks.Where(t => t.Album == album);

                            Assert.Equal(album.Title, resultAlbum.name);
                            Assert.Equal(album.Artist.Name, resultAlbum.artist);
                            Assert.Equal("r" + album.ArtistId, resultAlbum.artistId);
                            Assert.Equal(album.CoverPictureId?.ToString("X8"), resultAlbum.coverArt);
                            Assert.Equal(albumTracks.Count(), resultAlbum.songCount);
                            Assert.Equal(Math.Round(albumTracks.Sum(t => t.Duration) ?? 0), resultAlbum.duration);
                            Assert.False(resultAlbum.playCountSpecified);
                            Assert.Equal(default, resultAlbum.playCount);
            public static void GetGenresAsync_Always_GenresAreInExpectedOrder()
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random    = new RandomPopulator(dbContext);
                    var user      = random.AddUser();
                    var library   = random.AddLibrary();
                    var genres    = new List <Genre>();
                    var artist    = random.AddArtist();
                    var album     = random.AddAlbum();
                    var directory = random.AddDirectory(library);
                    foreach (string genreName in new[]
                    {
                        "A",
                        "a",
                        "C",
                        "𝓏",
                        "𓂀",
                        "B",
                        "b",
                    })
                    {
                        var genre = random.AddGenre();
                        genre.Name = genreName;
                        genres.Add(genre);
                        var file       = random.AddFile(directory);
                        var track      = random.AddTrack(file, artist, album);
                        var trackGenre = random.AddTrackGenre(track, genre);
                    }
                    dbContext.SaveChanges();

                    genres = genres
                             .OrderBy(g => g.Name, _stringComparer)
                             .ToList();

                    var result = RestApiQueries.GetGenresAsync(dbContext, user.UserId, CancellationToken.None).GetAwaiter().GetResult();

                    Assert.Equal(genres.Select(g => g.Name).ToArray(),
                                 result.genre.Select(g => g.Text.Single()).ToArray());
                }
            }
            public static void GetGenresAsync_GenreHasAlbumWithNoAccessibleTrack_AlbumIsNotCounted()
            {
                var dbConnection = OpenSqliteDatabase();

                var dbContextOptionsBuilder = new DbContextOptionsBuilder <MediaInfoContext>()
                                              .DisableClientSideEvaluation()
                                              .UseSqlite(dbConnection);

                using (var dbContext = new MediaInfoContext(dbContextOptionsBuilder.Options))
                {
                    var random = new RandomPopulator(dbContext);
                    var user   = random.AddUser();
                    var genre  = random.AddGenre();
                    var inaccessibleLibrary    = random.AddLibrary(accessControlled: true);
                    var inaccessibleArtist     = random.AddArtist();
                    var inaccessibleAlbum      = random.AddAlbum(inaccessibleArtist);
                    var inaccessibleDirectory  = random.AddDirectory(inaccessibleLibrary);
                    var inaccessibleFile       = random.AddFile(inaccessibleDirectory);
                    var inaccessibleTrack      = random.AddTrack(inaccessibleFile, inaccessibleArtist, inaccessibleAlbum);
                    var inaccessibleTrackGenre = random.AddTrackGenre(inaccessibleTrack, genre);
                    var accessibleArtist       = random.AddArtist();
                    var accessibleAlbum        = random.AddAlbum(inaccessibleArtist);
                    var accessibleLibrary      = random.AddLibrary(accessControlled: false);
                    var accessibleDirectory    = random.AddDirectory(accessibleLibrary);
                    var accessibleFile         = random.AddFile(accessibleDirectory);
                    var accessibleTrack        = random.AddTrack(accessibleFile, accessibleArtist, accessibleAlbum);
                    var accessibleTrackGenre   = random.AddTrackGenre(accessibleTrack, genre);
                    dbContext.SaveChanges();

                    var result = RestApiQueries.GetGenresAsync(dbContext, user.UserId, CancellationToken.None).GetAwaiter().GetResult();

                    var resultGenre = Assert.Single(result.genre);
                    Assert.Equal(1, resultGenre.albumCount);
                    Assert.Equal(1, resultGenre.songCount);
                }
            }