Merge remote-tracking branch 'upstream/master' into SubnetOverlappFix

This commit is contained in:
BaronGreenback
2021-03-14 18:40:44 +00:00
199 changed files with 1576 additions and 1074 deletions

View File

@@ -10,6 +10,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -27,22 +29,14 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Jellyfin.Server\Jellyfin.Server.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="TestPage.html" />
<ProjectReference Include="../../Jellyfin.Api/Jellyfin.Api.csproj" />
<ProjectReference Include="../../Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,33 @@
using System;
using System.Text;
using MediaBrowser.Common;
using Xunit;
namespace Jellyfin.Common.Tests
{
public static class Crc32Tests
{
[Fact]
public static void Compute_Empty_Zero()
{
Assert.Equal<uint>(0, Crc32.Compute(Array.Empty<byte>()));
}
[Theory]
[InlineData(0x414fa339, "The quick brown fox jumps over the lazy dog")]
public static void Compute_Valid_Success(uint expected, string data)
{
Assert.Equal(expected, Crc32.Compute(Encoding.UTF8.GetBytes(data)));
}
[Theory]
[InlineData(0x414fa339, "54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F67")]
[InlineData(0x190a55ad, "0000000000000000000000000000000000000000000000000000000000000000")]
[InlineData(0xff6cab0b, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")]
[InlineData(0x91267e8a, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")]
public static void Compute_ValidHex_Success(uint expected, string data)
{
Assert.Equal(expected, Crc32.Compute(Convert.FromHexString(data)));
}
}
}

View File

@@ -10,6 +10,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -21,7 +23,6 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
@@ -32,8 +33,4 @@
<ProjectReference Include="../../MediaBrowser.Providers/MediaBrowser.Providers.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,36 @@
using System;
using System.Text.Json;
using MediaBrowser.Common.Json.Converters;
using Xunit;
namespace Jellyfin.Common.Tests.Json
{
public class JsonVersionConverterTests
{
private readonly JsonSerializerOptions _options;
public JsonVersionConverterTests()
{
_options = new JsonSerializerOptions();
_options.Converters.Add(new JsonVersionConverter());
}
[Fact]
public void Deserialize_Version_Success()
{
var input = "\"1.025.222\"";
var output = new Version(1, 25, 222);
var deserializedInput = JsonSerializer.Deserialize<Version>(input, _options);
Assert.Equal(output, deserializedInput);
}
[Fact]
public void Serialize_Version_Success()
{
var input = new Version(1, 09, 59);
var output = "\"1.9.59\"";
var serializedInput = JsonSerializer.Serialize(input, _options);
Assert.Equal(output, serializedInput);
}
}
}

View File

@@ -10,6 +10,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -21,7 +23,6 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
@@ -31,8 +32,4 @@
<ProjectReference Include="../../MediaBrowser.Controller/MediaBrowser.Controller.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -5,6 +5,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -16,7 +18,6 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
@@ -26,8 +27,4 @@
<ProjectReference Include="../../Emby.Dlna/Emby.Dlna.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -16,7 +16,7 @@ namespace Jellyfin.MediaEncoding.Tests
var path = Path.Join("Test Data", fileName);
using (var stream = File.OpenRead(path))
{
await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream, JsonDefaults.GetOptions()).ConfigureAwait(false);
await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream, JsonDefaults.Options).ConfigureAwait(false);
}
}
}

View File

