mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-31 04:48:27 +01:00
Make the JsonConverters for delimited arrays more generic (#13396)
* Make the JsonConverters for delimited arrays more generic Also adds some tests for serialization (with different types) as we didn't have any before. * Ignore warnings
This commit is contained in:
@@ -12,7 +12,7 @@ using Xunit;
|
||||
|
||||
namespace Jellyfin.Api.Tests.ModelBinders
|
||||
{
|
||||
public sealed class CommaDelimitedArrayModelBinderTests
|
||||
public sealed class CommaDelimitedCollectionModelBinderTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task BindModelAsync_CorrectlyBindsValidCommaDelimitedStringArrayQuery()
|
||||
@@ -22,7 +22,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "lol,xd";
|
||||
var queryParamType = typeof(string[]);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -47,7 +47,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "42,0";
|
||||
var queryParamType = typeof(int[]);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -72,7 +72,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "How,Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -97,7 +97,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "How,,Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -123,7 +123,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString2 = "Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
@@ -151,7 +151,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
IReadOnlyList<TestType> queryParamValues = Array.Empty<TestType>();
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
@@ -179,7 +179,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "🔥,😢";
|
||||
var queryParamType = typeof(IReadOnlyList<TestType>);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -205,7 +205,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString2 = "😱";
|
||||
var queryParamType = typeof(IReadOnlyList<TestType>);
|
||||
|
||||
var modelBinder = new CommaDelimitedArrayModelBinder(new NullLogger<CommaDelimitedArrayModelBinder>());
|
||||
var modelBinder = new CommaDelimitedCollectionModelBinder(new NullLogger<CommaDelimitedCollectionModelBinder>());
|
||||
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
@@ -12,7 +12,7 @@ using Xunit;
|
||||
|
||||
namespace Jellyfin.Api.Tests.ModelBinders
|
||||
{
|
||||
public sealed class PipeDelimitedArrayModelBinderTests
|
||||
public sealed class PipeDelimitedCollectionModelBinderTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task BindModelAsync_CorrectlyBindsValidPipeDelimitedStringArrayQuery()
|
||||
@@ -22,7 +22,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "lol|xd";
|
||||
var queryParamType = typeof(string[]);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -47,7 +47,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "42|0";
|
||||
var queryParamType = typeof(int[]);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -72,7 +72,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "How|Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -97,7 +97,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "How||Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -123,7 +123,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString2 = "Much";
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
@@ -151,7 +151,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
IReadOnlyList<TestType> queryParamValues = Array.Empty<TestType>();
|
||||
var queryParamType = typeof(TestType[]);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
@@ -179,7 +179,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString = "🔥|😢";
|
||||
var queryParamType = typeof(IReadOnlyList<TestType>);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
new QueryCollection(new Dictionary<string, StringValues> { { queryParamName, new StringValues(queryParamString) } }),
|
||||
@@ -205,7 +205,7 @@ namespace Jellyfin.Api.Tests.ModelBinders
|
||||
var queryParamString2 = "😱";
|
||||
var queryParamType = typeof(IReadOnlyList<TestType>);
|
||||
|
||||
var modelBinder = new PipeDelimitedArrayModelBinder(new NullLogger<PipeDelimitedArrayModelBinder>());
|
||||
var modelBinder = new PipeDelimitedCollectionModelBinder(new NullLogger<PipeDelimitedCollectionModelBinder>());
|
||||
|
||||
var valueProvider = new QueryStringValueProvider(
|
||||
new BindingSource(string.Empty, string.Empty, false, false),
|
||||
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Extensions.Tests.Json.Models;
|
||||
@@ -7,7 +10,7 @@ using Xunit;
|
||||
|
||||
namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||
{
|
||||
public class JsonCommaDelimitedArrayTests
|
||||
public class JsonCommaDelimitedCollectionTests
|
||||
{
|
||||
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
|
||||
{
|
||||
@@ -36,6 +39,29 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||
Assert.Equal(desiredValue.Value, value?.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deserialize_EmptyList_Success()
|
||||
{
|
||||
var desiredValue = new GenericBodyListModel<string>
|
||||
{
|
||||
Value = []
|
||||
};
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<GenericBodyListModel<string>>(@"{ ""Value"": """" }", _jsonOptions));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deserialize_EmptyIReadOnlyList_Success()
|
||||
{
|
||||
var desiredValue = new GenericBodyIReadOnlyListModel<string>
|
||||
{
|
||||
Value = []
|
||||
};
|
||||
|
||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": """" }", _jsonOptions);
|
||||
Assert.Equal(desiredValue.Value, value?.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deserialize_String_Valid_Success()
|
||||
{
|
||||
@@ -48,6 +74,17 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||
Assert.Equal(desiredValue.Value, value?.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deserialize_StringList_Valid_Success()
|
||||
{
|
||||
var desiredValue = new GenericBodyListModel<string>
|
||||
{
|
||||
Value = ["a", "b", "c"]
|
||||
};
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => JsonSerializer.Deserialize<GenericBodyListModel<string>>(@"{ ""Value"": ""a,b,c"" }", _jsonOptions));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deserialize_String_Space_Valid_Success()
|
||||
{
|
||||
@@ -131,5 +168,41 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions);
|
||||
Assert.Equal(desiredValue.Value, value?.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_GenericCommandType_ReadOnlyArray_Valid_Success()
|
||||
{
|
||||
var valueToSerialize = new GenericBodyIReadOnlyCollectionModel<GeneralCommandType>
|
||||
{
|
||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }.AsReadOnly()
|
||||
};
|
||||
|
||||
string value = JsonSerializer.Serialize<GenericBodyIReadOnlyCollectionModel<GeneralCommandType>>(valueToSerialize, _jsonOptions);
|
||||
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_GenericCommandType_ImmutableArrayArray_Valid_Success()
|
||||
{
|
||||
var valueToSerialize = new GenericBodyIReadOnlyCollectionModel<GeneralCommandType>
|
||||
{
|
||||
Value = ImmutableArray.Create(new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown })
|
||||
};
|
||||
|
||||
string value = JsonSerializer.Serialize<GenericBodyIReadOnlyCollectionModel<GeneralCommandType>>(valueToSerialize, _jsonOptions);
|
||||
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_GenericCommandType_List_Valid_Success()
|
||||
{
|
||||
var valueToSerialize = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
||||
{
|
||||
Value = new List<GeneralCommandType> { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||
};
|
||||
|
||||
string value = JsonSerializer.Serialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(valueToSerialize, _jsonOptions);
|
||||
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Extensions.Tests.Json.Models;
|
||||
@@ -87,5 +88,17 @@ namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions);
|
||||
Assert.Equal(desiredValue.Value, value?.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_GenericCommandType_IReadOnlyList_Valid_Success()
|
||||
{
|
||||
var valueToSerialize = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
||||
{
|
||||
Value = new List<GeneralCommandType> { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||
};
|
||||
|
||||
string value = JsonSerializer.Serialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(valueToSerialize, _jsonOptions);
|
||||
Assert.Equal(@"{""Value"":[""MoveUp"",""MoveDown""]}", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Jellyfin.Extensions.Tests.Json.Models
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1819:Properties should not return arrays", MessageId = "Value", Justification = "Imported from ServiceStack")]
|
||||
[JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
|
||||
[JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
|
||||
public T[] Value { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Extensions.Json.Converters;
|
||||
|
||||
namespace Jellyfin.Extensions.Tests.Json.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The generic body <c>IReadOnlyCollection</c> model.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The value type.</typeparam>
|
||||
public sealed class GenericBodyIReadOnlyCollectionModel<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
|
||||
public IReadOnlyCollection<T> Value { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Jellyfin.Extensions.Tests.Json.Models
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonCommaDelimitedArrayConverterFactory))]
|
||||
[JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
|
||||
public IReadOnlyList<T> Value { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma warning disable CA1002 // Do not expose generic lists
|
||||
#pragma warning disable CA2227 // Collection properties should be read only
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Extensions.Json.Converters;
|
||||
|
||||
namespace Jellyfin.Extensions.Tests.Json.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// The generic body <c>List</c> model.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The value type.</typeparam>
|
||||
public sealed class GenericBodyListModel<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonCommaDelimitedCollectionConverterFactory))]
|
||||
public List<T> Value { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user