Merge remote-tracking branch 'upstream/master' into schedules-direct

This commit is contained in:
Cody Robibero
2021-10-08 07:49:40 -06:00
452 changed files with 6467 additions and 4633 deletions

View File

@@ -136,7 +136,7 @@ namespace Jellyfin.Api.Tests.Auth
_jellyfinAuthServiceMock.Setup(
a => a.Authenticate(
It.IsAny<HttpRequest>()))
.Returns(authorizationInfo);
.Returns(Task.FromResult(authorizationInfo));
return authorizationInfo;
}

View File

@@ -4,6 +4,7 @@ using AutoFixture;
using AutoFixture.AutoMoq;
using Jellyfin.Api.Auth.DefaultAuthorizationPolicy;
using Jellyfin.Api.Constants;
using Jellyfin.Server.Implementations.Security;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Library;
using Microsoft.AspNetCore.Authorization;
@@ -49,5 +50,61 @@ namespace Jellyfin.Api.Tests.Auth.DefaultAuthorizationPolicy
await _sut.HandleAsync(context);
Assert.True(context.HasSucceeded);
}
[Theory]
[MemberData(nameof(GetParts_ValidAuthHeader_Success_Data))]
public void GetParts_ValidAuthHeader_Success(string input, Dictionary<string, string> parts)
{
var dict = AuthorizationContext.GetParts(input);
foreach (var (key, value) in parts)
{
Assert.Equal(dict[key], value);
}
}
private static TheoryData<string, Dictionary<string, string>> GetParts_ValidAuthHeader_Success_Data()
{
var data = new TheoryData<string, Dictionary<string, string>>();
data.Add(
"x=\"123,123\",y=\"123\"",
new Dictionary<string, string>
{
{ "x", "123,123" },
{ "y", "123" }
});
data.Add(
"x=\"123,123\", y=\"123\",z=\"'hi'\"",
new Dictionary<string, string>
{
{ "x", "123,123" },
{ "y", "123" },
{ "z", "'hi'" }
});
data.Add(
"x=\"ab\"",
new Dictionary<string, string>
{
{ "x", "ab" }
});
data.Add(
"param=Hörbücher",
new Dictionary<string, string>
{
{ "param", "Hörbücher" }
});
data.Add(
"param=%22%Hörbücher",
new Dictionary<string, string>
{
{ "param", "\"%Hörbücher" }
});
return data;
}
}
}

View File

@@ -1,13 +1,5 @@
using System;
using System.Collections.Generic;
using AutoFixture;
using AutoFixture.AutoMoq;
using Jellyfin.Api.Controllers;
using Jellyfin.Api.Helpers;
using Jellyfin.Api.Models.StreamingDtos;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using Moq;
using Xunit;
namespace Jellyfin.Api.Tests.Controllers
@@ -26,33 +18,28 @@ namespace Jellyfin.Api.Tests.Controllers
}
}
public static IEnumerable<object[]> GetSegmentLengths_Success_TestData()
public static TheoryData<long, int, double[]> GetSegmentLengths_Success_TestData()
{
yield return new object[] { 0, 6, Array.Empty<double>() };
yield return new object[]
{
var data = new TheoryData<long, int, double[]>();
data.Add(0, 6, Array.Empty<double>());
data.Add(
TimeSpan.FromSeconds(3).Ticks,
6,
new double[] { 3 }
};
yield return new object[]
{
new double[] { 3 });
data.Add(
TimeSpan.FromSeconds(6).Ticks,
6,
new double[] { 6 }
};
yield return new object[]
{
new double[] { 6 });
data.Add(
TimeSpan.FromSeconds(3.3333333).Ticks,
6,
new double[] { 3.3333333 }
};
yield return new object[]
{
new double[] { 3.3333333 });
data.Add(
TimeSpan.FromSeconds(9.3333333).Ticks,
6,
new double[] { 6, 3.3333333 }
};
new double[] { 6, 3.3333333 });
return data;
}
}
}

View File

@@ -15,16 +15,16 @@ namespace Jellyfin.Api.Tests.Helpers
Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder));
}
public static IEnumerable<object[]> GetOrderBy_Success_TestData()
public static TheoryData<IReadOnlyList<string>, IReadOnlyList<SortOrder>, (string, SortOrder)[]> GetOrderBy_Success_TestData()
{
yield return new object[]
{
var data = new TheoryData<IReadOnlyList<string>, IReadOnlyList<SortOrder>, (string, SortOrder)[]>();
data.Add(
Array.Empty<string>(),
Array.Empty<SortOrder>(),
Array.Empty<(string, SortOrder)>()
};
yield return new object[]
{
Array.Empty<(string, SortOrder)>());
data.Add(
new string[]
{
"IsFavoriteOrLiked",
@@ -35,10 +35,9 @@ namespace Jellyfin.Api.Tests.Helpers
{
("IsFavoriteOrLiked", SortOrder.Ascending),
("Random", SortOrder.Ascending),
}
};
yield return new object[]
{
});
data.Add(
new string[]
{
"SortName",
@@ -52,8 +51,9 @@ namespace Jellyfin.Api.Tests.Helpers
{
("SortName", SortOrder.Descending),
("ProductionYear", SortOrder.Descending),
}
};
});
return data;
}
[Fact]

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -15,7 +15,7 @@
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.10" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="xunit" Version="2.4.1" />

View File

@@ -19,18 +19,16 @@ namespace Jellyfin.Common.Tests.Cryptography
Assert.Throws<ArgumentException>(() => new PasswordHash(string.Empty, Array.Empty<byte>()));
}
public static IEnumerable<object[]> Parse_Valid_TestData()
public static TheoryData<string, PasswordHash> Parse_Valid_TestData()
{
var data = new TheoryData<string, PasswordHash>();
// Id
yield return new object[]
{
data.Add(
"$PBKDF2",
new PasswordHash("PBKDF2", Array.Empty<byte>())
};
new PasswordHash("PBKDF2", Array.Empty<byte>()));
// Id + parameter
yield return new object[]
{
data.Add(
"$PBKDF2$iterations=1000",
new PasswordHash(
"PBKDF2",
@@ -39,12 +37,10 @@ namespace Jellyfin.Common.Tests.Cryptography
new Dictionary<string, string>()
{
{ "iterations", "1000" },
})
};
}));
// Id + parameters
yield return new object[]
{
data.Add(
"$PBKDF2$iterations=1000,m=120",
new PasswordHash(
"PBKDF2",
@@ -54,34 +50,28 @@ namespace Jellyfin.Common.Tests.Cryptography
{
{ "iterations", "1000" },
{ "m", "120" }
})
};
}));
// Id + hash
yield return new object[]
{
data.Add(
"$PBKDF2$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
new PasswordHash(
"PBKDF2",
Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"),
Array.Empty<byte>(),
new Dictionary<string, string>())
};
new Dictionary<string, string>()));
// Id + salt + hash
yield return new object[]
{
data.Add(
"$PBKDF2$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
new PasswordHash(
"PBKDF2",
Convert.FromHexString("62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D"),
Convert.FromHexString("69F420"),
new Dictionary<string, string>())
};
new Dictionary<string, string>()));
// Id + parameter + hash
yield return new object[]
{
data.Add(
"$PBKDF2$iterations=1000$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
new PasswordHash(
"PBKDF2",
@@ -90,12 +80,9 @@ namespace Jellyfin.Common.Tests.Cryptography
new Dictionary<string, string>()
{
{ "iterations", "1000" }
})
};
}));
// Id + parameters + hash
yield return new object[]
{
data.Add(
"$PBKDF2$iterations=1000,m=120$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
new PasswordHash(
"PBKDF2",
@@ -105,12 +92,9 @@ namespace Jellyfin.Common.Tests.Cryptography
{
{ "iterations", "1000" },
{ "m", "120" }
})
};
}));
// Id + parameters + salt + hash
yield return new object[]
{
data.Add(
"$PBKDF2$iterations=1000,m=120$69F420$62FBA410AFCA5B4475F35137AB2E8596B127E4D927BA23F6CC05C067E897042D",
new PasswordHash(
"PBKDF2",
@@ -120,8 +104,8 @@ namespace Jellyfin.Common.Tests.Cryptography
{
{ "iterations", "1000" },
{ "m", "120" }
})
};
}));
return data;
}
[Theory]

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -16,7 +16,7 @@
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.1" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.3" />
</ItemGroup>
<!-- Code Analyzers -->

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

