Files
jellyfin-multilang/tests/Jellyfin.Plugin.Multilang.Tests/ItemsProxyTransformerResolutionTests.cs
T
ajp_anton 096c6be8c7 Release 0.3.4: Jellyfin 12 stable support and audit fixes
Harden proxy permissions and cache behavior, streamline metadata fetching, remove obsolete rules, and validate the stable SDK with expanded regression coverage. Document backup format changes.
2026-09-09 01:18:43 +00:00

183 lines
5.8 KiB
C#

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 TraceUsesStoredOriginalTranslationWhenOriginalTitleIsEmpty()
{
var facts = Facts(originalTitle: "", originalLanguage: "fi");
var translations = TextTranslations((OriginalAction, TitleField, "Alkuperainen nimi"));
var attempts = new List<ItemsProxyResolutionAttempt>();
var normal = ItemsProxyTransformer.ResolveField(TitleField, [OriginalAction], facts, translations);
var traced = ItemsProxyTransformer.ResolveField(TitleField, [OriginalAction], facts, translations, attempts.Add);
Assert.Equal(normal, traced);
Assert.Equal("fi", traced.Language);
var chosen = Assert.Single(attempts);
Assert.True(chosen.Chosen);
Assert.Equal("Original/title", chosen.LookupKey);
Assert.Equal(traced.Value, chosen.Value);
}
[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);
Assert.Equal("fi", result.Language);
}
[Fact]
public void ResolveFieldUsesOriginalTitleBeforeTranslations()
{
var result = ItemsProxyTransformer.ResolveField(
TitleField,
[OriginalAction, LanguagePrefix + "en"],
Facts(originalTitle: "Original title", originalLanguage: "en"),
TextTranslations(("en", TitleField, "English title")));
Assert.True(result.Change);
Assert.Equal("Original title", result.Value);
Assert.Equal("en", result.Language);
}
[Fact]
public void ResolveFieldFallsBackToJellyfinForMissingTitle()
{
var result = ItemsProxyTransformer.ResolveField(
TitleField,
[LanguagePrefix + "sv"],
Facts(),
TextTranslations());
Assert.False(result.Change);
Assert.Null(result.Value);
Assert.Null(result.Language);
}
[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<string, Dictionary<string, string>> TextTranslations(params (string Lang, string Field, string Value)[] rows)
{
var result = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
foreach (var (lang, field, value) in rows)
{
if (!result.TryGetValue(lang, out var byField))
{
byField = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
result[lang] = byField;
}
byField[field] = value;
}
return result;
}
private static Dictionary<string, Dictionary<string, string>> AssetTranslations(params (string Kind, string Lang, string Value)[] rows)
{
var result = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
foreach (var (kind, lang, value) in rows)
{
if (!result.TryGetValue(kind, out var byLang))
{
byLang = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
result[kind] = byLang;
}
byLang[lang] = value;
}
return result;
}
private static FactsData Facts(string originalTitle = "", string originalLanguage = "")
=> new(
"item",
"tmdb",
"movie",
originalTitle,
originalLanguage,
"",
"[]",
"[]",
"[]",
"",
"[]",
0,
0);
}