@@ -10,6 +10,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -27,7 +29,6 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
@@ -37,8 +38,4 @@
<ProjectReference Include="../../MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,70 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using MediaBrowser.Model.Entities;
using Xunit;
namespace Jellyfin.Model.Tests.Entities
{
public class JsonLowerCaseConverterTests
{
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
{
Converters =
{
new JsonStringEnumConverter()
}
};
[Theory]
[InlineData(null, "{\"CollectionType\":null}")]
[InlineData(CollectionTypeOptions.Movies, "{\"CollectionType\":\"movies\"}")]
[InlineData(CollectionTypeOptions.MusicVideos, "{\"CollectionType\":\"musicvideos\"}")]
public void Serialize_CollectionTypeOptions_Correct(CollectionTypeOptions? collectionType, string expected)
{
Assert.Equal(expected, JsonSerializer.Serialize(new TestContainer(collectionType), _jsonOptions));
}
[Theory]
[InlineData("{\"CollectionType\":null}", null)]
[InlineData("{\"CollectionType\":\"movies\"}", CollectionTypeOptions.Movies)]
[InlineData("{\"CollectionType\":\"musicvideos\"}", CollectionTypeOptions.MusicVideos)]
public void Deserialize_CollectionTypeOptions_Correct(string json, CollectionTypeOptions? result)
{
var res = JsonSerializer.Deserialize<TestContainer>(json, _jsonOptions);
Assert.NotNull(res);
Assert.Equal(result, res!.CollectionType);
}
[Theory]
[InlineData(null)]
[InlineData(CollectionTypeOptions.Movies)]
[InlineData(CollectionTypeOptions.MusicVideos)]
public void RoundTrip_CollectionTypeOptions_Correct(CollectionTypeOptions? value)
{
var res = JsonSerializer.Deserialize<TestContainer>(JsonSerializer.Serialize(new TestContainer(value), _jsonOptions), _jsonOptions);
Assert.NotNull(res);
Assert.Equal(value, res!.CollectionType);
}
[Theory]
[InlineData("{\"CollectionType\":null}")]
[InlineData("{\"CollectionType\":\"movies\"}")]
[InlineData("{\"CollectionType\":\"musicvideos\"}")]
public void RoundTrip_String_Correct(string json)
{
var res = JsonSerializer.Serialize(JsonSerializer.Deserialize<TestContainer>(json, _jsonOptions), _jsonOptions);
Assert.Equal(json, res);
}
private class TestContainer
{
public TestContainer(CollectionTypeOptions? collectionType)
{
CollectionType = collectionType;
}
[JsonConverter(typeof(JsonLowerCaseConverter<CollectionTypeOptions?>))]
public CollectionTypeOptions? CollectionType { get; set; }
}
}
}

View File

