Files
jellyfin-multilang/tests/Jellyfin.Plugin.Multilang.Tests/CategoryRuleEvaluatorTests.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

144 lines
5.5 KiB
C#

using System.Text.Json;
using Jellyfin.Plugin.Multilang.Data;
using Jellyfin.Plugin.Multilang.Rules;
namespace Jellyfin.Plugin.Multilang.Tests;
public sealed class CategoryRuleEvaluatorTests
{
[Fact]
public void FastMatchingAndDiagnosticTraceAgreeAcrossAllRuleModes()
{
foreach (var relation in new[] { "is", "is_not", "contains", "not_contains" })
foreach (var fieldOr in new[] { false, true })
foreach (var valueOr in new[] { false, true })
foreach (var matchAll in new[] { false, true })
foreach (var facts in new[] { Facts(originalLanguage: "sv"), Facts(spokenLanguages: ["fi", "en"]), Facts(kind: "tv") })
{
var rule = Rule("original_language", relation, valueOr, "sv", "fi");
rule.Requirements[0].Fields = ["original_language", "spoken_languages"];
rule.Requirements[0].UseFieldOr = fieldOr;
rule.Requirements = [rule.Requirements[0], Requirement("production_countries", "contains", false, "FI")];
rule.MatchAllConditions = matchAll;
Assert.Equal(CategoryRuleEvaluator.Trace(rule, facts).Result, CategoryRuleEvaluator.Matches(rule, facts));
}
}
[Fact]
public void IsWithAndListRequiresExactSet()
{
var category = Rule("production_countries", "is", useOr: false, "SE", "FI");
Assert.True(CategoryRuleEvaluator.Matches(category, Facts(productionCountries: ["FI", "SE"])));
Assert.False(CategoryRuleEvaluator.Matches(category, Facts(productionCountries: ["FI"])));
Assert.False(CategoryRuleEvaluator.Matches(category, Facts(productionCountries: ["FI", "SE", "NO"])));
}
[Fact]
public void IsWithOrListRequiresSingleMatchingValue()
{
var category = Rule("original_language", "is", useOr: true, "sv", "fi");
Assert.True(CategoryRuleEvaluator.Matches(category, Facts(originalLanguage: "sv")));
Assert.False(CategoryRuleEvaluator.Matches(category, Facts(originalLanguage: "en")));
Assert.False(CategoryRuleEvaluator.Matches(category, Facts(originalLanguage: "", spokenLanguages: ["sv", "fi"])));
}
[Fact]
public void ContainsWithAndListRequiresEveryExpectedValue()
{
var category = Rule("spoken_languages", "contains", useOr: false, "sv", "fi");
Assert.True(CategoryRuleEvaluator.Matches(category, Facts(spokenLanguages: ["en", "sv", "fi"])));
Assert.False(CategoryRuleEvaluator.Matches(category, Facts(spokenLanguages: ["en", "sv"])));
}
[Fact]
public void ContainsWithOrListRequiresAnyExpectedValue()
{
var category = Rule("origin_countries", "contains", useOr: true, "SE", "FI");
Assert.True(CategoryRuleEvaluator.Matches(category, Facts(originCountries: ["NO", "FI"])));
Assert.False(CategoryRuleEvaluator.Matches(category, Facts(originCountries: ["NO", "DK"])));
}
[Fact]
public void MultipleConditionsRespectCategoryMatchMode()
{
var all = new UserCategoryRule
{
Scopes = ["M"],
MatchAllConditions = true,
Requirements =
[
Requirement("original_language", "is", false, "sv"),
Requirement("production_countries", "contains", true, "SE")
]
};
var any = CopyWithMatchAll(all, false);
var swedishLanguageOnly = Facts(originalLanguage: "sv", productionCountries: ["FI"]);
Assert.False(CategoryRuleEvaluator.Matches(all, swedishLanguageOnly));
Assert.True(CategoryRuleEvaluator.Matches(any, swedishLanguageOnly));
}
[Fact]
public void ScopeMustMatchItemKind()
{
var movieOnly = Rule("original_language", "is", useOr: false, "sv");
movieOnly.Scopes = ["M"];
Assert.True(CategoryRuleEvaluator.Matches(movieOnly, Facts(kind: "movie", originalLanguage: "sv")));
Assert.False(CategoryRuleEvaluator.Matches(movieOnly, Facts(kind: "tv", originalLanguage: "sv")));
}
private static UserCategoryRule Rule(string field, string relation, bool useOr, params string[] values)
=> new()
{
Scopes = ["M", "S", "C"],
Requirements = [Requirement(field, relation, useOr, values)]
};
private static UserCategoryRequirement Requirement(string field, string relation, bool useOr, params string[] values)
=> new()
{
Fields = [field],
Relation = relation,
UseOr = useOr,
Values = values
};
private static UserCategoryRule CopyWithMatchAll(UserCategoryRule rule, bool matchAll)
=> new()
{
Id = rule.Id,
Label = rule.Label,
Requirements = rule.Requirements,
MatchAllConditions = matchAll,
Scopes = rule.Scopes,
FieldActionLists = rule.FieldActionLists
};
private static FactsData Facts(
string kind = "movie",
string originalLanguage = "",
string[]? originCountries = null,
string[]? productionCountries = null,
string[]? spokenLanguages = null,
string audioLanguage = "")
=> new(
"item",
"tmdb",
kind,
"Original title",
originalLanguage,
originalLanguage,
JsonSerializer.Serialize(originCountries ?? []),
JsonSerializer.Serialize(productionCountries ?? []),
JsonSerializer.Serialize(spokenLanguages ?? []),
audioLanguage,
"[]",
0,
0);
}