using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Library.Genres;
using TeleWave.Application.Metadata;
using TeleWave.Application.Metadata.EnrichShows;
using TeleWave.Application.Tests.Support;
using TeleWave.Domain.Library;
using Xunit;
namespace TeleWave.Application.Tests.Metadata;
///
/// Массовое обогащение метаданными. Главное свойство — осторожность: чужой постер и чужой рейтинг
/// у шоу в эфире хуже, чем непроставленные метаданные.
///
public class EnrichShowsTests
{
[Fact]
public async Task Applies_WhenTitleMatchesExactly()
{
var fixture = new TestDb();
var show = Show.Create("Гравити Фолз", ShowKind.Series);
show.SetOriginalName("Gravity Falls");
await SeedAsync(fixture, show);
var provider = ProviderWith([
new MetadataCandidate("42", "Gravity Falls", 2012, null, null, ShowKind.Series),
]);
provider
.GetShowAsync("42", Arg.Any(), Arg.Any())
.Returns(new ShowMetadata("42", "Gravity Falls", 2012, "desc", null, [], null));
var result = await RunAsync(fixture, provider, show.Id);
Assert.Equal(1, result.Applied);
Assert.Empty(result.Skipped);
}
[Fact]
public async Task Skips_WhenSeveralCandidatesShareTheTitle()
{
// Два одноимённых — угадывать нельзя: у них разные постеры и разные рейтинги.
var fixture = new TestDb();
var show = Show.Create("Gravity Falls", ShowKind.Series);
await SeedAsync(fixture, show);
var provider = ProviderWith([
new MetadataCandidate("1", "Gravity Falls", null, null, null, ShowKind.Series),
new MetadataCandidate("2", "Gravity Falls", null, null, null, ShowKind.Series),
]);
var result = await RunAsync(fixture, provider, show.Id);
Assert.Equal(0, result.Applied);
Assert.Single(result.Skipped);
}
[Fact]
public async Task Skips_WhenOnlyLooseMatchFound()
{
var fixture = new TestDb();
var show = Show.Create("Пилот", ShowKind.Series);
await SeedAsync(fixture, show);
var provider = ProviderWith([
new MetadataCandidate("7", "Совсем другое шоу", null, null, null, ShowKind.Series),
]);
var result = await RunAsync(fixture, provider, show.Id);
Assert.Equal(0, result.Applied);
Assert.Single(result.Skipped);
}
[Fact]
public async Task Skips_AlreadyLinked()
{
// Ручной выбор источника массовая операция переписывать не должна.
var fixture = new TestDb();
var show = Show.Create("Gravity Falls", ShowKind.Series);
show.ApplyMetadata("tmdb", "999", null, null, null);
await SeedAsync(fixture, show);
var provider = ProviderWith([
new MetadataCandidate("42", "Gravity Falls", null, null, null, ShowKind.Series),
]);
var result = await RunAsync(fixture, provider, show.Id);
Assert.Equal(0, result.Applied);
Assert.Single(result.Skipped);
}
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 IMetadataProvider ProviderWith(IReadOnlyList candidates)
{
var provider = Substitute.For();
provider
.SearchShowsAsync(Arg.Any(), Arg.Any(), Arg.Any())
.Returns(candidates);
return provider;
}
private static async Task RunAsync(
TestDb fixture,
IMetadataProvider provider,
Guid showId
)
{
var resolver = Substitute.For();
resolver.Resolve("tmdb").Returns(provider);
await using var db = fixture.New();
var applier = new ShowMetadataApplier(
db,
resolver,
Substitute.For(),
Substitute.For(),
new GenreMatcher(db),
NullLogger.Instance
);
var result = await new EnrichShowsMetadataCommandHandler(db, resolver, applier).Handle(
new EnrichShowsMetadataCommand([showId], "tmdb"),
CancellationToken.None
);
Assert.True(result.IsSuccess);
await db.SaveChangesAsync(CancellationToken.None);
return result.Value;
}
}