using Jellyfin.Plugin.Multilang.Data; using Jellyfin.Plugin.Multilang.Services; namespace Jellyfin.Plugin.Multilang.Tests; public sealed class ItemsProxyTransformerResolutionTests { private const string TitleField = "title"; private const string OverviewField = "overview"; private const string TaglineField = "tagline"; private const string PosterKind = "poster"; private const string LogoKind = "logo"; private const string OriginalAction = "Original"; private const string LanguagePrefix = "Language:"; [Fact] public void ResolveFieldUsesFirstLanguageWithData() { var translations = TextTranslations( ("sv", OverviewField, ""), ("fi", OverviewField, "Finnish overview"), ("en", OverviewField, "English overview")); var result = ItemsProxyTransformer.ResolveField( OverviewField, [LanguagePrefix + "sv", LanguagePrefix + "fi", LanguagePrefix + "en"], Facts(), translations); Assert.True(result.Change); Assert.Equal("Finnish overview", result.Value); } [Fact] public void ResolveFieldUsesOriginalTitleBeforeTranslations() { var result = ItemsProxyTransformer.ResolveField( TitleField, [OriginalAction, LanguagePrefix + "en"], Facts(originalTitle: "Original title"), TextTranslations(("en", TitleField, "English title"))); Assert.True(result.Change); Assert.Equal("Original title", result.Value); } [Fact] public void ResolveFieldFallsBackToJellyfinForMissingTitle() { var result = ItemsProxyTransformer.ResolveField( TitleField, [LanguagePrefix + "sv"], Facts(), TextTranslations()); Assert.False(result.Change); Assert.Null(result.Value); } [Fact] public void ResolveFieldClearsMissingOptionalText() { var result = ItemsProxyTransformer.ResolveField( TaglineField, [LanguagePrefix + "sv"], Facts(), TextTranslations()); Assert.True(result.Change); Assert.Equal(string.Empty, result.Value); } [Fact] public void ResolveAssetUsesFirstLanguageWithData() { var assets = AssetTranslations( (PosterKind, "sv", ""), (PosterKind, "fi", "https://image/fi.jpg"), (PosterKind, "en", "https://image/en.jpg")); var result = ItemsProxyTransformer.ResolveAsset( PosterKind, [LanguagePrefix + "sv", LanguagePrefix + "fi", LanguagePrefix + "en"], assets); Assert.True(result.Change); Assert.Equal("https://image/fi.jpg", result.Value); } [Fact] public void ResolveAssetFallsBackToJellyfinForMissingPoster() { var result = ItemsProxyTransformer.ResolveAsset( PosterKind, [LanguagePrefix + "sv"], AssetTranslations()); Assert.False(result.Change); Assert.Null(result.Value); } [Fact] public void ResolveAssetClearsMissingOptionalImage() { var result = ItemsProxyTransformer.ResolveAsset( LogoKind, [LanguagePrefix + "sv"], AssetTranslations()); Assert.True(result.Change); Assert.Equal(string.Empty, result.Value); } private static Dictionary> TextTranslations(params (string Lang, string Field, string Value)[] rows) { var result = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (var (lang, field, value) in rows) { if (!result.TryGetValue(lang, out var byField)) { byField = new Dictionary(StringComparer.OrdinalIgnoreCase); result[lang] = byField; } byField[field] = value; } return result; } private static Dictionary> AssetTranslations(params (string Kind, string Lang, string Value)[] rows) { var result = new Dictionary>(StringComparer.OrdinalIgnoreCase); foreach (var (kind, lang, value) in rows) { if (!result.TryGetValue(kind, out var byLang)) { byLang = new Dictionary(StringComparer.OrdinalIgnoreCase); result[kind] = byLang; } byLang[lang] = value; } return result; } private static FactsData Facts(string originalTitle = "") => new( "item", "tmdb", "movie", originalTitle, "", "", "[]", "[]", "[]", "", "[]", 0, 0); }