Add code analysis attributes where appropriate

This commit is contained in:
Bond_009 2021-03-09 01:28:21 +01:00
parent 3c46f10e3d
commit 5241bd41ef
5 changed files with 43 additions and 28 deletions

View file

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace Emby.Naming.Video namespace Emby.Naming.Video
@ -16,8 +17,14 @@ namespace Emby.Naming.Video
/// <param name="expressions">List of regex to parse name and year from.</param> /// <param name="expressions">List of regex to parse name and year from.</param>
/// <param name="newName">Parsing result string.</param> /// <param name="newName">Parsing result string.</param>
/// <returns>True if parsing was successful.</returns> /// <returns>True if parsing was successful.</returns>
public static bool TryClean(string name, IReadOnlyList<Regex> expressions, out ReadOnlySpan<char> newName) public static bool TryClean([NotNullWhen(true)] string? name, IReadOnlyList<Regex> expressions, out ReadOnlySpan<char> newName)
{ {
if (string.IsNullOrEmpty(name))
{
newName = ReadOnlySpan<char>.Empty;
return false;
}
var len = expressions.Count; var len = expressions.Count;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
@ -33,12 +40,6 @@ namespace Emby.Naming.Video
private static bool TryClean(string name, Regex expression, out ReadOnlySpan<char> newName) private static bool TryClean(string name, Regex expression, out ReadOnlySpan<char> newName)
{ {
if (string.IsNullOrEmpty(name))
{
newName = ReadOnlySpan<char>.Empty;
return false;
}
var match = expression.Match(name); var match = expression.Match(name);
int index = match.Index; int index = match.Index;
if (match.Success && index != 0) if (match.Success && index != 0)

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Emby.Naming.Common; using Emby.Naming.Common;
@ -146,7 +147,7 @@ namespace Emby.Naming.Video
/// <param name="name">Raw name.</param> /// <param name="name">Raw name.</param>
/// <param name="newName">Clean name.</param> /// <param name="newName">Clean name.</param>
/// <returns>True if cleaning of name was successful.</returns> /// <returns>True if cleaning of name was successful.</returns>
public bool TryCleanString(string name, out ReadOnlySpan<char> newName) public bool TryCleanString([NotNullWhen(true)] string? name, out ReadOnlySpan<char> newName)
{ {
return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName); return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName);
} }

View file

@ -59,11 +59,18 @@ namespace Emby.Server.Implementations.Library
/// <param name="newPath">The result of the sub path replacement</param> /// <param name="newPath">The result of the sub path replacement</param>
/// <returns>The path after replacing the sub path.</returns> /// <returns>The path after replacing the sub path.</returns>
/// <exception cref="ArgumentNullException"><paramref name="path" />, <paramref name="newSubPath" /> or <paramref name="newSubPath" /> is empty.</exception> /// <exception cref="ArgumentNullException"><paramref name="path" />, <paramref name="newSubPath" /> or <paramref name="newSubPath" /> is empty.</exception>
public static bool TryReplaceSubPath(this string path, string subPath, string newSubPath, [NotNullWhen(true)] out string? newPath) public static bool TryReplaceSubPath(
[NotNullWhen(true)] this string? path,
[NotNullWhen(true)] string? subPath,
[NotNullWhen(true)] string? newSubPath,
[NotNullWhen(true)] out string? newPath)
{ {
newPath = null; newPath = null;
if (string.IsNullOrEmpty(path) || string.IsNullOrEmpty(subPath) || string.IsNullOrEmpty(newSubPath) || subPath.Length > path.Length) if (string.IsNullOrEmpty(path)
|| string.IsNullOrEmpty(subPath)
|| string.IsNullOrEmpty(newSubPath)
|| subPath.Length > path.Length)
{ {
return false; return false;
} }

View file

@ -7,18 +7,13 @@ namespace Jellyfin.Naming.Tests.Video
{ {
public sealed class CleanStringTests public sealed class CleanStringTests
{ {
private readonly NamingOptions _namingOptions = new NamingOptions(); private readonly VideoResolver _videoResolver = new VideoResolver(new NamingOptions());
[Theory] [Theory]
[InlineData("Super movie 480p.mp4", "Super movie")] [InlineData("Super movie 480p.mp4", "Super movie")]
[InlineData("Super movie 480p 2001.mp4", "Super movie")] [InlineData("Super movie 480p 2001.mp4", "Super movie")]
[InlineData("Super movie [480p].mp4", "Super movie")] [InlineData("Super movie [480p].mp4", "Super movie")]
[InlineData("480 Super movie [tmdbid=12345].mp4", "480 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.4k.mkv", "Crouching.Tiger.Hidden.Dragon")]
[InlineData("Crouching.Tiger.Hidden.Dragon.UltraHD.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")] [InlineData("Crouching.Tiger.Hidden.Dragon.UHD.mkv", "Crouching.Tiger.Hidden.Dragon")]
@ -28,19 +23,26 @@ namespace Jellyfin.Naming.Tests.Video
[InlineData("Crouching.Tiger.Hidden.Dragon.BDrip.mkv", "Crouching.Tiger.Hidden.Dragon")] [InlineData("Crouching.Tiger.Hidden.Dragon.BDrip.mkv", "Crouching.Tiger.Hidden.Dragon")]
[InlineData("Crouching.Tiger.Hidden.Dragon.BDrip-HDC.mkv", "Crouching.Tiger.Hidden.Dragon")] [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")] [InlineData("Crouching.Tiger.Hidden.Dragon.4K.UltraHD.HDR.BDrip-HDC.mkv", "Crouching.Tiger.Hidden.Dragon")]
[InlineData(null, null)]
// FIXME: [InlineData("After The Sunset - [0004].mkv", "After The Sunset")] // 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)) Assert.True(_videoResolver.TryCleanString(input, out ReadOnlySpan<char> newName));
{ // TODO: compare spans when XUnit supports it
// TODO: compare spans when XUnit supports it Assert.Equal(expectedName, newName.ToString());
Assert.Equal(expectedName, newName.ToString()); }
}
else [Theory]
{ [InlineData(null)]
Assert.Equal(expectedName, input); [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

@ -40,12 +40,16 @@ namespace Jellyfin.Server.Implementations.Tests.Library
} }
[Theory] [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("", "", "")]
[InlineData("/my/path", "", "")] [InlineData("/my/path", "", "")]
[InlineData("", "/another/path", "")] [InlineData("", "/another/path", "")]
[InlineData("", "", "/new/subpath")] [InlineData("", "", "/new/subpath")]
[InlineData("/home/jeff/music/jeff's band/consistently inconsistent.mp3", "/home/jeff/music/not jeff's band", "/home/not jeff")] [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) public void TryReplaceSubPath_InvalidInput_ReturnsFalseAndNull(string? path, string? subPath, string? newSubPath)
{ {
Assert.False(PathExtensions.TryReplaceSubPath(path, subPath, newSubPath, out var result)); Assert.False(PathExtensions.TryReplaceSubPath(path, subPath, newSubPath, out var result));
Assert.Null(result); Assert.Null(result);