Add unit tests for dynamic group mode handling and exclusions
Implemented several unit tests to validate the behavior of dynamic group modes, including the preservation of pinned items when switching to dynamic mode, the dropping of exclusions when reverting to static mode, and the default pinning of new elements in dynamic groups. Additional tests ensure that exclusions are correctly applied and removed, and that static groups refuse exclusions. These tests enhance the coverage and reliability of the group management functionality.
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
using System.Text;
|
||||
using NSubstitute;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Library.Genres;
|
||||
using TeleWave.Application.Metadata;
|
||||
using TeleWave.Application.Tests.Support;
|
||||
using TeleWave.Domain.Images;
|
||||
using TeleWave.Domain.Library;
|
||||
using Xunit;
|
||||
|
||||
namespace TeleWave.Application.Tests.Metadata;
|
||||
|
||||
/// <summary>
|
||||
/// Применение метаданных: постер в реестр изображений, жанры, франшиза и отказы. Общий путь для
|
||||
/// точечного и массового применения — расхождение между ними отлаживать было бы нечем.
|
||||
/// </summary>
|
||||
public class ShowMetadataApplierTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task RegistersPoster_InImageRegistry()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var show = Show.Create("Шоу", ShowKind.Single);
|
||||
await SeedAsync(fixture, show);
|
||||
|
||||
var downloader = Substitute.For<IImageDownloader>();
|
||||
downloader
|
||||
.DownloadAsync("https://poster", Arg.Any<CancellationToken>())
|
||||
.Returns(new DownloadedImage(Encoding.UTF8.GetBytes("img"), ".jpg"));
|
||||
var store = Substitute.For<IImageStore>();
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await Applier(db, Meta(posterUrl: "https://poster"), downloader, store)
|
||||
.ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None);
|
||||
Assert.True(result.IsSuccess);
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
|
||||
await using var check = fixture.New();
|
||||
var image = check.Images.Single();
|
||||
Assert.Equal(ImageCategory.ShowPoster, image.Category);
|
||||
Assert.Equal(image.Id, check.Shows.Single().PosterImageId);
|
||||
await store
|
||||
.Received(1)
|
||||
.SaveAsync(image.Id, ".jpg", Arg.Any<byte[]>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task KeepsPoster_WhenDownloadFails()
|
||||
{
|
||||
// Источник отдал ссылку, но картинка не скачалась — это не повод валить применение.
|
||||
var fixture = new TestDb();
|
||||
var show = Show.Create("Шоу", ShowKind.Single);
|
||||
await SeedAsync(fixture, show);
|
||||
|
||||
var downloader = Substitute.For<IImageDownloader>();
|
||||
downloader
|
||||
.DownloadAsync(Arg.Any<string>(), Arg.Any<CancellationToken>())
|
||||
.Returns((DownloadedImage?)null);
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await Applier(db, Meta(posterUrl: "https://poster"), downloader)
|
||||
.ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None);
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.Empty(db.Images);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemembersFranchise_FromSource()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var show = Show.Create("Рокки", ShowKind.Single);
|
||||
await SeedAsync(fixture, show);
|
||||
|
||||
await using var db = fixture.New();
|
||||
await Applier(db, Meta(franchise: new MetadataFranchise("1241", "Рокки")))
|
||||
.ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None);
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
|
||||
await using var check = fixture.New();
|
||||
var stored = check.Shows.Single();
|
||||
Assert.Equal("1241", stored.FranchiseExternalId);
|
||||
Assert.Equal("Рокки", stored.FranchiseName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fails_WhenProviderUnavailable()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var show = Show.Create("Шоу", ShowKind.Single);
|
||||
await SeedAsync(fixture, show);
|
||||
|
||||
await using var db = fixture.New();
|
||||
var resolver = Substitute.For<IMetadataProviderResolver>();
|
||||
var applier = new ShowMetadataApplier(
|
||||
db,
|
||||
resolver,
|
||||
Substitute.For<IImageDownloader>(),
|
||||
Substitute.For<IImageStore>(),
|
||||
new GenreMatcher(db)
|
||||
);
|
||||
|
||||
var result = await applier.ApplyAsync(
|
||||
await LoadAsync(db, show.Id),
|
||||
"tmdb",
|
||||
"42",
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.False(result.IsSuccess);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fails_WhenSourceKnowsNothing()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var show = Show.Create("Шоу", ShowKind.Single);
|
||||
await SeedAsync(fixture, show);
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await Applier(db, meta: null)
|
||||
.ApplyAsync(await LoadAsync(db, show.Id), "tmdb", "42", CancellationToken.None);
|
||||
|
||||
Assert.False(result.IsSuccess);
|
||||
}
|
||||
|
||||
private static ShowMetadata Meta(
|
||||
string? posterUrl = null,
|
||||
MetadataFranchise? franchise = null
|
||||
) => new("42", "Шоу", 2000, "описание", posterUrl, [], null, franchise);
|
||||
|
||||
private static ShowMetadataApplier Applier(
|
||||
Infrastructure.Persistence.AppDbContext db,
|
||||
ShowMetadata? meta,
|
||||
IImageDownloader? downloader = null,
|
||||
IImageStore? store = null
|
||||
)
|
||||
{
|
||||
var provider = Substitute.For<IMetadataProvider>();
|
||||
provider
|
||||
.GetShowAsync(Arg.Any<string>(), Arg.Any<ShowKind>(), Arg.Any<CancellationToken>())
|
||||
.Returns(meta);
|
||||
var resolver = Substitute.For<IMetadataProviderResolver>();
|
||||
resolver.Resolve("tmdb").Returns(provider);
|
||||
|
||||
return new ShowMetadataApplier(
|
||||
db,
|
||||
resolver,
|
||||
downloader ?? Substitute.For<IImageDownloader>(),
|
||||
store ?? Substitute.For<IImageStore>(),
|
||||
new GenreMatcher(db)
|
||||
);
|
||||
}
|
||||
|
||||
private static async Task SeedAsync(TestDb fixture, Show show)
|
||||
{
|
||||
await using var seed = fixture.New();
|
||||
seed.Shows.Add(show);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
private static async Task<Show> LoadAsync(
|
||||
Infrastructure.Persistence.AppDbContext db,
|
||||
Guid showId
|
||||
) =>
|
||||
await Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstAsync(
|
||||
db.Shows,
|
||||
s => s.Id == showId
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user