View File

@@ -6,10 +6,17 @@ namespace Jellyfin.Extensions.Tests
{
public static class CopyToExtensionsTests
{
public static IEnumerable<object[]> CopyTo_Valid_Correct_TestData()
public static TheoryData<IReadOnlyList<int>, IList<int>, int, IList<int>> CopyTo_Valid_Correct_TestData()
{
yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 0, new[] { 0, 1, 2, 3, 4, 5 } };
yield return new object[] { new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 2, new[] { 5, 4, 0, 1, 2, 0 } };
var data = new TheoryData<IReadOnlyList<int>, IList<int>, int, IList<int>>();
data.Add(
new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 0, new[] { 0, 1, 2, 3, 4, 5 });
data.Add(
new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 2, new[] { 5, 4, 0, 1, 2, 0 } );
return data;
}
[Theory]
@@ -20,13 +27,26 @@ namespace Jellyfin.Extensions.Tests
Assert.Equal(expected, destination);
}
public static IEnumerable<object[]> CopyTo_Invalid_ThrowsArgumentOutOfRangeException_TestData()
public static TheoryData<IReadOnlyList<int>, IList<int>, int> CopyTo_Invalid_ThrowsArgumentOutOfRangeException_TestData()
{
yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, -1 };
yield return new object[] { new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 6 };
yield return new object[] { new[] { 0, 1, 2 }, Array.Empty<int>(), 0 };
yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0 }, 0 };
yield return new object[] { new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 1 };
var data = new TheoryData<IReadOnlyList<int>, IList<int>, int>();
data.Add(
new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, -1 );
data.Add(
new[] { 0, 1, 2 }, new[] { 5, 4, 3, 2, 1, 0 }, 6 );
data.Add(
new[] { 0, 1, 2 }, Array.Empty<int>(), 0 );
data.Add(
new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0 }, 0 );
data.Add(
new[] { 0, 1, 2, 3, 4, 5 }, new[] { 0, 0, 0, 0, 0, 0 }, 1 );
return data;
}
[Theory]

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -17,7 +17,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FsCheck.Xunit" Version="2.16.1" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.3" />
</ItemGroup>
<!-- Code Analyzers -->

View File

@@ -1,4 +1,3 @@
using System.Globalization;
using System.Text.Json;
using FsCheck;
using FsCheck.Xunit;

View File

