diff options
Diffstat (limited to 'tests')
11 files changed, 516 insertions, 3 deletions
diff --git a/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs new file mode 100644 index 000000000..a2f5c2501 --- /dev/null +++ b/tests/Jellyfin.Api.Tests/Auth/CustomAuthenticationHandlerTests.cs @@ -0,0 +1,175 @@ +using System; +using System.Linq; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using AutoFixture; +using AutoFixture.AutoMoq; +using Jellyfin.Api.Auth; +using Jellyfin.Api.Constants; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Net; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +namespace Jellyfin.Api.Tests.Auth +{ + public class CustomAuthenticationHandlerTests + { + private readonly IFixture _fixture; + + private readonly Mock<IAuthService> _jellyfinAuthServiceMock; + private readonly Mock<IOptionsMonitor<AuthenticationSchemeOptions>> _optionsMonitorMock; + private readonly Mock<ISystemClock> _clockMock; + private readonly Mock<IServiceProvider> _serviceProviderMock; + private readonly Mock<IAuthenticationService> _authenticationServiceMock; + private readonly UrlEncoder _urlEncoder; + private readonly HttpContext _context; + + private readonly CustomAuthenticationHandler _sut; + private readonly AuthenticationScheme _scheme; + + public CustomAuthenticationHandlerTests() + { + var fixtureCustomizations = new AutoMoqCustomization + { + ConfigureMembers = true + }; + + _fixture = new Fixture().Customize(fixtureCustomizations); + AllowFixtureCircularDependencies(); + + _jellyfinAuthServiceMock = _fixture.Freeze<Mock<IAuthService>>(); + _optionsMonitorMock = _fixture.Freeze<Mock<IOptionsMonitor<AuthenticationSchemeOptions>>>(); + _clockMock = _fixture.Freeze<Mock<ISystemClock>>(); + _serviceProviderMock = _fixture.Freeze<Mock<IServiceProvider>>(); + _authenticationServiceMock = _fixture.Freeze<Mock<IAuthenticationService>>(); + _fixture.Register<ILoggerFactory>(() => new NullLoggerFactory()); + + _urlEncoder = UrlEncoder.Default; + + _serviceProviderMock.Setup(s => s.GetService(typeof(IAuthenticationService))) + .Returns(_authenticationServiceMock.Object); + + _optionsMonitorMock.Setup(o => o.Get(It.IsAny<string>())) + .Returns(new AuthenticationSchemeOptions + { + ForwardAuthenticate = null + }); + + _context = new DefaultHttpContext + { + RequestServices = _serviceProviderMock.Object + }; + + _scheme = new AuthenticationScheme( + _fixture.Create<string>(), + null, + typeof(CustomAuthenticationHandler)); + + _sut = _fixture.Create<CustomAuthenticationHandler>(); + _sut.InitializeAsync(_scheme, _context).Wait(); + } + + [Fact] + public async Task HandleAuthenticateAsyncShouldFailWithNullUser() + { + _jellyfinAuthServiceMock.Setup( + a => a.Authenticate( + It.IsAny<HttpRequest>(), + It.IsAny<AuthenticatedAttribute>())) + .Returns((User)null); + + var authenticateResult = await _sut.AuthenticateAsync(); + + Assert.False(authenticateResult.Succeeded); + Assert.Equal("Invalid user", authenticateResult.Failure.Message); + } + + [Fact] + public async Task HandleAuthenticateAsyncShouldFailOnSecurityException() + { + var errorMessage = _fixture.Create<string>(); + + _jellyfinAuthServiceMock.Setup( + a => a.Authenticate( + It.IsAny<HttpRequest>(), + It.IsAny<AuthenticatedAttribute>())) + .Throws(new SecurityException(errorMessage)); + + var authenticateResult = await _sut.AuthenticateAsync(); + + Assert.False(authenticateResult.Succeeded); + Assert.Equal(errorMessage, authenticateResult.Failure.Message); + } + + [Fact] + public async Task HandleAuthenticateAsyncShouldSucceedWithUser() + { + SetupUser(); + var authenticateResult = await _sut.AuthenticateAsync(); + + Assert.True(authenticateResult.Succeeded); + Assert.Null(authenticateResult.Failure); + } + + [Fact] + public async Task HandleAuthenticateAsyncShouldAssignNameClaim() + { + var user = SetupUser(); + var authenticateResult = await _sut.AuthenticateAsync(); + + Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Name, user.Name)); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task HandleAuthenticateAsyncShouldAssignRoleClaim(bool isAdmin) + { + var user = SetupUser(isAdmin); + var authenticateResult = await _sut.AuthenticateAsync(); + + var expectedRole = user.Policy.IsAdministrator ? UserRoles.Administrator : UserRoles.User; + Assert.True(authenticateResult.Principal.HasClaim(ClaimTypes.Role, expectedRole)); + } + + [Fact] + public async Task HandleAuthenticateAsyncShouldAssignTicketCorrectScheme() + { + SetupUser(); + var authenticatedResult = await _sut.AuthenticateAsync(); + + Assert.Equal(_scheme.Name, authenticatedResult.Ticket.AuthenticationScheme); + } + + private User SetupUser(bool isAdmin = false) + { + var user = _fixture.Create<User>(); + user.Policy.IsAdministrator = isAdmin; + + _jellyfinAuthServiceMock.Setup( + a => a.Authenticate( + It.IsAny<HttpRequest>(), + It.IsAny<AuthenticatedAttribute>())) + .Returns(user); + + return user; + } + + private void AllowFixtureCircularDependencies() + { + // A circular dependency exists in the User entity around parent folders, + // this allows Autofixture to generate a User regardless, rather than throw + // an error. + _fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList() + .ForEach(b => _fixture.Behaviors.Remove(b)); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + } + } +} diff --git a/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandlerTests.cs new file mode 100644 index 000000000..84cdbe360 --- /dev/null +++ b/tests/Jellyfin.Api.Tests/Auth/FirstTimeSetupOrElevatedPolicy/FirstTimeSetupOrElevatedHandlerTests.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using AutoFixture; +using AutoFixture.AutoMoq; +using Jellyfin.Api.Auth.FirstTimeSetupOrElevatedPolicy; +using Jellyfin.Api.Constants; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Configuration; +using Microsoft.AspNetCore.Authorization; +using Moq; +using Xunit; + +namespace Jellyfin.Api.Tests.Auth.FirstTimeSetupOrElevatedPolicy +{ + public class FirstTimeSetupOrElevatedHandlerTests + { + private readonly Mock<IConfigurationManager> _configurationManagerMock; + private readonly List<IAuthorizationRequirement> _requirements; + private readonly FirstTimeSetupOrElevatedHandler _sut; + + public FirstTimeSetupOrElevatedHandlerTests() + { + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + _configurationManagerMock = fixture.Freeze<Mock<IConfigurationManager>>(); + _requirements = new List<IAuthorizationRequirement> {new FirstTimeSetupOrElevatedRequirement()}; + + _sut = fixture.Create<FirstTimeSetupOrElevatedHandler>(); + } + + [Theory] + [InlineData(UserRoles.Administrator)] + [InlineData(UserRoles.Guest)] + [InlineData(UserRoles.User)] + public async Task ShouldSucceedIfStartupWizardIncomplete(string userRole) + { + SetupConfigurationManager(false); + var user = SetupUser(userRole); + var context = new AuthorizationHandlerContext(_requirements, user, null); + + await _sut.HandleAsync(context); + Assert.True(context.HasSucceeded); + } + + [Theory] + [InlineData(UserRoles.Administrator, true)] + [InlineData(UserRoles.Guest, false)] + [InlineData(UserRoles.User, false)] + public async Task ShouldRequireAdministratorIfStartupWizardComplete(string userRole, bool shouldSucceed) + { + SetupConfigurationManager(true); + var user = SetupUser(userRole); + var context = new AuthorizationHandlerContext(_requirements, user, null); + + await _sut.HandleAsync(context); + Assert.Equal(shouldSucceed, context.HasSucceeded); + } + + private static ClaimsPrincipal SetupUser(string role) + { + var claims = new[] {new Claim(ClaimTypes.Role, role)}; + var identity = new ClaimsIdentity(claims); + return new ClaimsPrincipal(identity); + } + + private void SetupConfigurationManager(bool startupWizardCompleted) + { + var commonConfiguration = new BaseApplicationConfiguration + { + IsStartupWizardCompleted = startupWizardCompleted + }; + + _configurationManagerMock.Setup(c => c.CommonConfiguration) + .Returns(commonConfiguration); + } + } +} diff --git a/tests/Jellyfin.Api.Tests/Auth/RequiresElevationPolicy/RequiresElevationHandlerTests.cs b/tests/Jellyfin.Api.Tests/Auth/RequiresElevationPolicy/RequiresElevationHandlerTests.cs new file mode 100644 index 000000000..e2beea1ad --- /dev/null +++ b/tests/Jellyfin.Api.Tests/Auth/RequiresElevationPolicy/RequiresElevationHandlerTests.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using Jellyfin.Api.Auth.RequiresElevationPolicy; +using Jellyfin.Api.Constants; +using Microsoft.AspNetCore.Authorization; +using Xunit; + +namespace Jellyfin.Api.Tests.Auth.RequiresElevationPolicy +{ + public class RequiresElevationHandlerTests + { + private readonly RequiresElevationHandler _sut; + + public RequiresElevationHandlerTests() + { + _sut = new RequiresElevationHandler(); + } + + [Theory] + [InlineData(UserRoles.Administrator, true)] + [InlineData(UserRoles.User, false)] + [InlineData(UserRoles.Guest, false)] + public async Task ShouldHandleRolesCorrectly(string role, bool shouldSucceed) + { + var requirements = new List<IAuthorizationRequirement> {new RequiresElevationRequirement()}; + + var claims = new[] {new Claim(ClaimTypes.Role, role)}; + var identity = new ClaimsIdentity(claims); + var user = new ClaimsPrincipal(identity); + + var context = new AuthorizationHandlerContext(requirements, user, null); + + await _sut.HandleAsync(context); + Assert.Equal(shouldSucceed, context.HasSucceeded); + } + } +} diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj index e0deeeabb..1f83489bd 100644 --- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj +++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj @@ -6,6 +6,10 @@ </PropertyGroup> <ItemGroup> + <PackageReference Include="AutoFixture" Version="4.11.0" /> + <PackageReference Include="AutoFixture.AutoMoq" Version="4.11.0" /> + <PackageReference Include="AutoFixture.Xunit2" Version="4.11.0" /> + <PackageReference Include="Microsoft.Extensions.Options" Version="3.0.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> @@ -15,6 +19,7 @@ <ItemGroup> <ProjectReference Include="../../MediaBrowser.Api/MediaBrowser.Api.csproj" /> + <ProjectReference Include="../../Jellyfin.Api/Jellyfin.Api.csproj" /> </ItemGroup> </Project> diff --git a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs index 12fde0770..c46c9578b 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/EncoderValidatorTestsData.cs @@ -26,7 +26,7 @@ libswscale 5. 5.100 / 5. 5.100 libswresample 3. 5.100 / 3. 5.100 libpostproc 55. 5.100 / 55. 5.100"; - public const string FFmpegV414Output = @"ffmpeg version 4.1.4-1~deb10u1 Copyright (c) 2000-2019 the FFmpeg developers + public const string FFmpegV414Output = @"ffmpeg version 4.1.4-1~deb10u1 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 8 (Raspbian 8.3.0-6+rpi1) configuration: --prefix=/usr --extra-version='1~deb10u1' --toolchain=hardened --libdir=/usr/lib/arm-linux-gnueabihf --incdir=/usr/include/arm-linux-gnueabihf --arch=arm --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared libavutil 56. 22.100 / 56. 22.100 @@ -39,7 +39,7 @@ libswscale 5. 3.100 / 5. 3.100 libswresample 3. 3.100 / 3. 3.100 libpostproc 55. 3.100 / 55. 3.100"; - public const string FFmpegV404Output = @"ffmpeg version 4.0.4 Copyright (c) 2000-2019 the FFmpeg developers + public const string FFmpegV404Output = @"ffmpeg version 4.0.4 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 8 (Debian 8.3.0-6) configuration: --toolchain=hardened --prefix=/usr --target-os=linux --enable-cross-compile --extra-cflags=--static --enable-gpl --enable-static --disable-doc --disable-ffplay --disable-shared --disable-libxcb --disable-sdl2 --disable-xlib --enable-libfontconfig --enable-fontconfig --enable-gmp --enable-gnutls --enable-libass --enable-libbluray --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libwebp --enable-libx264 --enable-libx265 --enable-libzvbi --enable-omx --enable-omx-rpi --enable-version3 --enable-vaapi --enable-vdpau --arch=amd64 --enable-nvenc --enable-nvdec libavutil 56. 14.100 / 56. 14.100 @@ -51,7 +51,7 @@ libswscale 5. 1.100 / 5. 1.100 libswresample 3. 1.100 / 3. 1.100 libpostproc 55. 1.100 / 55. 1.100"; - public const string FFmpegGitUnknownOutput = @"ffmpeg version N-94303-g7cb4f8c962 Copyright (c) 2000-2019 the FFmpeg developers + public const string FFmpegGitUnknownOutput = @"ffmpeg version N-94303-g7cb4f8c962 Copyright (c) 2000-2019 the FFmpeg developers built with gcc 9.1.1 (GCC) 20190716 configuration: --enable-gpl --enable-version3 --enable-sdl2 --enable-fontconfig --enable-gnutls --enable-iconv --enable-libass --enable-libdav1d --enable-libbluray --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libtheora --enable-libtwolame --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libzimg --enable-lzma --enable-zlib --enable-gmp --enable-libvidstab --enable-libvorbis --enable-libvo-amrwbenc --enable-libmysofa --enable-libspeex --enable-libxvid --enable-libaom --enable-libmfx --enable-amf --enable-ffnvcodec --enable-cuvid --enable-d3d11va --enable-nvenc --enable-nvdec --enable-dxva2 --enable-avisynth --enable-libopenmpt libavutil 56. 30.100 / 56. 30.100 diff --git a/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs new file mode 100644 index 000000000..2032f6cec --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/FFprobeParserTests.cs @@ -0,0 +1,22 @@ +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using MediaBrowser.MediaEncoding.Probing; +using Xunit; + +namespace Jellyfin.MediaEncoding.Tests +{ + public class FFprobeParserTests + { + [Theory] + [InlineData("ffprobe1.json")] + public async Task Test(string fileName) + { + var path = Path.Join("Test Data", fileName); + using (var stream = File.OpenRead(path)) + { + await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream).ConfigureAwait(false); + } + } + } +} diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index 7f6b90533..5d9b32086 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -6,6 +6,12 @@ </PropertyGroup> <ItemGroup> + <None Include="Test Data\**\*.*"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> + </ItemGroup> + + <ItemGroup> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/ffprobe1.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/ffprobe1.json new file mode 100644 index 000000000..cdad5df50 --- /dev/null +++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/ffprobe1.json @@ -0,0 +1,105 @@ +{ + "streams": [ + { + "index": 0, + "codec_name": "h264", + "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10", + "profile": "Main", + "codec_type": "video", + "codec_time_base": "1/50", + "codec_tag_string": "[27][0][0][0]", + "codec_tag": "0x001b", + "width": 1920, + "height": 1080, + "coded_width": 1920, + "coded_height": 1080, + "has_b_frames": 0, + "sample_aspect_ratio": "0:1", + "display_aspect_ratio": "0:1", + "pix_fmt": "yuvj420p", + "level": 42, + "color_range": "pc", + "color_space": "bt709", + "color_transfer": "bt709", + "color_primaries": "bt709", + "chroma_location": "left", + "field_order": "progressive", + "refs": 1, + "is_avc": "false", + "nal_length_size": "0", + "id": "0x1", + "r_frame_rate": "25/1", + "avg_frame_rate": "25/1", + "time_base": "1/90000", + "start_pts": 8570867078, + "start_time": "95231.856422", + "duration_ts": 31694552, + "duration": "352.161689", + "bits_per_raw_sample": "8", + "disposition": { + "default": 0, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0 + } + }, + { + "index": 1, + "codec_name": "aac", + "codec_long_name": "AAC (Advanced Audio Coding)", + "profile": "LC", + "codec_type": "audio", + "codec_time_base": "1/44100", + "codec_tag_string": "[15][0][0][0]", + "codec_tag": "0x000f", + "sample_fmt": "fltp", + "sample_rate": "44100", + "channels": 2, + "channel_layout": "stereo", + "bits_per_sample": 0, + "id": "0x2", + "r_frame_rate": "0/0", + "avg_frame_rate": "0/0", + "time_base": "1/90000", + "start_pts": 8570867697, + "start_time": "95231.863300", + "duration_ts": 31695687, + "duration": "352.174300", + "bit_rate": "98191", + "disposition": { + "default": 0, + "dub": 0, + "original": 0, + "comment": 0, + "lyrics": 0, + "karaoke": 0, + "forced": 0, + "hearing_impaired": 0, + "visual_impaired": 0, + "clean_effects": 0, + "attached_pic": 0, + "timed_thumbnails": 0 + } + } + ], + "format": { + "filename": "TS Test record.ts", + "nb_streams": 2, + "nb_programs": 1, + "format_name": "mpegts", + "format_long_name": "MPEG-TS (MPEG-2 Transport Stream)", + "start_time": "95231.856422", + "duration": "352.181178", + "size": "179003772", + "bit_rate": "4066174", + "probe_score": 50 + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs new file mode 100644 index 000000000..e324002f0 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/IO/ManagedFileSystemTests.cs @@ -0,0 +1,43 @@ +using System; +using AutoFixture; +using AutoFixture.AutoMoq; +using Emby.Server.Implementations.IO; +using MediaBrowser.Model.System; +using Xunit; + +namespace Jellyfin.Server.Implementations.Tests.IO +{ + public class ManagedFileSystemTests + { + private readonly IFixture _fixture; + private readonly ManagedFileSystem _sut; + + public ManagedFileSystemTests() + { + _fixture = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true }); + _sut = _fixture.Create<ManagedFileSystem>(); + } + + [Theory] + [InlineData("/Volumes/Library/Sample/Music/Playlists/", "../Beethoven/Misc/Moonlight Sonata.mp3", "/Volumes/Library/Sample/Music/Beethoven/Misc/Moonlight Sonata.mp3")] + [InlineData("/Volumes/Library/Sample/Music/Playlists/", "../../Beethoven/Misc/Moonlight Sonata.mp3", "/Volumes/Library/Sample/Beethoven/Misc/Moonlight Sonata.mp3")] + [InlineData("/Volumes/Library/Sample/Music/Playlists/", "Beethoven/Misc/Moonlight Sonata.mp3", "/Volumes/Library/Sample/Music/Playlists/Beethoven/Misc/Moonlight Sonata.mp3")] + public void MakeAbsolutePathCorrectlyHandlesRelativeFilePaths( + string folderPath, + string filePath, + string expectedAbsolutePath) + { + var generatedPath = _sut.MakeAbsolutePath(folderPath, filePath); + + if (MediaBrowser.Common.System.OperatingSystem.Id == OperatingSystemId.Windows) + { + var expectedWindowsPath = expectedAbsolutePath.Replace('/', '\\'); + Assert.Equal(expectedWindowsPath, generatedPath.Split(':')[1]); + } + else + { + Assert.Equal(expectedAbsolutePath, generatedPath); + } + } + } +} diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj new file mode 100644 index 000000000..bb2afea16 --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj @@ -0,0 +1,25 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFramework>netcoreapp3.1</TargetFramework> + + <IsPackable>false</IsPackable> + + <RootNamespace>Jellyfin.Server.Implementations.Tests</RootNamespace> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="AutoFixture" Version="4.11.0" /> + <PackageReference Include="AutoFixture.AutoMoq" Version="4.11.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> + <PackageReference Include="Moq" Version="4.13.1" /> + <PackageReference Include="xunit" Version="2.4.0" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> + <PackageReference Include="coverlet.collector" Version="1.0.1" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\..\Emby.Server.Implementations\Emby.Server.Implementations.csproj" /> + </ItemGroup> + +</Project> diff --git a/tests/coverletArgs.runsettings b/tests/coverletArgs.runsettings new file mode 100644 index 000000000..3113957e0 --- /dev/null +++ b/tests/coverletArgs.runsettings @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8" ?> +<RunSettings> + <DataCollectionRunSettings> + <DataCollectors> + <DataCollector friendlyName="XPlat code coverage"> + <Configuration> + <Format>cobertura</Format> + <Exclude>[coverlet.*.tests?]*,[*]Coverlet.Core*,[*]Moq*</Exclude> <!-- [Assembly-Filter]Type-Filter --> + <ExcludeByAttribute>Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute</ExcludeByAttribute> + <SingleHit>false</SingleHit> + <UseSourceLink>true</UseSourceLink> + <IncludeTestAssembly>false</IncludeTestAssembly> + </Configuration> + </DataCollector> + </DataCollectors> + </DataCollectionRunSettings> +</RunSettings>
\ No newline at end of file |
