Merge pull request #17715 from Shadowghost/fix-people-cleanup
Delete credits nothing maps to and bound item-by-name folder names
This commit is contained in:
@@ -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")]
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user