@@ -14,5 +14,28 @@ namespace Jellyfin.Extensions.Tests
{
Assert.Equal(count, str.AsSpan().Count(needle));
}
[Theory]
[InlineData("", 'q', "")]
[InlineData("Banana split", ' ', "Banana")]
[InlineData("Banana split", 'q', "Banana split")]
[InlineData("Banana split 2", ' ', "Banana")]
public void LeftPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult)
{
var result = str.AsSpan().LeftPart(needle).ToString();
Assert.Equal(expectedResult, result);
}
[Theory]
[InlineData("", 'q', "")]
[InlineData("Banana split", ' ', "split")]
[InlineData("Banana split", 'q', "Banana split")]
[InlineData("Banana split.", '.', "")]
[InlineData("Banana split 2", ' ', "2")]
public void RightPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult)
{
var result = str.AsSpan().RightPart(needle).ToString();
Assert.Equal(expectedResult, result);
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using MediaBrowser.MediaEncoding.Encoder;
using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
@@ -34,23 +32,21 @@ namespace Jellyfin.MediaEncoding.Tests
Assert.Equal(valid, _encoderValidator.ValidateVersionInternal(versionOutput));
}
private class GetFFmpegVersionTestData : IEnumerable<object?[]>
private class GetFFmpegVersionTestData : TheoryData<string, Version?>
{
public IEnumerator<object?[]> GetEnumerator()
public GetFFmpegVersionTestData()
{
yield return new object?[] { EncoderValidatorTestsData.FFmpegV44Output, new Version(4, 4) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV432Output, new Version(4, 3, 2) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV431Output, new Version(4, 3, 1) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV43Output, new Version(4, 3) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput2, new Version(4, 0) };
yield return new object?[] { EncoderValidatorTestsData.FFmpegGitUnknownOutput, null };
Add(EncoderValidatorTestsData.FFmpegV44Output, new Version(4, 4));
Add(EncoderValidatorTestsData.FFmpegV432Output, new Version(4, 3, 2));
Add(EncoderValidatorTestsData.FFmpegV431Output, new Version(4, 3, 1));
Add(EncoderValidatorTestsData.FFmpegV43Output, new Version(4, 3));
Add(EncoderValidatorTestsData.FFmpegV421Output, new Version(4, 2, 1));
Add(EncoderValidatorTestsData.FFmpegV42Output, new Version(4, 2));
Add(EncoderValidatorTestsData.FFmpegV414Output, new Version(4, 1, 4));
Add(EncoderValidatorTestsData.FFmpegV404Output, new Version(4, 0, 4));
Add(EncoderValidatorTestsData.FFmpegGitUnknownOutput2, new Version(4, 0));
Add(EncoderValidatorTestsData.FFmpegGitUnknownOutput, null);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Text.Json;
using System.Threading.Tasks;
using Jellyfin.Extensions.Json;
using MediaBrowser.MediaEncoding.Probing;
using MediaBrowser.Model.IO;
using Xunit;
namespace Jellyfin.MediaEncoding.Tests
@@ -14,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Tests
public async Task Test(string fileName)
{
var path = Path.Join("Test Data", fileName);
await using (var stream = File.OpenRead(path))
await using (var stream = AsyncFile.OpenRead(path))
{
var res = await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(stream, JsonDefaults.Options).ConfigureAwait(false);
Assert.NotNull(res);

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -18,10 +18,14 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
</ItemGroup>
<!-- Code Analyzers -->

View File

@@ -69,7 +69,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
Assert.Equal("Album", res.Album);
Assert.Equal(2021, res.ProductionYear);
Assert.True(res.PremiereDate.HasValue);
Assert.Equal(DateTime.Parse("2021-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate);
Assert.Equal(DateTime.Parse("2021-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AdjustToUniversal), res.PremiereDate);
}
[Fact]
@@ -85,11 +85,44 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
Assert.Equal("City to City", res.Album);
Assert.Equal(1978, res.ProductionYear);
Assert.True(res.PremiereDate.HasValue);
Assert.Equal(DateTime.Parse("1978-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate);
Assert.Equal(DateTime.Parse("1978-01-01T00:00Z", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AdjustToUniversal), res.PremiereDate);
Assert.Contains("Electronic", res.Genres);
Assert.Contains("Ambient", res.Genres);
Assert.Contains("Pop", res.Genres);
Assert.Contains("Jazz", res.Genres);
}
[Fact]
public void GetMediaInfo_Music_Success()
{
var bytes = File.ReadAllBytes("Test Data/Probing/music_metadata.json");
var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, null, true, "Test Data/Probing/music.flac", MediaProtocol.File);
Assert.Equal("UP NO MORE", res.Name);
Assert.Single(res.Artists);
Assert.Equal("TWICE", res.Artists[0]);
Assert.Equal("Eyes wide open", res.Album);
Assert.Equal(2020, res.ProductionYear);
Assert.True(res.PremiereDate.HasValue);
Assert.Equal(DateTime.Parse("2020-10-26T00:00Z", DateTimeFormatInfo.CurrentInfo, DateTimeStyles.AdjustToUniversal), res.PremiereDate);
Assert.Equal(22, res.People.Length);
Assert.Equal("Krysta Youngs", res.People[0].Name);
Assert.Equal(PersonType.Composer, res.People[0].Type);
Assert.Equal("Julia Ross", res.People[1].Name);
Assert.Equal(PersonType.Composer, res.People[1].Type);
Assert.Equal("Yiwoomin", res.People[2].Name);
Assert.Equal(PersonType.Composer, res.People[2].Type);
Assert.Equal("Ji-hyo Park", res.People[3].Name);
Assert.Equal(PersonType.Lyricist, res.People[3].Type);
Assert.Equal("Yiwoomin", res.People[4].Name);
Assert.Equal(PersonType.Actor, res.People[4].Type);
Assert.Equal("Electric Piano", res.People[4].Role);
Assert.Equal(4, res.Genres.Length);
Assert.Contains("Electronic", res.Genres);
Assert.Contains("Trance", res.Genres);
Assert.Contains("Dance", res.Genres);
Assert.Contains("Jazz", res.Genres);
}
}
}

View File

@@ -31,5 +31,27 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
Assert.Equal("Very good, Lieutenant.", trackEvent2.Text);
}
}
[Fact]
public void Parse_EmptyNewlineBetweenText_Success()
{
using (var stream = File.OpenRead("Test Data/example2.srt"))
{
var parsed = new SrtParser(new NullLogger<SrtParser>()).Parse(stream, CancellationToken.None);
Assert.Equal(2, parsed.TrackEvents.Count);
var trackEvent1 = parsed.TrackEvents[0];
Assert.Equal("311", trackEvent1.Id);
Assert.Equal(TimeSpan.Parse("00:16:46.465", CultureInfo.InvariantCulture).Ticks, trackEvent1.StartPositionTicks);
Assert.Equal(TimeSpan.Parse("00:16:49.009", CultureInfo.InvariantCulture).Ticks, trackEvent1.EndPositionTicks);
Assert.Equal("Una vez que la gente se entere" + Environment.NewLine + Environment.NewLine + "de que ustedes están aquí,", trackEvent1.Text);
var trackEvent2 = parsed.TrackEvents[1];
Assert.Equal("312", trackEvent2.Id);
Assert.Equal(TimeSpan.Parse("00:16:49.092", CultureInfo.InvariantCulture).Ticks, trackEvent2.StartPositionTicks);
Assert.Equal(TimeSpan.Parse("00:16:51.470", CultureInfo.InvariantCulture).Ticks, trackEvent2.EndPositionTicks);
Assert.Equal("este lugar se convertirá" + Environment.NewLine + Environment.NewLine + "en un maldito zoológico.", trackEvent2.Text);
}
}
}
}

View File

@@ -38,10 +38,11 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
}
}
public static IEnumerable<object[]> Parse_MultipleDialogues_TestData()
public static TheoryData<string, IReadOnlyList<SubtitleTrackEvent>> Parse_MultipleDialogues_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, IReadOnlyList<SubtitleTrackEvent>>();
data.Add(
@"[Events]
Format: Layer, Start, End, Text
Dialogue: ,0:00:01.18,0:00:01.85,dialogue1
@@ -65,8 +66,9 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
StartPositionTicks = 31800000,
EndPositionTicks = 38500000
}
}
};
});
return data;
}
[Fact]

View File

@@ -0,0 +1,83 @@
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.AutoMoq;
using MediaBrowser.MediaEncoding.Subtitles;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using Xunit;
namespace Jellyfin.MediaEncoding.Subtitles.Tests
{
public class SubtitleEncoderTests
{
internal static TheoryData<MediaSourceInfo, MediaStream, SubtitleEncoder.SubtitleInfo> GetReadableFile_Valid_TestData()
{
var data = new TheoryData<MediaSourceInfo, MediaStream, SubtitleEncoder.SubtitleInfo>();
data.Add(
new MediaSourceInfo()
{
Protocol = MediaProtocol.File
},
new MediaStream()
{
Path = "/media/sub.ass",
IsExternal = true
},
new SubtitleEncoder.SubtitleInfo("/media/sub.ass", MediaProtocol.File, "ass", true));
data.Add(
new MediaSourceInfo()
{
Protocol = MediaProtocol.File
},
new MediaStream()
{
Path = "/media/sub.ssa",
IsExternal = true
},
new SubtitleEncoder.SubtitleInfo("/media/sub.ssa", MediaProtocol.File, "ssa", true));
data.Add(
new MediaSourceInfo()
{
Protocol = MediaProtocol.File
},
new MediaStream()
{
Path = "/media/sub.srt",
IsExternal = true
},
new SubtitleEncoder.SubtitleInfo("/media/sub.srt", MediaProtocol.File, "srt", true));
data.Add(
new MediaSourceInfo()
{
Protocol = MediaProtocol.Http
},
new MediaStream()
{
Path = "/media/sub.ass",
IsExternal = true
},
new SubtitleEncoder.SubtitleInfo("/media/sub.ass", MediaProtocol.File, "ass", true));
return data;
}
[Theory]
[MemberData(nameof(GetReadableFile_Valid_TestData))]
internal async Task GetReadableFile_Valid_Success(MediaSourceInfo mediaSource, MediaStream subtitleStream, SubtitleEncoder.SubtitleInfo subtitleInfo)
{
var fixture = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
var subtitleEncoder = fixture.Create<SubtitleEncoder>();
var result = await subtitleEncoder.GetReadableFile(mediaSource, subtitleStream, CancellationToken.None).ConfigureAwait(false);
Assert.Equal(subtitleInfo.Path, result.Path);
Assert.Equal(subtitleInfo.Protocol, result.Protocol);
Assert.Equal(subtitleInfo.Format, result.Format);
Assert.Equal(subtitleInfo.IsExternal, result.IsExternal);
}
}
}

