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 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, CriteriaText = rule.CriteriaText, Requirements = rule.Requirements, MatchAllConditions = matchAll, Scopes = rule.Scopes, FieldActions = rule.FieldActions, 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); }