using Flaro.Core.Metadata;
using Microsoft.Extensions.Logging.Abstractions;
namespace Flaro.Metadata.Tests;
/// Was ausser Titel und Plakat noch ankommt.
///
///
/// Daran hängen Detailseite, Vorschläge und der Filter nach Genre. Mit
/// Titel, Jahr, Beschreibung und zwei Bildern lässt sich eine Kachel zeichnen
/// und sonst nichts.
///
public class AnreicherungTests
{
private static TmdbClient Client(Attrappe attrappe, string sprache = "de-DE") =>
new(new HttpClient(attrappe) { BaseAddress = new Uri(TmdbClient.BaseAddress) },
FesteEinstellungen.MitSchluessel(sprache), NullLogger.Instance);
private const string Suche = """{"results":[{"id":603,"title":"Matrix"}]}""";
private const string Einzeln = """
{"id":603,"title":"Matrix","release_date":"1999-03-30",
"overview":"Neo zweifelt an der Wirklichkeit.",
"poster_path":"/abc.jpg","backdrop_path":"/def.jpg",
"runtime":136,"vote_average":8.2,"tagline":"Die Wirklichkeit ist eine Lüge.",
"genres":[{"name":"Science Fiction"},{"name":"Action"}],
"external_ids":{"imdb_id":"tt0133093"},
"release_dates":{"results":[
{"iso_3166_1":"US","release_dates":[{"certification":"R"}]},
{"iso_3166_1":"DE","release_dates":[{"certification":""},{"certification":"16"}]}
]},
"images":{"logos":[
{"file_path":"/englisch.png","iso_639_1":"en","vote_average":9.0},
{"file_path":"/deutsch.png","iso_639_1":"de","vote_average":2.0},
{"file_path":"/ohne.png","iso_639_1":null,"vote_average":5.0}
]},
"credits":{
"cast":[
{"id":6384,"name":"Keanu Reeves","character":"Neo","profile_path":"/k.jpg","order":0},
{"id":2975,"name":"Laurence Fishburne","character":"Morpheus","profile_path":null,"order":1}
],
"crew":[
{"id":9339,"name":"Lana Wachowski","job":"Director","profile_path":"/l.jpg"},
{"id":9339,"name":"Lana Wachowski","job":"Writer","profile_path":"/l.jpg"},
{"id":9339,"name":"Lana Wachowski","job":"Story","profile_path":"/l.jpg"},
{"id":111,"name":"Jemand vom Licht","job":"Gaffer","profile_path":null}
]
}}
""";
private static Attrappe Vollstaendig() =>
Attrappe.NachPfad(("search/movie", Suche), ("movie/603", Einzeln));
[Test]
public async Task Laufzeit_Bewertung_und_Werbezeile_kommen_an()
{
var film = await Client(Vollstaendig()).FindMovieAsync("Matrix", 1999);
Assert.Multiple(() =>
{
Assert.That(film!.ProviderId, Is.EqualTo(603));
Assert.That(film.RuntimeMinutes, Is.EqualTo(136));
Assert.That(film.Rating, Is.EqualTo(8.2));
Assert.That(film.Tagline, Is.EqualTo("Die Wirklichkeit ist eine Lüge."));
Assert.That(film.ImdbId, Is.EqualTo("tt0133093"));
});
}
[Test]
public async Task Genres_kommen_als_Namen_an()
{
var film = await Client(Vollstaendig()).FindMovieAsync("Matrix", 1999);
Assert.That(film!.Genres, Is.EqualTo(new[] { "Science Fiction", "Action" }));
}
/// Freigaben sind national — die FSK gilt nicht in Kansas.
[Test]
public async Task Die_Freigabe_richtet_sich_nach_dem_eingestellten_Land()
{
var deutsch = await Client(Vollstaendig(), "de-DE").FindMovieAsync("Matrix", 1999);
var amerikanisch = await Client(Vollstaendig(), "en-US").FindMovieAsync("Matrix", 1999);
Assert.Multiple(() =>
{
// Der erste DE-Eintrag ist leer; genommen wird der erste gefüllte.
Assert.That(deutsch!.ContentRating, Is.EqualTo("16"));
Assert.That(amerikanisch!.ContentRating, Is.EqualTo("R"));
});
}
/// Der Schriftzug in der eigenen Sprache schlägt den besser bewerteten.
[Test]
public async Task Das_Logo_kommt_in_der_eingestellten_Sprache()
{
var film = await Client(Vollstaendig(), "de-DE").FindMovieAsync("Matrix", 1999);
Assert.That(film!.Logo!.Url, Does.EndWith("/deutsch.png"),
"auch wenn das englische bei TMDB besser bewertet ist");
}
/// Ohne eigene Sprache gewinnt das sprachlose vor dem englischen.
///
///
/// Ein Schriftzug ohne Sprachangabe enthält meist gar keinen Text —
/// er ist überall richtig.
///
[Test]
public async Task Ohne_passende_Sprache_gewinnt_das_sprachlose()
{
var film = await Client(Vollstaendig(), "fr-FR").FindMovieAsync("Matrix", 1999);
Assert.That(film!.Logo!.Url, Does.EndWith("/ohne.png"));
}
[Test]
public async Task Darsteller_kommen_in_der_Reihenfolge_der_Quelle()
{
var film = await Client(Vollstaendig()).FindMovieAsync("Matrix", 1999);
var darsteller = film!.Credits!.Where(c => c.Kind == CreditKind.Actor).ToList();
Assert.Multiple(() =>
{
Assert.That(darsteller.Select(d => d.Name),
Is.EqualTo(new[] { "Keanu Reeves", "Laurence Fishburne" }));
Assert.That(darsteller[0].Character, Is.EqualTo("Neo"));
Assert.That(darsteller[0].Portrait!.Url, Does.EndWith("/k.jpg"));
Assert.That(darsteller[1].Portrait, Is.Null, "kein Bild ist null, keine kaputte Adresse");
});
}
/// Aus dem Stab nur Regie und Drehbuch.
///
///
/// TMDB führt dort auch Beleuchter und Caterer. Eine Detailseite, die
/// alle nennt, nennt nichts.
///
[Test]
public async Task Vom_Stab_kommen_nur_Regie_und_Drehbuch()
{
var film = await Client(Vollstaendig()).FindMovieAsync("Matrix", 1999);
var stab = film!.Credits!.Where(c => c.Kind != CreditKind.Actor).ToList();
Assert.Multiple(() =>
{
Assert.That(stab.Count(c => c.Kind == CreditKind.Director), Is.EqualTo(1));
// „Writer" und „Story" sind bei TMDB zwei Zeilen und hier ein Name.
Assert.That(stab.Count(c => c.Kind == CreditKind.Writer), Is.EqualTo(1));
Assert.That(stab.Any(c => c.Name.Contains("Licht")), Is.False);
});
}
/// Was ein Einzelabruf nicht hergibt, darf den Treffer nicht kippen.
///
///
/// Eine Antwort, die keine Kennung enthält — ein Anmeldeportal, ein Proxy,
/// eine Trefferliste —, liest der Dekoder als Null. Das als Treffer
/// durchzulassen hiesse, einen Film mit der Kennung 0 anzulegen; statt
/// dessen bleibt, was die Suche schon wusste.
///
[Test]
public async Task Ein_leerer_Einzelabruf_faellt_auf_den_Suchtreffer_zurueck()
{
var attrappe = Attrappe.NachPfad(
("search/movie", """{"results":[{"id":603,"title":"Matrix","release_date":"1999-03-30"}]}"""),
("movie/603", "{}"));
var film = await Client(attrappe).FindMovieAsync("Matrix", 1999);
Assert.Multiple(() =>
{
Assert.That(film!.ProviderId, Is.EqualTo(603));
Assert.That(film.Title, Is.EqualTo("Matrix"));
Assert.That(film.Genres, Is.Null);
});
}
/// Alles in einer Anfrage statt in vieren.
[Test]
public async Task Der_Einzelabruf_holt_alles_auf_einmal()
{
var attrappe = Vollstaendig();
await Client(attrappe).FindMovieAsync("Matrix", 1999);
var einzeln = attrappe.Aufrufe.Single(a => a.Contains("movie/603"));
Assert.Multiple(() =>
{
Assert.That(einzeln, Does.Contain("credits"));
Assert.That(einzeln, Does.Contain("external_ids"));
Assert.That(einzeln, Does.Contain("release_dates"));
Assert.That(einzeln, Does.Contain("images"));
// Sprachlose Schriftzüge liefert TMDB nur, wenn man sie nennt.
Assert.That(einzeln, Does.Contain("null"));
Assert.That(attrappe.Aufrufe, Has.Count.EqualTo(2), "Suche und Einzelabruf, mehr nicht");
});
}
[Test]
public async Task Eine_Serie_bekommt_die_Folgenlaenge_als_Laufzeit()
{
var attrappe = Attrappe.NachPfad(
("search/tv", """{"results":[{"id":70523,"name":"Dark"}]}"""),
("tv/70523", """
{"id":70523,"name":"Dark","first_air_date":"2017-12-01",
"episode_run_time":[60],"vote_average":8.4,
"genres":[{"name":"Mystery"}],
"content_ratings":{"results":[{"iso_3166_1":"DE","rating":"16"}]}}
"""));
var serie = await Client(attrappe).FindSeriesAsync("Dark", null);
Assert.Multiple(() =>
{
Assert.That(serie!.RuntimeMinutes, Is.EqualTo(60));
Assert.That(serie.Rating, Is.EqualTo(8.4));
Assert.That(serie.Genres, Is.EqualTo(new[] { "Mystery" }));
Assert.That(serie.ContentRating, Is.EqualTo("16"));
});
}
}