View File

@@ -0,0 +1,144 @@
{
"streams": [
{
"index": 0,
"codec_name": "flac",
"codec_long_name": "FLAC (Free Lossless Audio Codec)",
"codec_type": "audio",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"sample_fmt": "s16",
"sample_rate": "44100",
"channels": 2,
"channel_layout": "stereo",
"bits_per_sample": 0,
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/44100",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 9447984,
"duration": "214.240000",
"bits_per_raw_sample": "16",
"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": "mjpeg",
"codec_long_name": "Motion JPEG",
"profile": "Baseline",
"codec_type": "video",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"width": 500,
"height": 500,
"coded_width": 500,
"coded_height": 500,
"closed_captions": 0,
"has_b_frames": 0,
"sample_aspect_ratio": "1:1",
"display_aspect_ratio": "1:1",
"pix_fmt": "yuvj420p",
"level": -99,
"color_range": "pc",
"color_space": "bt470bg",
"chroma_location": "center",
"refs": 1,
"r_frame_rate": "90000/1",
"avg_frame_rate": "0/0",
"time_base": "1/90000",
"start_pts": 0,
"start_time": "0.000000",
"duration_ts": 19281600,
"duration": "214.240000",
"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": 1,
"timed_thumbnails": 0
},
"tags": {
"comment": "Cover (front)"
}
}
],
"format": {
"filename": "03 UP NO MORE.flac",
"nb_streams": 2,
"nb_programs": 0,
"format_name": "flac",
"format_long_name": "raw FLAC",
"start_time": "0.000000",
"duration": "214.240000",
"size": "28714641",
"bit_rate": "1072242",
"probe_score": 100,
"tags": {
"MUSICBRAINZ_RELEASEGROUPID": "aa05ff10-8589-4c9c-a0d4-6b024f4e4556",
"ORIGINALDATE": "2020-10-26",
"ORIGINALYEAR": "2020",
"RELEASETYPE": "album",
"MUSICBRAINZ_ALBUMID": "222e6610-75c9-400e-8dc3-bb61f9fc5ca7",
"SCRIPT": "Latn",
"ALBUM": "Eyes wide open",
"RELEASECOUNTRY": "JP",
"BARCODE": "190295105280",
"LABEL": "JYP Entertainment",
"RELEASESTATUS": "official",
"DATE": "2020-10-26",
"MUSICBRAINZ_ALBUMARTISTID": "8da127cc-c432-418f-b356-ef36210d82ac",
"album_artist": "TWICE",
"ALBUMARTISTSORT": "TWICE",
"TOTALDISCS": "1",
"TOTALTRACKS": "13",
"MEDIA": "Digital Media",
"disc": "1",
"MUSICBRAINZ_TRACKID": "7d1a1044-b564-480d-9df3-22f9656fdb97",
"TITLE": "UP NO MORE",
"ISRC": "US5TA2000136",
"PERFORMER": "Yiwoomin (electric piano);Yiwoomin (synthesizer);Yiwoomin (bass);Yiwoomin (guitar);TWICE;Tzu-yu Chou (vocals);Momo Hirai (vocals);Na-yeon Im (vocals);Da-hyun Kim (vocals);Sana Minatozaki (vocals);Mina Myoui (vocals);Ji-hyo Park (vocals);Chae-young Son (vocals);Jeong-yeon Yoo (vocals);Perrie (background vocals)",
"MIXER": "Bong Won Shin",
"ARRANGER": "Krysta Youngs;Julia Ross;Yiwoomin",
"MUSICBRAINZ_WORKID": "02b37083-0337-4721-9f17-bf31971043e8",
"LANGUAGE": "kor;eng",
"WORK": "Up No More",
"COMPOSER": "Krysta Youngs;Julia Ross;Yiwoomin",
"COMPOSERSORT": "Krysta Youngs;Ross, Julia;Yiwoomin",
"LYRICIST": "Ji-hyo Park",
"MUSICBRAINZ_ARTISTID": "8da127cc-c432-418f-b356-ef36210d82ac",
"ARTIST": "TWICE",
"ARTISTSORT": "TWICE",
"ARTISTS": "TWICE",
"MUSICBRAINZ_RELEASETRACKID": "ad49b840-da9e-4e7c-924b-29fdee187052",
"track": "3",
"GENRE": "Electronic;Trance;Dance;Jazz",
"WEBSITE": "http://twice.jype.com/;http://www.twicejapan.com/",
"ACOUSTID_ID": "aae2e972-108c-4d0c-8e31-9d078283e3dc",
"MOOD": "Not acoustic;Not aggressive;Electronic;Happy;Party;Not relaxed;Not sad",
"TRACKTOTAL": "13",
"DISCTOTAL": "1"
}
}
}

View File

@@ -0,0 +1,11 @@
311
00:16:46,465 --> 00:16:49,009
Una vez que la gente se entere
de que ustedes están aquí,
312
00:16:49,092 --> 00:16:51,470
este lugar se convertirá
en un maldito zoológico.

View File

@@ -1,4 +1,3 @@
using System.Collections.Generic;
using MediaBrowser.Model.Entities;
using Xunit;
@@ -6,12 +5,11 @@ namespace Jellyfin.Model.Tests.Entities
{
public class MediaStreamTests
{
public static IEnumerable<object[]> Get_DisplayTitle_TestData()
public static TheoryData<MediaStream, string> Get_DisplayTitle_TestData()
{
return new List<object[]>
{
new object[]
{
var data = new TheoryData<MediaStream, string>();
data.Add(
new MediaStream
{
Type = MediaStreamType.Subtitle,
@@ -21,61 +19,57 @@ namespace Jellyfin.Model.Tests.Entities
IsDefault = false,
Codec = "ASS"
},
"English - Und - ASS"
},
new object[]
"English - Und - ASS");
data.Add(
new MediaStream
{
new MediaStream
{
Type = MediaStreamType.Subtitle,
Title = "English",
Language = string.Empty,
IsForced = false,
IsDefault = false,
Codec = string.Empty
},
"English - Und"
Type = MediaStreamType.Subtitle,
Title = "English",
Language = string.Empty,
IsForced = false,
IsDefault = false,
Codec = string.Empty
},
new object[]
"English - Und");
data.Add(
new MediaStream
{
new MediaStream
{
Type = MediaStreamType.Subtitle,
Title = "English",
Language = "EN",
IsForced = false,
IsDefault = false,
Codec = string.Empty
},
"English"
Type = MediaStreamType.Subtitle,
Title = "English",
Language = "EN",
IsForced = false,
IsDefault = false,
Codec = string.Empty
},
new object[]
"English");
data.Add(
new MediaStream
{
new MediaStream
{
Type = MediaStreamType.Subtitle,
Title = "English",
Language = "EN",
IsForced = true,
IsDefault = true,
Codec = "SRT"
},
"English - Default - Forced - SRT"
Type = MediaStreamType.Subtitle,
Title = "English",
Language = "EN",
IsForced = true,
IsDefault = true,
Codec = "SRT"
},
new object[]
"English - Default - Forced - SRT");
data.Add(
new MediaStream
{
new MediaStream
{
Type = MediaStreamType.Subtitle,
Title = null,
Language = null,
IsForced = false,
IsDefault = false,
Codec = null
},
"Und"
}
};
Type = MediaStreamType.Subtitle,
Title = null,
Language = null,
IsForced = false,
IsDefault = false,
Codec = null
},
"Und");
return data;
}
[Theory]

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -11,7 +11,7 @@
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.1" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.3" />
</ItemGroup>
<!-- Code Analyzers -->

View File

@@ -1,4 +1,3 @@
using System.Collections.Generic;
using Emby.Naming.AudioBook;
using Emby.Naming.Common;
using Xunit;
@@ -9,29 +8,29 @@ namespace Jellyfin.Naming.Tests.AudioBook
{
private readonly NamingOptions _namingOptions = new NamingOptions();
public static IEnumerable<object[]> Resolve_ValidFileNameTestData()
public static TheoryData<AudioBookFileInfo> Resolve_ValidFileNameTestData()
{
yield return new object[]
{
var data = new TheoryData<AudioBookFileInfo>();
data.Add(
new AudioBookFileInfo(
@"/server/AudioBooks/Larry Potter/Larry Potter.mp3",
"mp3")
};
yield return new object[]
{
"mp3"));
data.Add(
new AudioBookFileInfo(
@"/server/AudioBooks/Berry Potter/Chapter 1 .ogg",
"ogg",
chapterNumber: 1)
};
yield return new object[]
{
chapterNumber: 1));
data.Add(
new AudioBookFileInfo(
@"/server/AudioBooks/Nerry Potter/Part 3 - Chapter 2.mp3",
"mp3",
chapterNumber: 2,
partNumber: 3)
};
partNumber: 3));
return data;
}
[Theory]

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