@@ -18,7 +18,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void HasProviderId_NullProvider_False()
{
var nullProvider = new ProviderIdsExtensionsTestsObject()
var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -47,6 +47,15 @@ namespace Jellyfin.Model.Tests.Entities
Assert.True(provider.HasProviderId(MetadataProvider.Imdb));
}
[Fact]
public void HasProviderId_FoundNameEmptyValue_False()
{
var provider = new ProviderIdsExtensionsTestsObject();
provider.ProviderIds[MetadataProvider.Imdb.ToString()] = string.Empty;
Assert.False(provider.HasProviderId(MetadataProvider.Imdb));
}
[Fact]
public void GetProviderId_NullInstance_ThrowsArgumentNullException()
{
@@ -68,7 +77,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void GetProviderId_NullProvider_Null()
{
var nullProvider = new ProviderIdsExtensionsTestsObject()
var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -85,7 +94,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void TryGetProviderId_NullProvider_False()
{
var nullProvider = new ProviderIdsExtensionsTestsObject()
var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -112,6 +121,16 @@ namespace Jellyfin.Model.Tests.Entities
Assert.Equal(ExampleImdbId, id);
}
[Fact]
public void TryGetProviderId_FoundNameEmptyValue_False()
{
var provider = new ProviderIdsExtensionsTestsObject();
provider.ProviderIds[MetadataProvider.Imdb.ToString()] = string.Empty;
Assert.False(provider.TryGetProviderId(MetadataProvider.Imdb, out var id));
Assert.Null(id);
}
[Fact]
public void SetProviderId_NullInstance_ThrowsArgumentNullException()
{
@@ -146,7 +165,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void SetProviderId_NullProvider_Success()
{
var nullProvider = new ProviderIdsExtensionsTestsObject()
var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};
@@ -158,7 +177,7 @@ namespace Jellyfin.Model.Tests.Entities
[Fact]
public void SetProviderId_NullProviderAndEmptyName_Success()
{
var nullProvider = new ProviderIdsExtensionsTestsObject()
var nullProvider = new ProviderIdsExtensionsTestsObject
{
ProviderIds = null!
};

View File

@@ -5,6 +5,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -16,7 +18,6 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
@@ -26,8 +27,4 @@
<ProjectReference Include="../../MediaBrowser.Model/MediaBrowser.Model.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -10,7 +10,7 @@ namespace Jellyfin.Naming.Tests.AudioBook
{
private readonly NamingOptions _namingOptions = new NamingOptions();
public static IEnumerable<object[]> GetResolveFileTestData()
public static IEnumerable<object[]> Resolve_ValidFileNameTestData()
{
yield return new object[]
{
@@ -36,7 +36,7 @@ namespace Jellyfin.Naming.Tests.AudioBook
}
[Theory]
[MemberData(nameof(GetResolveFileTestData))]
[MemberData(nameof(Resolve_ValidFileNameTestData))]
public void Resolve_ValidFileName_Success(AudioBookFileInfo expectedResult)
{
var result = new AudioBookResolver(_namingOptions).Resolve(expectedResult.Path);

View File

@@ -8,8 +8,10 @@
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -25,14 +27,9 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -7,18 +7,13 @@ namespace Jellyfin.Naming.Tests.Video
{
public sealed class CleanStringTests
{
private readonly NamingOptions _namingOptions = new NamingOptions();
private readonly VideoResolver _videoResolver = new VideoResolver(new NamingOptions());
[Theory]
[InlineData("Super movie 480p.mp4", "Super movie")]
[InlineData("Super movie 480p 2001.mp4", "Super movie")]
[InlineData("Super movie [480p].mp4", "Super movie")]
[InlineData("480 Super movie [tmdbid=12345].mp4", "480 Super movie")]
[InlineData("Super movie(2009).mp4", "Super movie(2009).mp4")]
[InlineData("Run lola run (lola rennt) (2009).mp4", "Run lola run (lola rennt) (2009).mp4")]
[InlineData(@"American.Psycho.mkv", "American.Psycho.mkv")]
[InlineData(@"American Psycho.mkv", "American Psycho.mkv")]
[InlineData(@"[rec].mkv", "[rec].mkv")]
[InlineData("Crouching.Tiger.Hidden.Dragon.4k.mkv", "Crouching.Tiger.Hidden.Dragon")]
[InlineData("Crouching.Tiger.Hidden.Dragon.UltraHD.mkv", "Crouching.Tiger.Hidden.Dragon")]
[InlineData("Crouching.Tiger.Hidden.Dragon.UHD.mkv", "Crouching.Tiger.Hidden.Dragon")]
@@ -29,17 +24,25 @@ namespace Jellyfin.Naming.Tests.Video
[InlineData("Crouching.Tiger.Hidden.Dragon.BDrip-HDC.mkv", "Crouching.Tiger.Hidden.Dragon")]
[InlineData("Crouching.Tiger.Hidden.Dragon.4K.UltraHD.HDR.BDrip-HDC.mkv", "Crouching.Tiger.Hidden.Dragon")]
// FIXME: [InlineData("After The Sunset - [0004].mkv", "After The Sunset")]
public void CleanStringTest(string input, string expectedName)
public void CleanStringTest_NeedsCleaning_Success(string input, string expectedName)
{
if (new VideoResolver(_namingOptions).TryCleanString(input, out ReadOnlySpan<char> newName))
{
// TODO: compare spans when XUnit supports it
Assert.Equal(expectedName, newName.ToString());
}
else
{
Assert.Equal(expectedName, input);
}
Assert.True(_videoResolver.TryCleanString(input, out ReadOnlySpan<char> newName));
// TODO: compare spans when XUnit supports it
Assert.Equal(expectedName, newName.ToString());
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData("Super movie(2009).mp4")]
[InlineData("[rec].mkv")]
[InlineData("American.Psycho.mkv")]
[InlineData("American Psycho.mkv")]
[InlineData("Run lola run (lola rennt) (2009).mp4")]
public void CleanStringTest_DoesntNeedCleaning_False(string? input)
{
Assert.False(_videoResolver.TryCleanString(input, out ReadOnlySpan<char> newName));
Assert.True(newName.IsEmpty);
}
}
}

View File

@@ -368,6 +368,44 @@ namespace Jellyfin.Naming.Tests.Video
Assert.Single(result[0].AlternateVersions);
}
[Fact]
public void Resolve_GivenFolderNameWithBracketsAndHyphens_GroupsBasedOnFolderName()
{
var files = new[]
{
@"/movies/John Wick - Kapitel 3 (2019) [imdbid=tt6146586]/John Wick - Kapitel 3 (2019) [imdbid=tt6146586] - Version 1.mkv",
@"/movies/John Wick - Kapitel 3 (2019) [imdbid=tt6146586]/John Wick - Kapitel 3 (2019) [imdbid=tt6146586] - Version 2.mkv"
};
var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
}).ToList()).ToList();
Assert.Single(result);
Assert.Empty(result[0].Extras);
Assert.Single(result[0].AlternateVersions);
}
[Fact]
public void Resolve_GivenUnclosedBrackets_DoesNotGroup()
{
var files = new[]
{
@"/movies/John Wick - Chapter 3 (2019)/John Wick - Chapter 3 (2019) [Version 1].mkv",
@"/movies/John Wick - Chapter 3 (2019)/John Wick - Chapter 3 (2019) [Version 2.mkv"
};
var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
}).ToList()).ToList();
Assert.Equal(2, result.Count);
}
[Fact]
public void TestEmptyList()
{

View File

@@ -11,7 +11,7 @@ namespace Jellyfin.Naming.Tests.Video
{
private readonly VideoResolver _videoResolver = new VideoResolver(new NamingOptions());
public static IEnumerable<object[]> GetResolveFileTestData()
public static IEnumerable<object[]> ResolveFile_ValidFileNameTestData()
{
yield return new object[]
{
@@ -156,7 +156,7 @@ namespace Jellyfin.Naming.Tests.Video
}
[Theory]
[MemberData(nameof(GetResolveFileTestData))]
[MemberData(nameof(ResolveFile_ValidFileNameTestData))]
public void ResolveFile_ValidFileName_Success(VideoFileInfo expectedResult)
{
var result = _videoResolver.ResolveFile(expectedResult.Path);

View File

@@ -8,8 +8,10 @@
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -22,18 +24,18 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Emby.Server.Implementations\Emby.Server.Implementations.csproj" />
<ProjectReference Include="..\..\..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
<ProjectReference Include="../../Emby.Server.Implementations/Emby.Server.Implementations.csproj" />
<ProjectReference Include="../../MediaBrowser.Common/MediaBrowser.Common.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG</DefineConstants>
</PropertyGroup>
</Project>

View File

@@ -1,13 +1,13 @@
using System;
using System.Collections.ObjectModel;
using System.Net;
using Jellyfin.Networking.Configuration;
using Jellyfin.Networking.Manager;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net;
using Moq;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
using System.Collections.ObjectModel;
namespace Jellyfin.Networking.Tests
{
@@ -126,7 +126,6 @@ namespace Jellyfin.Networking.Tests
Assert.True(IPNetAddress.TryParse(address, out _));
}
/// <summary>
/// All should be invalid address strings.
/// </summary>
@@ -143,7 +142,6 @@ namespace Jellyfin.Networking.Tests
Assert.False(IPHost.TryParse(address, out _));
}
/// <summary>
/// Test collection parsing.
/// </summary>
@@ -154,19 +152,22 @@ namespace Jellyfin.Networking.Tests
/// <param name="result4">Excluded IP4 addresses from the collection.</param>
/// <param name="result5">Network addresses of the collection.</param>
[Theory]
[InlineData("127.0.0.1#",
[InlineData(
"127.0.0.1#",
"[]",
"[]",
"[]",
"[]",
"[]")]
[InlineData("!127.0.0.1",
[InlineData(
"!127.0.0.1",
"[]",
"[]",
"[127.0.0.1/32]",
"[127.0.0.1/32]",
"[]")]
[InlineData("",
[InlineData(
"",
"[]",
"[]",
"[]",
@@ -179,7 +180,8 @@ namespace Jellyfin.Networking.Tests
"[10.10.10.10/32]",
"[10.10.10.10/32]",
"[192.158.0.0/16,127.0.0.1/32,::1/128,fd23:184f:2029:0:3139:7386:67d7:d517/128]")]
[InlineData("192.158.1.2/255.255.0.0,192.169.1.2/8",
[InlineData(
"192.158.1.2/255.255.0.0,192.169.1.2/8",
"[192.158.1.2/16,192.169.1.2/8]",
"[192.158.1.2/16,192.169.1.2/8]",
"[]",
@@ -196,12 +198,12 @@ namespace Jellyfin.Networking.Tests
{
EnableIPV6 = true,
EnableIPV4 = true,
};
};
using var nm = new NetworkManager(GetMockConfig(conf), new NullLogger<NetworkManager>());
// Test included.
Collection<IPObject> nc = nm.CreateIPCollection(settings.Split(","), false);
Collection<IPObject> nc = nm.CreateIPCollection(settings.Split(","), false);
Assert.Equal(nc.AsString(), result1);
// Test excluded.
@@ -210,7 +212,7 @@ namespace Jellyfin.Networking.Tests
conf.EnableIPV6 = false;
nm.UpdateSettings(conf);
// Test IP4 included.
nc = nm.CreateIPCollection(settings.Split(","), false);
Assert.Equal(nc.AsString(), result2);
@@ -254,7 +256,6 @@ namespace Jellyfin.Networking.Tests
throw new ArgumentNullException(nameof(result));
}
var conf = new NetworkConfiguration()
{
EnableIPV6 = true,
@@ -380,7 +381,6 @@ namespace Jellyfin.Networking.Tests
Assert.True(ncResult.Compare(resultCollection));
}
[Theory]
[InlineData("10.1.1.1/32", "10.1.1.1")]
[InlineData("192.168.1.254/32", "192.168.1.254/255.255.255.255")]
@@ -457,7 +457,7 @@ namespace Jellyfin.Networking.Tests
// On my system eth16 is internal, eth11 external (Windows defines the indexes).
//
// This test is to replicate how subnet bound ServerPublisherUri work throughout the system.
// User on internal network, we're bound internal and external - so result is internal override.
[InlineData("192.168.1.1", "192.168.1.0/24", "eth16,eth11", false, "192.168.1.0/24=internal.jellyfin", "internal.jellyfin")]
@@ -481,7 +481,6 @@ namespace Jellyfin.Networking.Tests
// User is internal, no binding - so result is the 1st internal, which is then overridden.
[InlineData("192.168.1.1", "192.168.1.0/24", "", false, "eth16=http://helloworld.com", "http://helloworld.com")]
public void TestBindInterfaceOverrides(string source, string lan, string bindAddresses, bool ipv6enabled, string publishedServers, string result)
{
if (lan == null)

View File

@@ -10,6 +10,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
<RootNamespace>Jellyfin.Server.Implementations.Tests</RootNamespace>
</PropertyGroup>
@@ -31,7 +33,6 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
@@ -42,8 +43,4 @@
<ProjectReference Include="..\..\Jellyfin.Server.Implementations\Jellyfin.Server.Implementations.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

View File

@@ -24,5 +24,35 @@ namespace Jellyfin.Server.Implementations.Tests.Library
{
Assert.Throws<ArgumentException>(() => PathExtensions.GetAttributeValue(input, attribute));
}
[Theory]
[InlineData("C:/Users/jeff/myfile.mkv", "C:/Users/jeff", "/home/jeff", "/home/jeff/myfile.mkv")]
[InlineData("C:/Users/jeff/myfile.mkv", "C:/Users/jeff/", "/home/jeff", "/home/jeff/myfile.mkv")]
[InlineData("/home/jeff/music/jeff's band/consistently inconsistent.mp3", "/home/jeff/music/jeff's band", "/home/not jeff", "/home/not jeff/consistently inconsistent.mp3")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff", "/home/jeff", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff", "/home/jeff/", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff/", "/home/jeff/", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff/", "/", "/myfile.mkv")]
public void TryReplaceSubPath_ValidArgs_Correct(string path, string subPath, string newSubPath, string? expectedResult)
{
Assert.True(PathExtensions.TryReplaceSubPath(path, subPath, newSubPath, out var result));
Assert.Equal(expectedResult, result);
}
[Theory]
[InlineData(null, null, null)]
[InlineData(null, "/my/path", "/another/path")]
[InlineData("/my/path", null, "/another/path")]
[InlineData("/my/path", "/another/path", null)]
[InlineData("", "", "")]
[InlineData("/my/path", "", "")]
[InlineData("", "/another/path", "")]
[InlineData("", "", "/new/subpath")]
[InlineData("/home/jeff/music/jeff's band/consistently inconsistent.mp3", "/home/jeff/music/not jeff's band", "/home/not jeff")]
public void TryReplaceSubPath_InvalidInput_ReturnsFalseAndNull(string? path, string? subPath, string? newSubPath)
{
Assert.False(PathExtensions.TryReplaceSubPath(path, subPath, newSubPath, out var result));
Assert.Null(result);
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun;
using Xunit;
namespace Jellyfin.Server.Implementations.Tests.LiveTv
{
public class HdHomerunManagerTests
{
[Fact]
public void WriteNullTerminatedString_Empty_Success()
{
ReadOnlySpan<byte> expected = stackalloc byte[]
{
1, 0
};
Span<byte> buffer = stackalloc byte[128];
int len = HdHomerunManager.WriteNullTerminatedString(buffer, string.Empty);
Assert.Equal(expected.Length, len);
Assert.True(expected.SequenceEqual(buffer.Slice(0, len)));
}
[Fact]
public void WriteNullTerminatedString_Valid_Success()
{
ReadOnlySpan<byte> expected = stackalloc byte[]
{
10, (byte)'T', (byte)'h', (byte)'e', (byte)' ', (byte)'q', (byte)'u', (byte)'i', (byte)'c', (byte)'k', 0
};
Span<byte> buffer = stackalloc byte[128];
int len = HdHomerunManager.WriteNullTerminatedString(buffer, "The quick");
Assert.Equal(expected.Length, len);
Assert.True(expected.SequenceEqual(buffer.Slice(0, len)));
}
[Fact]
public void WriteGetMessage_Valid_Success()
{
ReadOnlySpan<byte> expected = stackalloc byte[]
{
0, 4,
0, 12,
3,
10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
0xc0, 0xc9, 0x87, 0x33
};
Span<byte> buffer = stackalloc byte[128];
int len = HdHomerunManager.WriteGetMessage(buffer, 0, "N");
Assert.Equal(expected.Length, len);
Assert.True(expected.SequenceEqual(buffer.Slice(0, len)));
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Net;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
@@ -5,7 +6,7 @@ using System.Threading.Tasks;
using MediaBrowser.Model.Branding;
using Xunit;
namespace Jellyfin.Api.Tests
namespace Jellyfin.Server.Integration.Tests
{
public sealed class BrandingControllerTests : IClassFixture<JellyfinApplicationFactory>
{
@@ -26,7 +27,7 @@ namespace Jellyfin.Api.Tests
var response = await client.GetAsync("/Branding/Configuration");
// Assert
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
var responseBody = await response.Content.ReadAsStreamAsync();

View File

@@ -8,12 +8,12 @@ using Jellyfin.Api.Models;
using MediaBrowser.Common.Json;
using Xunit;
namespace Jellyfin.Api.Tests.Controllers
namespace Jellyfin.Server.Integration.Tests.Controllers
{
public sealed class DashboardControllerTests : IClassFixture<JellyfinApplicationFactory>
{
private readonly JellyfinApplicationFactory _factory;
private readonly JsonSerializerOptions _jsonOpions = JsonDefaults.GetOptions();
private readonly JsonSerializerOptions _jsonOpions = JsonDefaults.Options;
public DashboardControllerTests(JellyfinApplicationFactory factory)
{
@@ -37,9 +37,9 @@ namespace Jellyfin.Api.Tests.Controllers
var response = await client.GetAsync("/web/ConfigurationPage?name=TestPlugin").ConfigureAwait(false);
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(MediaTypeNames.Text.Html, response.Content.Headers.ContentType?.MediaType);
StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Api.Tests.TestPage.html")!);
StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Server.Integration.Tests.TestPage.html")!);
Assert.Equal(await response.Content.ReadAsStringAsync(), reader.ReadToEnd());
}
@@ -60,7 +60,7 @@ namespace Jellyfin.Api.Tests.Controllers
var response = await client.GetAsync("/web/ConfigurationPages").ConfigureAwait(false);
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var res = await response.Content.ReadAsStreamAsync();
_ = await JsonSerializer.DeserializeAsync<ConfigurationPageInfo[]>(res, _jsonOpions);
@@ -74,7 +74,7 @@ namespace Jellyfin.Api.Tests.Controllers
var response = await client.GetAsync("/web/ConfigurationPages?enableInMainMenu=true").ConfigureAwait(false);
Assert.True(response.IsSuccessStatusCode);
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);

View File

@@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.15.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.15.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.0.3" />
<PackageReference Include="Moq" Version="4.16.0" />
</ItemGroup>
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../Jellyfin.Server/Jellyfin.Server.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="TestPage.html" />
</ItemGroup>
</Project>

View File

@@ -4,17 +4,17 @@ using System.IO;
using System.Threading;
using Emby.Server.Implementations;
using Emby.Server.Implementations.IO;
using Jellyfin.Server;
using MediaBrowser.Common;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Logging;
namespace Jellyfin.Api.Tests
namespace Jellyfin.Server.Integration.Tests
{
/// <summary>
/// Factory for bootstrapping the Jellyfin application in memory for functional end to end tests.
@@ -25,9 +25,9 @@ namespace Jellyfin.Api.Tests
private readonly ConcurrentBag<IDisposable> _disposableComponents = new ConcurrentBag<IDisposable>();
/// <summary>
/// Initializes a new instance of the <see cref="JellyfinApplicationFactory"/> class.
/// Initializes static members of the <see cref="JellyfinApplicationFactory"/> class.
/// </summary>
public JellyfinApplicationFactory()
static JellyfinApplicationFactory()
{
// Perform static initialization that only needs to happen once per test-run
Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateLogger();
@@ -78,6 +78,7 @@ namespace Jellyfin.Api.Tests
appPaths,
loggerFactory,
commandLineOpts,
new ConfigurationBuilder().Build(),
new ManagedFileSystem(loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
serviceCollection);
_disposableComponents.Add(appHost);

View File

@@ -6,7 +6,7 @@ using MediaBrowser.Model.Branding;
using Xunit;
using Xunit.Abstractions;
namespace Jellyfin.Api.Tests
namespace Jellyfin.Server.Integration.Tests
{
public sealed class OpenApiSpecTests : IClassFixture<JellyfinApplicationFactory>
{

View File

@@ -4,10 +4,11 @@ using Emby.Server.Implementations;
using Jellyfin.Server;
using MediaBrowser.Controller;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Api.Tests
namespace Jellyfin.Server.Integration.Tests
{
/// <summary>
/// Implementation of the abstract <see cref="ApplicationHost" /> class.
@@ -20,18 +21,21 @@ namespace Jellyfin.Api.Tests
/// <param name="applicationPaths">The <see cref="ServerApplicationPaths" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="startup">The <see cref="IConfiguration" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="collection">The <see cref="IServiceCollection"/> to be used by the <see cref="CoreAppHost"/>.</param>
public TestAppHost(
IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
IStartupOptions options,
IConfiguration startup,
IFileSystem fileSystem,
IServiceCollection collection)
: base(
applicationPaths,
loggerFactory,
options,
startup,
fileSystem,
collection)
{

View File

@@ -7,7 +7,7 @@ using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins;
using MediaBrowser.Model.Serialization;
namespace Jellyfin.Api.Tests
namespace Jellyfin.Server.Integration.Tests
{
public class TestPlugin : BasePlugin<BasePluginConfiguration>, IHasWebPages
{

View File

@@ -6,7 +6,7 @@ using MediaBrowser.Common.Plugins;
using MediaBrowser.Model.Plugins;
using MediaBrowser.Model.Serialization;
namespace Jellyfin.Api.Tests
namespace Jellyfin.Server.Integration.Tests
{
public class TestPluginWithoutPages : BasePlugin<BasePluginConfiguration>
{

View File

@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.15.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.15.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.15.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.3" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.0.3" />
<PackageReference Include="Moq" Version="4.16.0" />
</ItemGroup>
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../../Jellyfin.Server/Jellyfin.Server.csproj" />
</ItemGroup>
</Project>

View File

@@ -10,7 +10,7 @@ using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;
namespace Jellyfin.Api.Tests
namespace Jellyfin.Server.Tests
{
public class ParseNetworkTests
{

View File

@@ -5,6 +5,8 @@
<IsPackable>false</IsPackable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
@@ -23,7 +25,6 @@
<!-- Code Analyzers -->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
@@ -34,8 +35,4 @@
<ProjectReference Include="../../MediaBrowser.Providers/MediaBrowser.Providers.csproj" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>