From 3114520c87579eb5cf150e4d764f59fd32f39412 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Mon, 5 Oct 2026 19:19:07 -0400 Subject: Backport pull request #18279 from jellyfin/release-12.z Recompute the parental rating score whenever an item is saved Original-merge: 29d7a3ca2444070bda748161a2da777c8e42594e Merged-by: crobibero Backported-by: Cody Robibero --- .../LibraryManager/ParentalRatingScoreTests.cs | 112 +++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/ParentalRatingScoreTests.cs (limited to 'tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager') diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/ParentalRatingScoreTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/ParentalRatingScoreTests.cs new file mode 100644 index 0000000000..7adf7ce3b3 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/ParentalRatingScoreTests.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AutoFixture; +using AutoFixture.AutoMoq; +using Emby.Naming.Common; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Controller.Sorting; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using Moq; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Library.LibraryManager; + +[Collection("LibraryManagerTests")] +public sealed class ParentalRatingScoreTests : IDisposable +{ + private readonly Emby.Server.Implementations.Library.LibraryManager _libraryManager; + private readonly List _saved = []; + private readonly ILibraryManager? _previousLibraryManager; + private readonly ILocalizationManager? _previousLocalizationManager; + + public ParentalRatingScoreTests() + { + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fixture.Register(() => new NamingOptions()); + fixture.Freeze>() + .Setup(c => c.ApplicationPaths.ProgramDataPath).Returns("/data"); + fixture.Freeze>() + .Setup(p => p.SaveItems(It.IsAny>(), It.IsAny())) + .Callback, CancellationToken>((items, _) => _saved.AddRange(items)); + + _libraryManager = fixture.Build() + .Do(s => s.AddParts( + fixture.Create>(), + [], + fixture.Create>(), + fixture.Create>(), + fixture.Create>())) + .Create(); + + // BaseItem resolves these through process-wide statics; restored in Dispose. + _previousLibraryManager = BaseItem.LibraryManager; + _previousLocalizationManager = BaseItem.LocalizationManager; + BaseItem.LibraryManager = _libraryManager; + + var localizationManagerMock = new Mock(); + localizationManagerMock.Setup(l => l.GetRatingScore("G", It.IsAny())).Returns(new ParentalRatingScore(0, null)); + localizationManagerMock.Setup(l => l.GetRatingScore("XXX", It.IsAny())).Returns(new ParentalRatingScore(1000, null)); + BaseItem.LocalizationManager = localizationManagerMock.Object; + Video.RecordingsManager ??= fixture.Create(); + } + + public void Dispose() + { + BaseItem.LibraryManager = _previousLibraryManager!; + BaseItem.LocalizationManager = _previousLocalizationManager!; + } + + private static Movie CreateRatedMovie() => new() + { + Id = Guid.NewGuid(), + Name = "Up", + PreferredMetadataCountryCode = "us", + OfficialRating = "G", + InheritedParentalRatingValue = 0 + }; + + [Fact] + public async Task UpdateItemAsync_ChangedCustomRating_StoresItsScore() + { + var movie = CreateRatedMovie(); + movie.CustomRating = "XXX"; + + await _libraryManager.UpdateItemAsync(movie, null!, ItemUpdateType.MetadataEdit, CancellationToken.None); + + Assert.Equal(1000, Assert.Single(_saved).InheritedParentalRatingValue); + } + + [Fact] + public async Task UpdateItemAsync_ClearedRatings_ClearsScore() + { + var movie = CreateRatedMovie(); + movie.OfficialRating = null; + + await _libraryManager.UpdateItemAsync(movie, null!, ItemUpdateType.MetadataEdit, CancellationToken.None); + + Assert.Null(Assert.Single(_saved).InheritedParentalRatingValue); + } + + [Fact] + public void CreateItem_RatedItem_StoresItsScore() + { + var movie = CreateRatedMovie(); + movie.InheritedParentalRatingValue = null; + movie.CustomRating = "XXX"; + + _libraryManager.CreateItem(movie, null); + + Assert.Equal(1000, _saved.Single().InheritedParentalRatingValue); + } +} -- cgit v1.2.3