View File

@@ -18,30 +18,31 @@ namespace Jellyfin.Naming.Tests.Video
[Fact]
public void TestKodiExtras()
{
Test("trailer.mp4", ExtraType.Trailer, _videoOptions);
Test("300-trailer.mp4", ExtraType.Trailer, _videoOptions);
Test("trailer.mp4", ExtraType.Trailer);
Test("300-trailer.mp4", ExtraType.Trailer);
Test("theme.mp3", ExtraType.ThemeSong, _videoOptions);
Test("theme.mp3", ExtraType.ThemeSong);
}
[Fact]
public void TestExpandedExtras()
{
Test("trailer.mp4", ExtraType.Trailer, _videoOptions);
Test("trailer.mp3", null, _videoOptions);
Test("300-trailer.mp4", ExtraType.Trailer, _videoOptions);
Test("trailer.mp4", ExtraType.Trailer);
Test("trailer.mp3", null);
Test("300-trailer.mp4", ExtraType.Trailer);
Test("stuff trailerthings.mkv", null);
Test("theme.mp3", ExtraType.ThemeSong, _videoOptions);
Test("theme.mkv", null, _videoOptions);
Test("theme.mp3", ExtraType.ThemeSong);
Test("theme.mkv", null);
Test("300-scene.mp4", ExtraType.Scene, _videoOptions);
Test("300-scene2.mp4", ExtraType.Scene, _videoOptions);
Test("300-clip.mp4", ExtraType.Clip, _videoOptions);
Test("300-scene.mp4", ExtraType.Scene);
Test("300-scene2.mp4", ExtraType.Scene);
Test("300-clip.mp4", ExtraType.Clip);
Test("300-deleted.mp4", ExtraType.DeletedScene, _videoOptions);
Test("300-deletedscene.mp4", ExtraType.DeletedScene, _videoOptions);
Test("300-interview.mp4", ExtraType.Interview, _videoOptions);
Test("300-behindthescenes.mp4", ExtraType.BehindTheScenes, _videoOptions);
Test("300-deleted.mp4", ExtraType.DeletedScene);
Test("300-deletedscene.mp4", ExtraType.DeletedScene);
Test("300-interview.mp4", ExtraType.Interview);
Test("300-behindthescenes.mp4", ExtraType.BehindTheScenes);
}
[Theory]
@@ -55,9 +56,9 @@ namespace Jellyfin.Naming.Tests.Video
[InlineData(ExtraType.Unknown, "extras")]
public void TestDirectories(ExtraType type, string dirName)
{
Test(dirName + "/300.mp4", type, _videoOptions);
Test("300/" + dirName + "/something.mkv", type, _videoOptions);
Test("/data/something/Movies/300/" + dirName + "/whoknows.mp4", type, _videoOptions);
Test(dirName + "/300.mp4", type);
Test("300/" + dirName + "/something.mkv", type);
Test("/data/something/Movies/300/" + dirName + "/whoknows.mp4", type);
}
[Theory]
@@ -66,32 +67,25 @@ namespace Jellyfin.Naming.Tests.Video
[InlineData("The Big Short")]
public void TestNonExtraDirectories(string dirName)
{
Test(dirName + "/300.mp4", null, _videoOptions);
Test("300/" + dirName + "/something.mkv", null, _videoOptions);
Test("/data/something/Movies/300/" + dirName + "/whoknows.mp4", null, _videoOptions);
Test("/data/something/Movies/" + dirName + "/" + dirName + ".mp4", null, _videoOptions);
Test(dirName + "/300.mp4", null);
Test("300/" + dirName + "/something.mkv", null);
Test("/data/something/Movies/300/" + dirName + "/whoknows.mp4", null);
Test("/data/something/Movies/" + dirName + "/" + dirName + ".mp4", null);
}
[Fact]
public void TestSample()
{
Test("300-sample.mp4", ExtraType.Sample, _videoOptions);
Test("300-sample.mp4", ExtraType.Sample);
}
private void Test(string input, ExtraType? expectedType, NamingOptions videoOptions)
private void Test(string input, ExtraType? expectedType)
{
var parser = GetExtraTypeParser(videoOptions);
var parser = GetExtraTypeParser(_videoOptions);
var extraType = parser.GetExtraInfo(input).ExtraType;
if (expectedType == null)
{
Assert.Null(extraType);
}
else
{
Assert.Equal(expectedType, extraType);
}
Assert.Equal(expectedType, extraType);
}
[Fact]

View File

