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")); }); } }