diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/AudioResolverTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/AudioResolverTests.cs new file mode 100644 index 0000000000..ca5829f10a --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/AudioResolverTests.cs @@ -0,0 +1,73 @@ +using System.Linq; +using Emby.Naming.Common; +using Emby.Server.Implementations.Library.Resolvers.Audio; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.IO; +using Moq; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.Library; + +public class AudioResolverTests +{ + private static readonly NamingOptions _namingOptions = new(); + + [Theory] + [InlineData("words.mp3")] // single non-tagged file + [InlineData("chapter 01.mp3")] + [InlineData("part 1.mp3")] + [InlineData("chapter 01.mp3", "non-media.txt")] + [InlineData("title.mp3", "title.epub")] + [InlineData("01.mp3", "subdirectory/")] // single media file with sub-directory - note that this will hide any contents in the subdirectory + public void Resolve_AudiobookDirectory_SingleResult(params string[] children) + { + var resolved = TestResolveChildren("/parent/title", children); + Assert.NotNull(resolved); + } + + [Theory] + /* Results that can't be displayed as an audio book. */ + [InlineData] // no contents + [InlineData("subdirectory/")] + [InlineData("non-media.txt")] + /* Names don't indicate parts of a single book. */ + [InlineData("Name.mp3", "Another Name.mp3")] + /* Results that are an audio book but not currently navigable as such (multiple chapters and/or parts). */ + [InlineData("01.mp3", "02.mp3")] + [InlineData("chapter 01.mp3", "chapter 02.mp3")] + [InlineData("part 1.mp3", "part 2.mp3")] + [InlineData("chapter 01 part 01.mp3", "chapter 01 part 02.mp3")] + /* Mismatched chapters, parts, and named files. */ + [InlineData("chapter 01.mp3", "part 2.mp3")] + public void Resolve_AudiobookDirectory_NoResult(params string[] children) + { + var resolved = TestResolveChildren("/parent/book title", children); + Assert.Null(resolved); + } + + private Audio? TestResolveChildren(string parent, string[] children) + { + var childrenMetadata = children.Select(name => new FileSystemMetadata + { + FullName = parent + "/" + name, + IsDirectory = name.EndsWith('/') + }).ToArray(); + + var resolver = new AudioResolver(_namingOptions); + var itemResolveArgs = new ItemResolveArgs( + null, + Mock.Of()) + { + CollectionType = "books", + FileInfo = new FileSystemMetadata + { + FullName = parent, + IsDirectory = true + }, + FileSystemChildren = childrenMetadata + }; + + return resolver.Resolve(itemResolveArgs); + } +}