@@ -1,4 +1,3 @@
using System.Collections.Generic;
using System.Linq;
using Emby.Naming.Common;
using Emby.Naming.Video;
@@ -11,148 +10,134 @@ namespace Jellyfin.Naming.Tests.Video
{
private static NamingOptions _namingOptions = new NamingOptions();
public static IEnumerable<object[]> ResolveFile_ValidFileNameTestData()
public static TheoryData<VideoFileInfo> ResolveFile_ValidFileNameTestData()
{
yield return new object[]
{
var data = new TheoryData<VideoFileInfo>();
data.Add(
new VideoFileInfo(
path: @"/server/Movies/7 Psychos.mkv/7 Psychos.mkv",
container: "mkv",
name: "7 Psychos")
};
yield return new object[]
{
name: "7 Psychos"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/3 days to kill (2005)/3 days to kill (2005).mkv",
container: "mkv",
name: "3 days to kill",
year: 2005)
};
yield return new object[]
{
year: 2005));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/American Psycho/American.Psycho.mkv",
container: "mkv",
name: "American.Psycho")
};
yield return new object[]
{
name: "American.Psycho"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/brave (2007)/brave (2006).3d.sbs.mkv",
container: "mkv",
name: "brave",
year: 2006,
is3D: true,
format3D: "sbs")
};
yield return new object[]
{
format3D: "sbs"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).3d1.sbas.mkv",
container: "mkv",
name: "300",
year: 2006)
};
yield return new object[]
{
year: 2006));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).3d.sbs.mkv",
container: "mkv",
name: "300",
year: 2006,
is3D: true,
format3D: "sbs")
};
yield return new object[]
{
format3D: "sbs"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/brave (2007)/brave (2006)-trailer.bluray.disc",
container: "disc",
name: "brave",
year: 2006,
isStub: true,
stubType: "bluray")
};
yield return new object[]
{
stubType: "bluray"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006)-trailer.bluray.disc",
container: "disc",
name: "300",
year: 2006,
isStub: true,
stubType: "bluray")
};
yield return new object[]
{
stubType: "bluray"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/Brave (2007)/Brave (2006).bluray.disc",
container: "disc",
name: "Brave",
year: 2006,
isStub: true,
stubType: "bluray")
};
yield return new object[]
{
stubType: "bluray"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).bluray.disc",
container: "disc",
name: "300",
year: 2006,
isStub: true,
stubType: "bluray")
};
yield return new object[]
{
stubType: "bluray"));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006)-trailer.mkv",
container: "mkv",
name: "300",
year: 2006,
extraType: ExtraType.Trailer)
};
yield return new object[]
{
extraType: ExtraType.Trailer));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/Brave (2007)/Brave (2006)-trailer.mkv",
container: "mkv",
name: "Brave",
year: 2006,
extraType: ExtraType.Trailer)
};
yield return new object[]
{
extraType: ExtraType.Trailer));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).mkv",
container: "mkv",
name: "300",
year: 2006)
};
yield return new object[]
{
year: 2006));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/Bad Boys (1995)/Bad Boys (1995).mkv",
container: "mkv",
name: "Bad Boys",
year: 1995)
};
yield return new object[]
{
year: 1995));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/Brave (2007)/Brave (2006).mkv",
container: "mkv",
name: "Brave",
year: 2006)
};
yield return new object[]
{
year: 2006));
data.Add(
new VideoFileInfo(
path: @"/server/Movies/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF.mp4",
container: "mp4",
name: "Rain Man",
year: 1988)
};
year: 1988));
return data;
}
[Theory]

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -16,7 +16,7 @@
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.1" />
<PackageReference Include="FsCheck.Xunit" Version="2.16.3" />
<PackageReference Include="Moq" Version="4.16.1" />
</ItemGroup>

View File

@@ -20,7 +20,7 @@ namespace Jellyfin.Networking.Tests
CallBase = true
};
configManager.Setup(x => x.GetConfiguration(It.IsAny<string>())).Returns(conf);
return (IConfigurationManager)configManager.Object;
return configManager.Object;
}
/// <summary>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

View File

@@ -1,4 +1,4 @@
#pragma warning disable CA1002 // Do not expose generic lists
#pragma warning disable CA1002 // Do not expose generic lists
using System.Collections.Generic;
using MediaBrowser.Model.Entities;
@@ -11,11 +11,12 @@ namespace Jellyfin.Providers.Tests.MediaInfo
{
public class SubtitleResolverTests
{
public static IEnumerable<object[]> AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles_TestData()
public static TheoryData<List<MediaStream>, string, int, string[], MediaStream[]> AddExternalSubtitleStreams_GivenMixedFilenames_ReturnsValidSubtitles_TestData()
{
var data = new TheoryData<List<MediaStream>, string, int, string[], MediaStream[]>();
var index = 0;
yield return new object[]
{
data.Add(
new List<MediaStream>(),
"/video/My.Video.mkv",
index,
@@ -52,8 +53,9 @@ namespace Jellyfin.Providers.Tests.MediaInfo
CreateMediaStream("/video/My.Video.default.forced.en.srt", "srt", "en", index++, isForced: true, isDefault: true),
CreateMediaStream("/video/My.Video.en.default.forced.srt", "srt", "en", index++, isForced: true, isDefault: true),
CreateMediaStream("/video/My.Video.With.Additional.Garbage.en.srt", "srt", "en", index),
}
};
});
return data;
}
[Theory]

View File

