using System; 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; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaSegments; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Querying; using Moq; using Xunit; 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(); fileSystem.Setup(x => x.GetValidFilename(It.IsAny())).Returns((string name) => name); BaseItem.FileSystem = fileSystem.Object; } [Theory] [InlineData("", "")] [InlineData("1", "0000000001")] [InlineData("t", "t")] [InlineData("test", "test")] [InlineData("test1", "test0000000001")] [InlineData("1test 2", "0000000001test 0000000002")] public void BaseItem_ModifySortChunks_Valid(string input, string expected) => Assert.Equal(expected, BaseItem.ModifySortChunks(input)); [Theory] [InlineData("The Matrix", "matrix")] [InlineData("Spider-Man", "spiderman")] [InlineData("A Movie: Part 2", "movie: part 0000000002")] public void GetSortName_AppliesConfiguredCleaning(string input, string expected) => Assert.Equal(expected, BaseItem.GetSortName(input, true, new ServerConfiguration())); [Fact] public void GetSortName_WithoutAlphaNumericSorting_ReturnsTrimmedInput() => Assert.Equal("The Matrix", BaseItem.GetSortName(" The Matrix", false, new ServerConfiguration())); [Fact] public void SortName_ForcedSortName_IsCleanedLikeAutoSortName() { var configManager = new Mock(); configManager.Setup(x => x.Configuration).Returns(new ServerConfiguration()); BaseItem.ConfigurationManager = configManager.Object; const string Raw = "The Spider-Man: Homecoming"; var auto = new Video { Name = Raw }; var forced = new Video { Name = "zzz unrelated name", ForcedSortName = Raw }; // A forced sort name must be cleaned the same way as an auto-generated one so both sort together (#17388). Assert.Equal(auto.SortName, forced.SortName); // Sanity: cleaning actually ran (leading article and hyphen removed, colon kept, lowercased). Assert.Equal("spiderman: homecoming", forced.SortName); } [Theory] [InlineData("/Movies/Ted/Ted.mp4", "/Movies/Ted/Ted - Unrated Edition.mp4", "Ted", "Unrated Edition")] [InlineData("/Movies/Deadpool 2 (2018)/Deadpool 2 (2018).mkv", "/Movies/Deadpool 2 (2018)/Deadpool 2 (2018) - Super Duper Cut.mkv", "Deadpool 2 (2018)", "Super Duper Cut")] public void GetMediaSourceName_Valid(string primaryPath, string altPath, string name, string altName) { var video = new Video() { Path = primaryPath }; var videoAlt = new Video() { Path = altPath, }; var mediaSourceManager = new Mock(); mediaSourceManager.Setup(x => x.GetPathProtocol(It.IsAny())) .Returns((string x) => MediaProtocol.File); var libraryManager = new Mock(); libraryManager.Setup(x => x.GetLocalAlternateVersionIds(It.IsAny