Enhance metadata handling by introducing ShowKind parameter across various components. Update SearchShowMetadataQuery and related handlers to support querying by show type, ensuring accurate metadata retrieval for series and films. Implement validation to prevent episodes from being associated with non-series shows. Update frontend API to include ShowKind in metadata search requests, improving overall functionality and user experience.
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NSubstitute;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Library.Genres;
|
||||
using TeleWave.Application.Metadata;
|
||||
using TeleWave.Application.Metadata.ApplyShowMetadata;
|
||||
using TeleWave.Application.Tests.Support;
|
||||
using TeleWave.Domain.Library;
|
||||
using Xunit;
|
||||
|
||||
namespace TeleWave.Application.Tests.Metadata;
|
||||
|
||||
public class ApplyShowMetadataTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(ShowKind.Series)]
|
||||
[InlineData(ShowKind.Single)]
|
||||
public async Task PassesShowKindToProvider(ShowKind kind)
|
||||
{
|
||||
// Тип определяет, в какое пространство идентификаторов пойдёт TMDb, и берётся он у самого
|
||||
// шоу, а не из команды: иначе запросом можно было бы записать сериалу метаданные
|
||||
// одноимённого фильма.
|
||||
var arranged = await ArrangeAsync(kind);
|
||||
Respond(arranged.Provider, new ShowMetadata("42", "A", 2000, null, null));
|
||||
|
||||
var result = await ApplyAsync(arranged);
|
||||
|
||||
Assert.True(result);
|
||||
await arranged
|
||||
.Provider.Received(1)
|
||||
.GetShowAsync("42", kind, Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AppliesRecognizedRating()
|
||||
{
|
||||
var arranged = await ArrangeAsync(ShowKind.Single);
|
||||
Respond(arranged.Provider, new ShowMetadata("42", "A", 2000, null, null, null, "PG-13"));
|
||||
|
||||
await ApplyAsync(arranged);
|
||||
|
||||
Assert.Equal(ShowAudience.Pg13, await SavedAudienceAsync(arranged));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task KeepsRating_WhenSourceGivesNothingUsable()
|
||||
{
|
||||
// «Not Rated» — это отсутствие данных. Снять им проставленный рейтинг нельзя: обновление
|
||||
// метаданных тихо открыло бы взрослому шоу дорогу в детское время.
|
||||
var arranged = await ArrangeAsync(ShowKind.Single, ShowAudience.R);
|
||||
Respond(arranged.Provider, new ShowMetadata("42", "A", 2000, null, null, null, "Not Rated"));
|
||||
|
||||
await ApplyAsync(arranged);
|
||||
|
||||
Assert.Equal(ShowAudience.R, await SavedAudienceAsync(arranged));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fails_ForInterstitial()
|
||||
{
|
||||
var arranged = await ArrangeAsync(ShowKind.Interstitial);
|
||||
|
||||
Assert.False(await ApplyAsync(arranged));
|
||||
await arranged
|
||||
.Provider.DidNotReceive()
|
||||
.GetShowAsync(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<ShowKind>(),
|
||||
Arg.Any<CancellationToken>()
|
||||
);
|
||||
}
|
||||
|
||||
private static void Respond(IMetadataProvider provider, ShowMetadata meta) =>
|
||||
provider
|
||||
.GetShowAsync("42", Arg.Any<ShowKind>(), Arg.Any<CancellationToken>())
|
||||
.Returns(meta);
|
||||
|
||||
private static async Task<bool> ApplyAsync(Arranged arranged)
|
||||
{
|
||||
await using var db = arranged.Fixture.New();
|
||||
var handler = new ApplyShowMetadataCommandHandler(
|
||||
db,
|
||||
arranged.Resolver,
|
||||
Substitute.For<IImageDownloader>(),
|
||||
Substitute.For<IImageStore>(),
|
||||
new GenreMatcher(db)
|
||||
);
|
||||
|
||||
var result = await handler.Handle(
|
||||
new ApplyShowMetadataCommand(arranged.ShowId, "tmdb", "42"),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
// В обычном пути сохраняет UnitOfWorkBehavior; при прямом вызове хендлера его нет.
|
||||
if (result.IsSuccess)
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
return result.IsSuccess;
|
||||
}
|
||||
|
||||
private static async Task<ShowAudience?> SavedAudienceAsync(Arranged arranged)
|
||||
{
|
||||
await using var db = arranged.Fixture.New();
|
||||
return (await db.Shows.FirstAsync(s => s.Id == arranged.ShowId)).Audience;
|
||||
}
|
||||
|
||||
private sealed record Arranged(
|
||||
TestDb Fixture,
|
||||
IMetadataProvider Provider,
|
||||
IMetadataProviderResolver Resolver,
|
||||
Guid ShowId
|
||||
);
|
||||
|
||||
private static async Task<Arranged> ArrangeAsync(ShowKind kind, ShowAudience? audience = null)
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var show = Show.Create("A", kind);
|
||||
show.SetAudience(audience);
|
||||
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Shows.Add(show);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
var provider = Substitute.For<IMetadataProvider>();
|
||||
var resolver = Substitute.For<IMetadataProviderResolver>();
|
||||
resolver.Resolve("tmdb").Returns(provider);
|
||||
|
||||
return new Arranged(fixture, provider, resolver, show.Id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user