@@ -32,10 +32,11 @@ namespace Jellyfin.Server.Implementations.Tests.Data
_sqliteItemRepository = _fixture.Create<SqliteItemRepository>();
}
public static IEnumerable<object[]> ItemImageInfoFromValueString_Valid_TestData()
public static TheoryData<string, ItemImageInfo> ItemImageInfoFromValueString_Valid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, ItemImageInfo>();
data.Add(
"/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN",
new ItemImageInfo
{
@@ -45,41 +46,33 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Width = 1920,
Height = 1080,
BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
}
};
});
yield return new object[]
{
data.Add(
"https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*0*0",
new ItemImageInfo
{
Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
Type = ImageType.Primary,
}
};
});
yield return new object[]
{
data.Add(
"https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary",
new ItemImageInfo
{
Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
Type = ImageType.Primary,
}
};
});
yield return new object[]
{
data.Add(
"https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg*0*Primary*600",
new ItemImageInfo
{
Path = "https://image.tmdb.org/t/p/original/zhB5CHEgqqh4wnEqDNJLfWXJlcL.jpg",
Type = ImageType.Primary,
}
};
});
yield return new object[]
{
data.Add(
"%MetadataPath%/library/68/68578562b96c80a7ebd530848801f645/poster.jpg*637264380567586027*Primary*600*336",
new ItemImageInfo
{
@@ -88,8 +81,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data
DateModified = new DateTime(637264380567586027, DateTimeKind.Utc),
Width = 600,
Height = 336
}
};
});
return data;
}
[Theory]
@@ -117,10 +111,10 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Assert.Null(_sqliteItemRepository.ItemImageInfoFromValueString(value));
}
public static IEnumerable<object[]> DeserializeImages_Valid_TestData()
public static TheoryData<string, ItemImageInfo[]> DeserializeImages_Valid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, ItemImageInfo[]>();
data.Add(
"/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN",
new ItemImageInfo[]
{
@@ -133,11 +127,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Height = 1080,
BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
}
}
};
});
yield return new object[]
{
data.Add(
"%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/poster.jpg*637261226720645297*Primary*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/logo.png*637261226720805297*Logo*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/landscape.jpg*637261226721285297*Thumb*0*0|%MetadataPath%/library/2a/2a27372f1e9bc757b1db99721bbeae1e/backdrop.jpg*637261226721685297*Backdrop*0*0",
new ItemImageInfo[]
{
@@ -165,20 +157,19 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Type = ImageType.Backdrop,
DateModified = new DateTime(637261226721685297, DateTimeKind.Utc),
}
}
};
});
return data;
}
public static IEnumerable<object[]> DeserializeImages_ValidAndInvalid_TestData()
public static TheoryData<string, ItemImageInfo[]> DeserializeImages_ValidAndInvalid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, ItemImageInfo[]>();
data.Add(
string.Empty,
Array.Empty<ItemImageInfo>()
};
Array.Empty<ItemImageInfo>());
yield return new object[]
{
data.Add(
"/mnt/series/Family Guy/Season 1/Family Guy - S01E01-thumb.jpg*637452096478512963*Primary*1920*1080*WjQbtJtSO8nhNZ%L_Io#R/oaS6o}-;adXAoIn7j[%hW9s:WGw[nN|test|1234||ss",
new ItemImageInfo[]
{
@@ -191,14 +182,13 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Height = 1080,
BlurHash = "WjQbtJtSO8nhNZ%L_Io#R*oaS6o}-;adXAoIn7j[%hW9s:WGw[nN"
}
}
};
});
yield return new object[]
{
data.Add(
"|",
Array.Empty<ItemImageInfo>()
};
Array.Empty<ItemImageInfo>());
return data;
}
[Theory]
@@ -242,30 +232,27 @@ namespace Jellyfin.Server.Implementations.Tests.Data
Assert.Equal(expected, _sqliteItemRepository.SerializeImages(value));
}
public static IEnumerable<object[]> DeserializeProviderIds_Valid_TestData()
public static TheoryData<string, Dictionary<string, string>> DeserializeProviderIds_Valid_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, Dictionary<string, string>>();
data.Add(
"Imdb=tt0119567",
new Dictionary<string, string>()
{
{ "Imdb", "tt0119567" },
}
};
});
yield return new object[]
{
data.Add(
"Imdb=tt0119567|Tmdb=330|TmdbCollection=328",
new Dictionary<string, string>()
{
{ "Imdb", "tt0119567" },
{ "Tmdb", "330" },
{ "TmdbCollection", "328" },
}
};
});
yield return new object[]
{
data.Add(
"MusicBrainzAlbum=9d363e43-f24f-4b39-bc5a-7ef305c677c7|MusicBrainzReleaseGroup=63eba062-847c-3b73-8b0f-6baf27bba6fa|AudioDbArtist=111352|AudioDbAlbum=2116560|MusicBrainzAlbumArtist=20244d07-534f-4eff-b4d4-930878889970",
new Dictionary<string, string>()
{
@@ -274,8 +261,9 @@ namespace Jellyfin.Server.Implementations.Tests.Data
{ "AudioDbArtist", "111352" },
{ "AudioDbAlbum", "2116560" },
{ "MusicBrainzAlbumArtist", "20244d07-534f-4eff-b4d4-930878889970" },
}
};
});
return data;
}
[Theory]

View File

@@ -6,7 +6,7 @@
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
<RootNamespace>Jellyfin.Server.Implementations.Tests</RootNamespace>

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Emby.Server.Implementations.LiveTv.EmbyTV;
using MediaBrowser.Controller.LiveTv;
using Xunit;
@@ -8,43 +7,36 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
{
public static class RecordingHelperTests
{
public static IEnumerable<object[]> GetRecordingName_Success_TestData()
public static TheoryData<string, TimerInfo> GetRecordingName_Success_TestData()
{
yield return new object[]
{
var data = new TheoryData<string, TimerInfo>();
data.Add(
"The Incredibles 2020_04_20_21_06_00",
new TimerInfo
{
Name = "The Incredibles",
StartDate = new DateTime(2020, 4, 20, 21, 6, 0, DateTimeKind.Local),
IsMovie = true
}
};
});
yield return new object[]
{
data.Add(
"The Incredibles (2004)",
new TimerInfo
{
Name = "The Incredibles",
IsMovie = true,
ProductionYear = 2004
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory 2020_04_20_21_06_00",
new TimerInfo
{
Name = "The Big Bang Theory",
StartDate = new DateTime(2020, 4, 20, 21, 6, 0, DateTimeKind.Local),
IsProgramSeries = true,
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory S12E10",
new TimerInfo
{
@@ -52,11 +44,8 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
IsProgramSeries = true,
SeasonNumber = 12,
EpisodeNumber = 10
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory S12E10 The VCR Illumination",
new TimerInfo
{
@@ -65,22 +54,17 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
SeasonNumber = 12,
EpisodeNumber = 10,
EpisodeTitle = "The VCR Illumination"
}
};
yield return new object[]
{
});
data.Add(
"The Big Bang Theory 2018-12-06",
new TimerInfo
{
Name = "The Big Bang Theory",
IsProgramSeries = true,
OriginalAirDate = new DateTime(2018, 12, 6)
}
};
});
yield return new object[]
{
data.Add(
"The Big Bang Theory 2018-12-06 - The VCR Illumination",
new TimerInfo
{
@@ -88,11 +72,9 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
IsProgramSeries = true,
OriginalAirDate = new DateTime(2018, 12, 6),
EpisodeTitle = "The VCR Illumination"
}
};
});
yield return new object[]
{
data.Add(
"The Big Bang Theory 2018_12_06_21_06_00 - The VCR Illumination",
new TimerInfo
{
@@ -101,8 +83,9 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
IsProgramSeries = true,
OriginalAirDate = new DateTime(2018, 12, 6),
EpisodeTitle = "The VCR Illumination"
}
};
});
return data;
}
[Theory]

View File

