aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs52
-rw-r--r--tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs81
-rw-r--r--tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsCastTests.cs105
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryPlayedOrderingTests.cs189
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs73
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/SeasonResolverTests.cs2
6 files changed, 501 insertions, 1 deletions
diff --git a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs
index e34eb0bda3..86bac4256a 100644
--- a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs
+++ b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Database.Implementations.Entities;
@@ -27,6 +28,57 @@ namespace Jellyfin.Controller.Tests.Entities;
public class BaseItemTests
{
+ [Fact]
+ public void GetItemByNameFolderName_ShortName_IsKeptAsIs()
+ {
+ SetupPassThroughFileSystem();
+
+ Assert.Equal("Mairghread Scott", BaseItem.GetItemByNameFolderName("Mairghread Scott."));
+ }
+
+ [Fact]
+ public void GetItemByNameFolderName_OverlongName_FitsInAPathComponent()
+ {
+ SetupPassThroughFileSystem();
+
+ // What a provider result that concatenated a whole credit list into one name looks like.
+ var name = string.Join(", ", Enumerable.Repeat("Jerry Siegel (created by: Superman)", 20));
+
+ var folderName = BaseItem.GetItemByNameFolderName(name);
+
+ Assert.True(Encoding.UTF8.GetByteCount(folderName) <= 128);
+ Assert.StartsWith("Jerry Siegel (created by: Superman)", folderName, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void GetItemByNameFolderName_OverlongNamesSharingAPrefix_StayApart()
+ {
+ SetupPassThroughFileSystem();
+
+ var prefix = new string('a', 200);
+
+ Assert.NotEqual(
+ BaseItem.GetItemByNameFolderName(prefix + "Joe Shuster"),
+ BaseItem.GetItemByNameFolderName(prefix + "Bob Kane"));
+ }
+
+ [Fact]
+ public void GetItemByNameFolderName_OverlongName_IsStable()
+ {
+ SetupPassThroughFileSystem();
+
+ var name = new string('a', 300);
+
+ Assert.Equal(BaseItem.GetItemByNameFolderName(name), BaseItem.GetItemByNameFolderName(name));
+ }
+
+ private static void SetupPassThroughFileSystem()
+ {
+ var fileSystem = new Mock<IFileSystem>();
+ fileSystem.Setup(x => x.GetValidFilename(It.IsAny<string>())).Returns((string name) => name);
+ BaseItem.FileSystem = fileSystem.Object;
+ }
+
[Theory]
[InlineData("", "")]
[InlineData("1", "0000000001")]
diff --git a/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs b/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs
new file mode 100644
index 0000000000..bd50a903f1
--- /dev/null
+++ b/tests/Jellyfin.Providers.Tests/Omdb/OmdbProviderTests.cs
@@ -0,0 +1,81 @@
+using System.Linq;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Providers.Plugins.Omdb;
+using Xunit;
+
+namespace Jellyfin.Providers.Tests.Omdb
+{
+ public class OmdbProviderTests
+ {
+ [Fact]
+ public void AddPeople_CommaSeparatedList_SplitsIntoIndividualPeople()
+ {
+ var result = new MetadataResult<Movie>();
+
+ OmdbProvider.AddPeople(result, "Philip G. Epstein, Julius J. Epstein, Howard Koch", PersonKind.Writer);
+
+ Assert.Equal(
+ new[] { "Philip G. Epstein", "Julius J. Epstein", "Howard Koch" },
+ result.People!.Select(p => p.Name));
+ Assert.All(result.People!, p => Assert.Equal(PersonKind.Writer, p.Type));
+ }
+
+ [Fact]
+ public void AddPeople_RoleAnnotations_AreStrippedAndDeduplicated()
+ {
+ var result = new MetadataResult<Movie>();
+
+ OmdbProvider.AddPeople(result, "Mari Okada (screenplay), Mari Okada (story), Jun'ichi Satô (screenplay), Jun'ichi Satô (story)", PersonKind.Writer);
+
+ Assert.Equal(
+ new[] { "Mari Okada", "Jun'ichi Satô" },
+ result.People!.Select(p => p.Name));
+ }
+
+ [Theory]
+ [InlineData(
+ "Jerry Siegel (created by: Superman, Superboy), Bob Kane (created by: Batman)",
+ "Jerry Siegel|Bob Kane")]
+ [InlineData("Alan Moore (created by: John Constantine)", "Alan Moore")]
+ public void AddPeople_CommaInsideAnAnnotation_StaysOneCredit(string credits, string expected)
+ {
+ var result = new MetadataResult<Movie>();
+
+ OmdbProvider.AddPeople(result, credits, PersonKind.Writer);
+
+ Assert.Equal(expected.Split('|'), result.People!.Select(p => p.Name));
+ }
+
+ [Theory]
+ [InlineData("Jack Salvatore, Jr.", "Jack Salvatore, Jr.")]
+ [InlineData("Efrem Zimbalist, Jr., Tom Hanks", "Efrem Zimbalist, Jr.|Tom Hanks")]
+ [InlineData("Tom Hanks, Sammy Davis, Jr", "Tom Hanks|Sammy Davis, Jr")]
+ [InlineData("Harold Ramis, Ken Griffey, III (voice)", "Harold Ramis|Ken Griffey, III")]
+ [InlineData("Robert Downey Jr., Gwyneth Paltrow", "Robert Downey Jr.|Gwyneth Paltrow")]
+ [InlineData("Jr., Tom Hanks", "Jr.|Tom Hanks")]
+ public void AddPeople_GenerationalSuffix_StaysWithItsName(string credits, string expected)
+ {
+ var result = new MetadataResult<Movie>();
+
+ OmdbProvider.AddPeople(result, credits, PersonKind.Actor);
+
+ Assert.Equal(expected.Split('|'), result.People!.Select(p => p.Name));
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("(uncredited)")]
+ public void AddPeople_NoUsableName_AddsNothing(string? credits)
+ {
+ var result = new MetadataResult<Movie>();
+
+ OmdbProvider.AddPeople(result, credits!, PersonKind.Actor);
+
+ Assert.Null(result.People);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsCastTests.cs b/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsCastTests.cs
new file mode 100644
index 0000000000..182e7c52eb
--- /dev/null
+++ b/tests/Jellyfin.Providers.Tests/Tmdb/TmdbUtilsCastTests.cs
@@ -0,0 +1,105 @@
+using System.Collections.Generic;
+using System.Linq;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Providers.Plugins.Tmdb;
+using TMDbLib.Objects.TvShows;
+using Xunit;
+
+namespace Jellyfin.Providers.Tests.Tmdb
+{
+ public class TmdbUtilsCastTests
+ {
+ private static readonly PluginConfiguration _config = new() { MaxCastMembers = 10 };
+
+ [Fact]
+ public void MapAggregateCast_MemberWithSeveralRoles_YieldsOneCreditPerRole()
+ {
+ var cast = new List<CastAggregate>
+ {
+ CreateAggregate("Megumi Toyoguchi", 1, 0, ("Tabby (voice)", 3), ("Mimiru (voice)", 12))
+ };
+
+ var people = TmdbUtils.MapAggregateCast(cast, _config, _ => null).ToArray();
+
+ // The character they played the longest comes first, which is their own billing.
+ Assert.Equal(["Mimiru (voice)", "Tabby (voice)"], people.Select(p => p.Role));
+ Assert.All(people, p => Assert.Equal("Megumi Toyoguchi", p.Name));
+ Assert.All(people, p => Assert.Equal(PersonKind.Actor, p.Type));
+ Assert.All(people, p => Assert.Equal("1", p.GetProviderId(MetadataProvider.Tmdb)));
+ }
+
+ [Fact]
+ public void MapAggregateCast_MemberWithoutARole_IsStillCredited()
+ {
+ var cast = new List<CastAggregate> { CreateAggregate("Uncredited Actor", 2, 0) };
+
+ var person = Assert.Single(TmdbUtils.MapAggregateCast(cast, _config, _ => null));
+
+ Assert.Equal(string.Empty, person.Role);
+ }
+
+ [Fact]
+ public void MapAggregateCast_MoreThanConfigured_KeepsTheTopBilled()
+ {
+ var cast = Enumerable.Range(0, 5)
+ .Select(i => CreateAggregate($"Actor {4 - i}", i + 1, 4 - i, ($"Role {4 - i}", 1)))
+ .ToList();
+
+ var people = TmdbUtils.MapAggregateCast(cast, new PluginConfiguration { MaxCastMembers = 2 }, _ => null);
+
+ Assert.Equal(["Actor 0", "Actor 1"], people.Select(p => p.Name));
+ }
+
+ [Fact]
+ public void MapAggregateCast_HideMissingCastMembers_DropsTheOnesWithoutAProfile()
+ {
+ var withProfile = CreateAggregate("Has Profile", 1, 0, ("Hero", 1));
+ withProfile.ProfilePath = "/profile.jpg";
+ var cast = new List<CastAggregate> { withProfile, CreateAggregate("No Profile", 2, 1, ("Villain", 1)) };
+
+ var people = TmdbUtils.MapAggregateCast(
+ cast,
+ new PluginConfiguration { MaxCastMembers = 10, HideMissingCastMembers = true },
+ _ => null);
+
+ Assert.Equal(["Has Profile"], people.Select(p => p.Name));
+ }
+
+ [Fact]
+ public void MapCast_FlatCredits_YieldOneCreditEach()
+ {
+ var cast = new List<Cast>
+ {
+ new() { Name = "Kevin Conroy", Id = 1, Order = 0, Character = " Batman (voice) " },
+ new() { Name = " ", Id = 2, Order = 1, Character = "Nobody" }
+ };
+
+ var person = Assert.Single(TmdbUtils.MapCast(cast, _config, _ => null));
+
+ Assert.Equal("Kevin Conroy", person.Name);
+ Assert.Equal("Batman (voice)", person.Role);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void MapCast_NoCast_YieldsNothing(bool aggregate)
+ {
+ Assert.Empty(aggregate
+ ? TmdbUtils.MapAggregateCast(null, _config, _ => null)
+ : TmdbUtils.MapCast(null, _config, _ => null));
+ }
+
+ private static CastAggregate CreateAggregate(string name, int id, int order, params (string Character, int Episodes)[] roles)
+ {
+ return new CastAggregate
+ {
+ Name = name,
+ Id = id,
+ Order = order,
+ Roles = roles.Select(role => new CastRole { Character = role.Character, EpisodeCount = role.Episodes }).ToList()
+ };
+ }
+ }
+}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryPlayedOrderingTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryPlayedOrderingTests.cs
new file mode 100644
index 0000000000..c2518f13b2
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryPlayedOrderingTests.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Emby.Server.Implementations.Data;
+using Jellyfin.Database.Implementations;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
+using Jellyfin.Server.Implementations.Item;
+using MediaBrowser.Controller.Entities;
+using Xunit;
+using BaseItemKind = Jellyfin.Data.Enums.BaseItemKind;
+using ItemSortBy = Jellyfin.Data.Enums.ItemSortBy;
+using LinkedChildType = Jellyfin.Database.Implementations.Entities.LinkedChildType;
+
+namespace Jellyfin.Server.Implementations.Tests.Item;
+
+/// <summary>
+/// Covers ordering by <see cref="ItemSortBy.IsPlayed"/> and <see cref="ItemSortBy.IsUnplayed"/>, which
+/// has to read the played state the isPlayed filter reports: folders hold none of their own and count
+/// as played once no descendant is left unplayed.
+/// </summary>
+public sealed class BaseItemRepositoryPlayedOrderingTests : SqliteDbTestFixture
+{
+ private const string SeriesType = "MediaBrowser.Controller.Entities.TV.Series";
+ private const string EpisodeType = "MediaBrowser.Controller.Entities.TV.Episode";
+ private const string BoxSetType = "MediaBrowser.Controller.Entities.Movies.BoxSet";
+ private const string MovieType = "MediaBrowser.Controller.Entities.Movies.Movie";
+
+ private readonly BaseItemRepository _repository;
+ private readonly User _user = new("test", "auth-provider", "reset-provider");
+
+ // Names run A..F so name order interleaves the two groups: a dropped or inverted played key shows
+ // up as a different sequence rather than as the expected one by luck.
+ private readonly Guid _watchedSeries = Guid.NewGuid();
+ private readonly Guid _unwatchedSeries = Guid.NewGuid();
+ private readonly Guid _partiallyWatchedSeries = Guid.NewGuid();
+ private readonly Guid _secondUnwatchedSeries = Guid.NewGuid();
+ private readonly Guid _thirdUnwatchedSeries = Guid.NewGuid();
+ private readonly Guid _secondWatchedSeries = Guid.NewGuid();
+
+ // Box sets reach their children through LinkedChildren instead of the ancestor chain.
+ private readonly Guid _watchedBoxSet = Guid.NewGuid();
+ private readonly Guid _unwatchedBoxSet = Guid.NewGuid();
+
+ private readonly HashSet<Guid> _unwatchedSeriesIds;
+
+ public BaseItemRepositoryPlayedOrderingTests()
+ {
+ _unwatchedSeriesIds = [_unwatchedSeries, _partiallyWatchedSeries, _secondUnwatchedSeries, _thirdUnwatchedSeries];
+
+ using (var context = CreateDbContext())
+ {
+ Seed(context);
+ }
+
+ _repository = CreateBaseItemRepository(new ItemTypeLookup());
+ }
+
+ [Fact]
+ public void IsPlayed_OrdersUnwatchedSeriesBeforeWatchedOnes()
+ {
+ Assert.Equal(
+ [_unwatchedSeries, _partiallyWatchedSeries, _secondUnwatchedSeries, _thirdUnwatchedSeries, _watchedSeries, _secondWatchedSeries],
+ SeriesIds(ItemSortBy.IsPlayed));
+ }
+
+ [Fact]
+ public void IsPlayed_CountsAPartiallyWatchedSeriesAsUnwatched()
+ {
+ var ids = SeriesIds(ItemSortBy.IsPlayed);
+
+ Assert.True(ids.IndexOf(_partiallyWatchedSeries) < ids.IndexOf(_watchedSeries));
+ }
+
+ [Fact]
+ public void IsUnplayed_ReversesTheGroups()
+ {
+ Assert.Equal(
+ [_watchedSeries, _secondWatchedSeries, _unwatchedSeries, _partiallyWatchedSeries, _secondUnwatchedSeries, _thirdUnwatchedSeries],
+ SeriesIds(ItemSortBy.IsUnplayed));
+ }
+
+ [Fact]
+ public void IsPlayed_OrdersAnUnwatchedBoxSetBeforeAWatchedOne()
+ {
+ var ids = _repository
+ .GetItemList(Query(BaseItemKind.BoxSet, (ItemSortBy.IsPlayed, SortOrder.Ascending)))
+ .Select(i => i.Id);
+
+ Assert.Equal([_unwatchedBoxSet, _watchedBoxSet], ids);
+ }
+
+ [Fact]
+ public void IsPlayedThenRandom_StillPlacesEveryUnwatchedSeriesFirst()
+ {
+ var order = _repository
+ .GetItemList(Query(BaseItemKind.Series, (ItemSortBy.IsPlayed, SortOrder.Ascending), (ItemSortBy.Random, SortOrder.Ascending)))
+ .Select(i => i.Id);
+
+ Assert.Equal(_unwatchedSeriesIds, order.Take(_unwatchedSeriesIds.Count).ToHashSet());
+ }
+
+ [Fact]
+ public void IsPlayedThenRandom_FillsAPageWithUnwatchedSeries()
+ {
+ var page = _repository.GetItems(new InternalItemsQuery(_user)
+ {
+ IncludeItemTypes = [BaseItemKind.Series],
+ OrderBy = [(ItemSortBy.IsPlayed, SortOrder.Ascending), (ItemSortBy.Random, SortOrder.Ascending)],
+ Limit = 4,
+ EnableTotalRecordCount = true
+ });
+
+ Assert.Equal(6, page.TotalRecordCount);
+ Assert.Equal(_unwatchedSeriesIds, page.Items.Select(i => i.Id).ToHashSet());
+ }
+
+ private List<Guid> SeriesIds(ItemSortBy sortBy)
+ => _repository
+ .GetItemList(Query(BaseItemKind.Series, (sortBy, SortOrder.Ascending)))
+ .Select(i => i.Id)
+ .ToList();
+
+ private InternalItemsQuery Query(BaseItemKind kind, params (ItemSortBy OrderBy, SortOrder SortOrder)[] orderBy)
+ => new(_user)
+ {
+ IncludeItemTypes = [kind],
+ OrderBy = orderBy
+ };
+
+ private void Seed(JellyfinDbContext context)
+ {
+ context.Users.Add(_user);
+
+ AddSeries(context, _watchedSeries, "A watched", playedEpisodes: 1, unplayedEpisodes: 0);
+ AddSeries(context, _unwatchedSeries, "B unwatched", playedEpisodes: 0, unplayedEpisodes: 1);
+ AddSeries(context, _partiallyWatchedSeries, "C partially watched", playedEpisodes: 1, unplayedEpisodes: 1);
+ AddSeries(context, _secondUnwatchedSeries, "D unwatched", playedEpisodes: 0, unplayedEpisodes: 1);
+ AddSeries(context, _thirdUnwatchedSeries, "E unwatched", playedEpisodes: 0, unplayedEpisodes: 1);
+ AddSeries(context, _secondWatchedSeries, "F watched", playedEpisodes: 1, unplayedEpisodes: 0);
+
+ AddBoxSet(context, _watchedBoxSet, "A watched set", played: true);
+ AddBoxSet(context, _unwatchedBoxSet, "B unwatched set", played: false);
+
+ context.SaveChanges();
+ }
+
+ private void AddSeries(JellyfinDbContext context, Guid id, string name, int playedEpisodes, int unplayedEpisodes)
+ {
+ context.BaseItems.Add(new BaseItemEntity { Id = id, Type = SeriesType, Name = name, SortName = name, PresentationUniqueKey = id.ToString("N"), IsFolder = true });
+
+ for (var i = 0; i < playedEpisodes + unplayedEpisodes; i++)
+ {
+ var episodeId = Guid.NewGuid();
+ context.BaseItems.Add(new BaseItemEntity { Id = episodeId, Type = EpisodeType, Name = $"{name} {i}", PresentationUniqueKey = episodeId.ToString("N"), SeriesId = id });
+ context.AncestorIds.Add(new AncestorId { ItemId = episodeId, ParentItemId = id, Item = null!, ParentItem = null! });
+
+ if (i < playedEpisodes)
+ {
+ AddPlayedUserData(context, episodeId);
+ }
+ }
+ }
+
+ private void AddBoxSet(JellyfinDbContext context, Guid id, string name, bool played)
+ {
+ var movieId = Guid.NewGuid();
+
+ context.BaseItems.Add(new BaseItemEntity { Id = id, Type = BoxSetType, Name = name, SortName = name, PresentationUniqueKey = id.ToString("N"), IsFolder = true });
+ context.BaseItems.Add(new BaseItemEntity { Id = movieId, Type = MovieType, Name = $"{name} movie", PresentationUniqueKey = movieId.ToString("N") });
+ context.LinkedChildren.Add(new LinkedChildEntity { ParentId = id, ChildId = movieId, ChildType = LinkedChildType.Manual, SortOrder = 0 });
+
+ if (played)
+ {
+ AddPlayedUserData(context, movieId);
+ }
+ }
+
+ private void AddPlayedUserData(JellyfinDbContext context, Guid itemId)
+ => context.UserData.Add(new UserData
+ {
+ ItemId = itemId,
+ UserId = _user.Id,
+ CustomDataKey = itemId.ToString("N"),
+ Played = true,
+ Item = null!,
+ User = null!
+ });
+}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs
index 54565c5787..649458f733 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs
@@ -142,6 +142,79 @@ public sealed class PeopleRepositoryUpdatePeopleTests : SqliteDbTestFixture
Assert.Equal("Hero", map.Role);
}
+ [Fact]
+ public void UpdatePeople_CreditDroppedByTheProvider_LeavesNoCreditRowBehind()
+ {
+ _repository.UpdatePeople(_itemId, [
+ CreatePerson("Person A", PersonKind.Actor, "Hero"),
+ CreatePerson("Person B", PersonKind.Actor, "Villain")
+ ]);
+
+ _repository.UpdatePeople(_itemId, [CreatePerson("Person A", PersonKind.Actor, "Hero")]);
+
+ using var ctx = CreateDbContext();
+ Assert.Equal(["Person A"], ctx.Peoples.Select(e => e.Name).ToArray());
+ }
+
+ [Fact]
+ public void UpdatePeople_CreditStillHeldByAnotherItem_IsKept()
+ {
+ _repository.UpdatePeople(_itemId, [CreatePerson("Person A", PersonKind.Actor, "Hero")]);
+ _repository.UpdatePeople(AddMovie("Other Movie"), [CreatePerson("Person A", PersonKind.Actor, "Hero")]);
+
+ _repository.UpdatePeople(_itemId, []);
+
+ using var after = CreateDbContext();
+ Assert.Single(after.Peoples);
+ Assert.Single(after.PeopleBaseItemMap);
+ }
+
+ [Fact]
+ public void DeleteOrphanedCredits_CreditNoItemMapsTo_IsDeleted()
+ {
+ _repository.UpdatePeople(_itemId, [CreatePerson("Person A", PersonKind.Actor, "Hero")]);
+ using (var ctx = CreateDbContext())
+ {
+ // The state a credit was left in before UpdatePeople cleaned up after itself.
+ ctx.PeopleBaseItemMap.RemoveRange(ctx.PeopleBaseItemMap);
+ ctx.SaveChanges();
+ }
+
+ Assert.Equal(1, _repository.DeleteOrphanedCredits());
+
+ using var after = CreateDbContext();
+ Assert.Empty(after.Peoples);
+ }
+
+ [Fact]
+ public void DeleteOrphanedCredits_CreditAnItemMapsTo_IsKept()
+ {
+ _repository.UpdatePeople(_itemId, [CreatePerson("Person A", PersonKind.Actor, "Hero")]);
+
+ Assert.Equal(0, _repository.DeleteOrphanedCredits());
+
+ using var after = CreateDbContext();
+ Assert.Single(after.Peoples);
+ }
+
+ private Guid AddMovie(string name)
+ {
+ var id = Guid.NewGuid();
+ using var ctx = CreateDbContext();
+ ctx.BaseItems.Add(new BaseItemEntity
+ {
+ Id = id,
+ Type = new ItemTypeLookup().BaseItemKindNames[BaseItemKind.Movie],
+ Name = name,
+ MediaType = "Video",
+ IsMovie = true,
+ IsFolder = false,
+ IsVirtualItem = false
+ });
+ ctx.SaveChanges();
+ return id;
+ }
+
private static PersonInfo CreatePerson(string name, PersonKind type, string role)
{
return new PersonInfo
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/SeasonResolverTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/SeasonResolverTests.cs
index 133a3f7d47..feb2d8a625 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/SeasonResolverTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/SeasonResolverTests.cs
@@ -21,7 +21,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library
{
var localizationMock = new Mock<ILocalizationManager>();
localizationMock
- .Setup(l => l.GetLocalizedString(It.IsAny<string>()))
+ .Setup(l => l.GetServerLocalizedString(It.IsAny<string>()))
.Returns("Season {0}");
_resolver = new SeasonResolver(