@@ -1,17 +1,28 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.AutoMoq;
using Emby.Server.Implementations.QuickConnect;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Configuration;
using Moq;
using Xunit;
namespace Jellyfin.Server.Implementations.Tests.LiveTv
namespace Jellyfin.Server.Implementations.Tests.QuickConnect
{
public class QuickConnectManagerTests
{
private static readonly AuthorizationInfo _quickConnectAuthInfo = new AuthorizationInfo
{
Device = "Device",
DeviceId = "DeviceId",
Client = "Client",
Version = "1.0.0"
};
private readonly Fixture _fixture;
private readonly ServerConfiguration _config;
private readonly QuickConnectManager _quickConnectManager;
@@ -27,6 +38,12 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
{
ConfigureMembers = true
}).Inject(configManager.Object);
// User object contains circular references.
_fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => _fixture.Behaviors.Remove(b));
_fixture.Behaviors.Add(new OmitOnRecursionBehavior());
_quickConnectManager = _fixture.Create<QuickConnectManager>();
}
@@ -36,7 +53,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
[Fact]
public void TryConnect_QuickConnectUnavailable_ThrowsAuthenticationException()
=> Assert.Throws<AuthenticationException>(_quickConnectManager.TryConnect);
=> Assert.Throws<AuthenticationException>(() => _quickConnectManager.TryConnect(_quickConnectAuthInfo));
[Fact]
public void CheckRequestStatus_QuickConnectUnavailable_ThrowsAuthenticationException()
@@ -44,7 +61,7 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
[Fact]
public void AuthorizeRequest_QuickConnectUnavailable_ThrowsAuthenticationException()
=> Assert.Throws<AuthenticationException>(() => _quickConnectManager.AuthorizeRequest(Guid.Empty, string.Empty));
=> Assert.ThrowsAsync<AuthenticationException>(() => _quickConnectManager.AuthorizeRequest(Guid.Empty, string.Empty));
[Fact]
public void IsEnabled_QuickConnectAvailable_True()
@@ -57,17 +74,17 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
public void CheckRequestStatus_QuickConnectAvailable_Success()
{
_config.QuickConnectAvailable = true;
var res1 = _quickConnectManager.TryConnect();
var res1 = _quickConnectManager.TryConnect(_quickConnectAuthInfo);
var res2 = _quickConnectManager.CheckRequestStatus(res1.Secret);
Assert.Equal(res1, res2);
}
[Fact]
public void AuthorizeRequest_QuickConnectAvailable_Success()
public async Task AuthorizeRequest_QuickConnectAvailable_Success()
{
_config.QuickConnectAvailable = true;
var res = _quickConnectManager.TryConnect();
Assert.True(_quickConnectManager.AuthorizeRequest(Guid.Empty, res.Code));
var res = _quickConnectManager.TryConnect(_quickConnectAuthInfo);
Assert.True(await _quickConnectManager.AuthorizeRequest(Guid.Empty, res.Code));
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Emby.Server.Implementations.Sorting;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@@ -13,7 +11,7 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting
{
[Theory]
[ClassData(typeof(EpisodeBadData))]
public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem x, BaseItem y)
public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem? x, BaseItem? y)
{
var cmp = new AiredEpisodeOrderComparer();
Assert.Throws<ArgumentNullException>(() => cmp.Compare(x, y));
@@ -29,152 +27,138 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting
Assert.Equal(-expected, cmp.Compare(y, x));
}
private class EpisodeBadData : IEnumerable<object?[]>
private class EpisodeBadData : TheoryData<BaseItem?, BaseItem?>
{
public IEnumerator<object?[]> GetEnumerator()
public EpisodeBadData()
{
yield return new object?[] { null, new Episode() };
yield return new object?[] { new Episode(), null };
Add(null, new Episode());
Add(new Episode(), null);
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
private class EpisodeTestData : IEnumerable<object?[]>
private class EpisodeTestData : TheoryData<BaseItem, BaseItem, int>
{
public IEnumerator<object?[]> GetEnumerator()
public EpisodeTestData()
{
yield return new object?[]
{
Add(
new Movie(),
new Movie(),
0
};
yield return new object?[]
{
0);
Add(
new Movie(),
new Episode(),
1
};
1);
// Good cases
yield return new object?[]
{
Add(
new Episode(),
new Episode(),
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 2, IndexNumber = 1 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
1
};
1);
// Good Specials
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 0, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
1);
// Specials to Episodes
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 2 },
1
};
yield return new object?[]
{
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1 },
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 2 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1 },
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 3, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 3, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsAfterSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
1
};
1);
yield return new object?[]
{
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 2 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
1
};
yield return new object?[]
{
1);
Add(
new Episode { ParentIndexNumber = 1 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
0
};
yield return new object?[]
{
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 3 },
new Episode { ParentIndexNumber = 0, IndexNumber = 1, AirsBeforeSeasonNumber = 1, AirsBeforeEpisodeNumber = 2 },
1
};
}
1);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
// Premiere Date
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
0);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 11, 0, 0, 0) },
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
-1);
Add(
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 12, 0, 0, 0) },
new Episode { ParentIndexNumber = 1, IndexNumber = 1, PremiereDate = new DateTime(2021, 09, 11, 0, 0, 0) },
1);
}
}
}
}

View File

@@ -6,7 +6,9 @@ using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using AutoFixture.AutoMoq;
using Emby.Server.Implementations.Archiving;
using Emby.Server.Implementations.Updates;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Updates;
using Moq;
using Moq.Protected;
@@ -40,7 +42,9 @@ namespace Jellyfin.Server.Implementations.Tests.Updates
_fixture.Customize(new AutoMoqCustomization
{
ConfigureMembers = true
}).Inject(http);
});
_fixture.Inject(http);
_fixture.Inject<IZipClient>(new ZipClient());
_installationManager = _fixture.Create<InstallationManager>();
}
@@ -78,5 +82,32 @@ namespace Jellyfin.Server.Implementations.Tests.Updates
packages = _installationManager.FilterPackages(packages, id: new Guid("a4df60c5-6ab4-412a-8f79-2cab93fb2bc5")).ToArray();
Assert.Single(packages);
}
[Fact]
public async Task InstallPackage_InvalidChecksum_ThrowsInvalidDataException()
{
var packageInfo = new InstallationInfo()
{
Name = "Test",
SourceUrl = "https://repo.jellyfin.org/releases/plugin/empty/empty.zip",
Checksum = "InvalidChecksum"
};
await Assert.ThrowsAsync<InvalidDataException>(() => _installationManager.InstallPackage(packageInfo, CancellationToken.None)).ConfigureAwait(false);
}
[Fact]
public async Task InstallPackage_Valid_Success()
{
var packageInfo = new InstallationInfo()
{
Name = "Test",
SourceUrl = "https://repo.jellyfin.org/releases/plugin/empty/empty.zip",
Checksum = "11b5b2f1a9ebc4f66d6ef19018543361"
};
var ex = await Record.ExceptionAsync(() => _installationManager.InstallPackage(packageInfo, CancellationToken.None)).ConfigureAwait(false);
Assert.Null(ex);
}
}
}

View File

@@ -21,6 +21,7 @@ namespace Jellyfin.Server.Integration.Tests
[InlineData("a=1", "a=1")] // won't be processed as it has a value
[InlineData("a%3D1%26b%3D2%26c%3D3", "a=1&b=2&c=3")] // will be processed.
[InlineData("a=b&a=c", "a=b")]
[InlineData("a%3D1", "a=1")]
[InlineData("a%3Db%26a%3Dc", "a=b")]
public async Task Ensure_Decoding_Of_Urls_Is_Working(string sourceUrl, string unencodedUrl)
{

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -9,7 +9,7 @@
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.10" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="xunit" Version="2.4.1" />

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
@@ -10,7 +10,7 @@
<PackageReference Include="AutoFixture" Version="4.17.0" />
<PackageReference Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.17.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="5.0.10" />
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="xunit" Version="2.4.1" />

View File

@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using Jellyfin.Networking.Configuration;
using Jellyfin.Networking.Manager;
using Jellyfin.Server.Extensions;

View File

@@ -12,9 +12,6 @@ namespace Jellyfin.Server.Tests
{
[Theory]
[InlineData("e0a72cb2a2c7", "e0a72cb2a2c7")] // isn't encoded
[InlineData("random+test", "random test")] // encoded
[InlineData("random%20test", "random test")] // encoded
[InlineData("++", " ")] // encoded
public static void EmptyValueTest(string query, string key)
{
var dict = new Dictionary<string, StringValues>

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<CodeAnalysisRuleSet>../jellyfin-tests.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

View File

@@ -11,7 +11,6 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
using MediaBrowser.Model.System;
using MediaBrowser.Providers.Plugins.Tmdb.Movies;
using MediaBrowser.XbmcMetadata.Parsers;
using Microsoft.Extensions.Logging.Abstractions;